一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情。
上一篇文章我们介绍了工厂模式的基本概念,同时详细地描述了“工厂方法模式”的使用。这篇文章我们将介绍“抽象工厂模式”。
抽象工厂模式
抽象工厂模式的理解和使用其实比较复杂,在我们日常工作过程中其实几乎不太会应用得到。
但是作为一个经典的设计模式,我们还是有必要在这里体会一下这个经典的设计模式的思想。
类图
抽象工厂模式存在的意义是:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。
对比工厂方法模式,它们的区别就是:多了一层抽象,减少工厂的数量。
首先我们给出抽象工厂模式的类图,根据类图和后续的代码,我们可以更直观地理解抽象工厂模式:
式例代码
然后给出实例代码,代码的应用场景依旧延续上一篇文章的“车辆工厂”。
首先描述我们的需求:
现在汽车按照动力模式主要分为两大类:“新能源”汽车和传统燃油动力汽车。
有的消费者喜欢购买新能源汽车,认为其环保节能;有的消费者由于气候原因更喜欢购买燃油汽车。
针对汽车动力模式来说,不是新能源,就是燃油汽车。
上一篇文章中,在工厂方法模式的处理下,每种类型的汽车都会创建一个工厂(如小汽车工厂、卡车工厂),如果汽车类型过多的话,那么就有很多工厂存在。
针对现在的使用场景,我们可以将概念抽象出来:按照动力类型区分,汽车不是新能源就是燃油型。
所以我们只需要两个工厂(新能源汽车工厂、燃油汽车工厂)。
代码实现
针对最上层的工厂抽象,最大的工厂还是定义创建什么车:
public interface VehicleFactory {
Vehicle createCar();
Vehicle createTruck();
}
创建新能源汽车的工厂:
public class NewEnergyVehicleFactory implements VehicleFactory{
@Override
public Vehicle createCar() {
return new NewEnergyCar();
}
@Override
public Vehicle createTruck() {
return new NewEnergyTruck();
}
}
创建燃油汽车的工厂:
public class FuelVehicleFactory implements VehicleFactory{
@Override
public Vehicle createCar() {
return new FuelCar();
}
@Override
public Vehicle createTruck() {
return new FuelTruck();
}
}
根据所以汽车都有的特性,抽象出汽车抽象类:
public abstract class Vehicle {
public abstract void seats();
public abstract void powerSystem();
}
按照工厂的产品等级,创建汽车抽象类,下一步是创建小汽车和卡车:
// 所有小汽车都有的特性
public abstract class Car extends Vehicle{
@Override
public void seats() {
System.out.println("五座小汽车");
}
}
// 所有卡车都有的特性
public abstract class Truck extends Vehicle{
@Override
public void seats() {
System.out.println("两座卡车");
}
}
小汽车分为新能源小汽车、燃油小汽车;卡车分为新能源卡车,燃油卡车:
public class NewEnergyCar extends Car{
@Override
public void powerSystem() {
System.out.println("新能源小汽车");
}
}
public class FuelCar extends Car{
@Override
public void powerSystem() {
System.out.println("燃油小汽车");
}
}
public class NewEnergyTruck extends Truck{
@Override
public void powerSystem() {
System.out.println("新能源卡车");
}
}
public class FuelTruck extends Truck{
@Override
public void powerSystem() {
System.out.println("燃油卡车");
}
}
使用
public static void main(String[] args) {
// 需要新能源汽车就创建新能源汽车厂
VehicleFactory newEnergyVehicleFactory = new NewEnergyVehicleFactory();
Vehicle newEnergyCar = newEnergyVehicleFactory.createCar();
newEnergyCar.seats();
newEnergyCar.powerSystem();
// 需要燃油汽车就创建燃油汽车工厂
VehicleFactory fuelVehicleFactory = new FuelVehicleFactory();
Vehicle fuelTruck = fuelVehicleFactory.createTruck();
fuelTruck.seats();
fuelTruck.powerSystem();
}
输出:
五座小汽车
新能源小汽车
两座卡车
燃油卡车
总结
工厂方法模式的工厂是创建出某一种产品;而抽象工厂模式的工厂创建出的是“一类产品”。
我们把这一类产品称为“产品族”。
根据上面的实际应用场景,小汽车(car)是一类,卡车(truck)也是一类。所以在我们的最上层汽车工厂VehicleFactory 中定义了两类产品Vehicle createCar();和Vehicle createTruck();
针对我们汽车产品的继承结构我们称之为“产品等级”。
我们的汽车的产品等级从上到下可以划分为:Vechicle -> Car/Truck -> 通用属性seat -> 动力系统powerSystem。
因为所有汽车都是有座位的,同时汽车都需要有动力。所以Vehicle 接口定义了两个方法:void seat();和void powerSystem();
-
所有的小汽车都是有座位的,所以
Car实现了seat()方法.- 小汽车又分为新能源汽车和燃油汽车,所以定义了两个类
NewEnergyCar和FuelCar继承了Car,实现了powerSystem()方法
- 小汽车又分为新能源汽车和燃油汽车,所以定义了两个类
-
同理,所有的卡车也都是有座位的,所以
Truck实现了seat()方法.- 卡车也分为新能源汽车和燃油汽车,所以定义了两个类
NewEnergyTruck和FuelTruck继承了Truck,实现了powerSystem()方法
- 卡车也分为新能源汽车和燃油汽车,所以定义了两个类
针对上述实现,我们可以看出,其中具体的工厂是:面向多个产品等级结构去生产。
所以NewEnergyVehicleFactory 继承了VehicleFactory,实现了createCar()和createCar()来生产新能源小汽车和新能源卡车。
FuelVehicleFactory 也继承了VehicleFactory,实现了createCar()和createCar()来生产燃油小汽车和燃油卡车。
也就是说,找到新能源汽车厂来创建新能源汽车;找到燃油汽车厂来创建燃油车。
至此,我们已经讲解了工厂模式的三种类型,结合在一起来说就是:
-
简单工厂模式就是以某些具体的产品为中心来写代码,有几个具体的产品,就在工厂中生产出几个产品。整个过程只有一个工厂。
-
工厂方法模式中的产品设计是所有产品都继承一个产品类型,如小汽车
Car只有一层继承关系Vehicle。工厂的职责也很明确,就是制造Vehicle的。所以如果想生产Car,那么就要自己实现一个CarFactory,想生产一个Truck,就要自己实现一个TruckFactory。所以可以认为,工厂方法模式是有一个总工厂,具体的产品放到具体的工厂(继承总工厂)中去实现。 -
抽象工厂模式的特点就是“总工厂”中已经规定好产品族。如“小汽车”,“卡车”。针对每个产品族有不同的产品层级(或者说依据产品特性进行分层)。依据不同的产品登等级来定义不同的工厂。比如例子中的“新能源汽车工厂”和“燃油汽车工厂”。
经过这个总结可以发现,三种工厂模式的区别就比较明显了。实际开发中,我们一般使用简单工厂模式和工厂方法模式比较多。抽象工厂模式有比较明显的缺点,即:无法扩展产品族。比如要添加一类产品“摩托车”,那么我们就需要同时修改VehicleFactory/NewEnergyVehicleFactory/FuelVehicleFactory。
还是,我们要根据具体需求具体分析,没有最好的设计模式,只有最适合的设计模式。