前言
工厂模式(Factory Pattern)是Java中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的绝佳方式。
抽象工厂模式
抽象工厂模式比工厂方法模式的抽象程度更高,在工厂方法模式中每一个具体工厂只需要生产一种具体产品,但是在抽象工厂模式中一个具体工厂可以生产一组相关的具体产品,这样一组产品被称为产品族,产品族中的每一个产品都分属于某一个产品继承等级结构。
抽象工厂模式结构
产品等级结构与产品族
为了更好的理解抽象工厂, 我们这里先引入两个概念:
- 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是汽车,其子类有宝马汽车、奔驰汽车、大众汽车,而抽象汽车与具体品牌的汽车之间构成了一个产品等级结构,抽象汽车是父类,而具体品牌的汽车是其子类。
- 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如宝马工厂生产的宝马汽车、宝马摩托车。而宝马汽车位于汽车产品等级结构中,宝马摩托车位于摩托车产品等级结构中。
我们将此上,转换成图来看的话,如下所示:
在上图中,每一个具体工厂可以生产属于一个产品族的所有产品,例如宝马的工厂生产宝马汽车、宝马摩托车、宝马自行车,所生产的产品又位于不同的产品等级结构中。如果使用工厂方法模式,上图所示的结构需要提供9个具体工厂,而使用抽象工厂模式只需要提供3个具体工厂,极大减少了系统中类的个数。
抽象工厂模式概述
抽象工厂模式(Abstract Factory Pattern) 原始定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式为创建一组对象提供了解决方案,与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,而是负责创建一个产品族,如下图:
抽象工厂模式原理
在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法,用于产生多种不同类型的产品,也正是这些产品构成了一个产品族,抽象工厂模式的主要角色如下:
- 抽象工厂(Abstract Factory):它声明了一种用于创建一族产品的方法,每一个方法对应一种产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
抽象工厂模式实现
抽象工厂
在一个抽象工厂中可以声明多个工厂方法,用于创建不同类型的产品
/**
* 在一个抽象工厂中可以声明多个工厂方法,用于创建不同类型的产品
*
* @author Duansg
* @date 2022-12-17 9:26 下午
*/
public interface VehicleFactory {
/**
* 创建汽车
*
* @return
*/
AbstractCar createCar();
/**
* 创建摩托车
*
* @return
*/
AbstractMotorbike createMotorbike();
/**
* 创建自行车
*
* @return
*/
AbstractBicycle createBicycle();
}
具体工厂
每一个具体工厂方法,可以返回一个特定的产品对象,而同一个具体工厂所创建的产品对象构成了一个产品族,如下:
/**
* @author Duansg
* @date 2022-12-17 10:10 下午
*/
public class BenzFactory implements VehicleFactory {
@Override
public AbstractCar createCar() {
return new BenzCar();
}
@Override
public AbstractMotorbike createMotorbike() {
return new BenzMotorbike();
}
@Override
public AbstractBicycle createBicycle() {
return new BenzBicycle();
}
}
/**
* @author Duansg
* @date 2022-12-17 10:10 下午
*/
public class BmwFactory implements VehicleFactory {
@Override
public AbstractCar createCar() {
return new BmwCar();
}
@Override
public AbstractMotorbike createMotorbike() {
return new BmwMotorbike();
}
@Override
public AbstractBicycle createBicycle() {
return new BmwBicycle();
}
}
抽象产品
/**
* @author Duansg
* @date 2022-12-17 10:41 下午
*/
public interface AbstractBicycle {
//....
}
/**
* @author Duansg
* @date 2022-12-17 10:40 下午
*/
public interface AbstractCar {
//....
}
/**
* @author Duansg
* @date 2022-12-17 10:41 下午
*/
public interface AbstractMotorbike {
//....
}
具体产品
/**
* @author Duansg
* @date 2022-12-17 10:43 下午
*/
public class BenzBicycle implements AbstractBicycle {
//.....
}
/**
* @author Duansg
* @date 2022-12-17 10:42 下午
*/
public class BenzCar implements AbstractCar {
//.....
}
/**
* @author Duansg
* @date 2022-12-17 10:43 下午
*/
public class BenzMotorbike implements AbstractMotorbike {
//.....
}
/**
* @author Duansg
* @date 2022-12-17 10:43 下午
*/
public class BmwBicycle implements AbstractBicycle {
//.....
}
/**
* @author Duansg
* @date 2022-12-17 10:42 下午
*/
public class BmwCar implements AbstractCar {
//.....
}
/**
* @author Duansg
* @date 2022-12-17 10:43 下午
*/
public class BmwMotorbike implements AbstractMotorbike {
//.....
}
Test Unit
/**
* @author Duansg
* @date 2022-12-17 11:03 下午
*/
@Data
public class VehicleTestUnit {
/**
* 抽象自行车
*/
private AbstractBicycle bicycle;
/**
* 抽象汽车
*/
private AbstractCar car;
/**
* 抽象摩托车
*/
private AbstractMotorbike motorbike;
/**
* 就是使用抽象工厂来生产各种汽车
*
* @param vehicleFactory
*/
public VehicleTestUnit(VehicleFactory vehicleFactory) {
//在客户端看来
this.car = vehicleFactory.createCar();
this.bicycle = vehicleFactory.createBicycle();
this.motorbike = vehicleFactory.createMotorbike();
}
public static void main(String[] args) {
VehicleTestUnit vehicleFactory = new VehicleTestUnit(new BmwFactory());
System.out.println(vehicleFactory.getCar());
System.out.println(vehicleFactory.getMotorbike());
System.out.println(vehicleFactory.getBicycle());
}
}
小结
从上面代码实现中我们可以看出,抽象工厂模式向使用方隐藏了下列变化:
- 程序所支持的实例集合(具体工厂)的数目;
- 当前是使用的实例集合中的哪一个实例;
- 在任意给定时刻被实例化的具体类型;
所以说,在理解抽象工厂模式原理时,你一定要牢牢记住"如何找到某一个类产品的正确共性功能"这个重点。
优点
- 对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提升组件的复用性。
- 当需要提升代码的扩展性并降低维护成本时,把对象的创建和使用过程分开,能有效地将代码统一到一个级别上。
- 解决跨平台带来的兼容性问题。
缺点
增加新的产品等级结构相对麻烦,需要对原有结构进行比较大的修改,也可能需要修改抽象层代码,这显然会带来较大不变,违背了开闭原则。