设计模式之工厂模式
工厂方法模式定义了创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
来解析这个定义:
- “创建对象”这个点非常关键,表明了工厂模式的职责就是为了创建对象的,而不是干其他委托、代理什么的。同时也将创建对象这个职责从Client迁移出去了。
- “子类决定要实例化的类是哪一个”,说明创建对象的方法被子类继承,而这个方法的返回值是目标类,并且隐含着一个更重要的点,父类中定义的这个方法的返回值一定是一个目标抽象类,而子类返回是目标具体类。
- “实例化推迟到子类”,表明是在客户端调用时,通过选用不同的子类,来决定目标对象的具体类。

学习设计模式,一个关键的自我校验,是能够自己给自己出题,构建场景,并通过目标设计模式来解决。
// 1. 定义抽象产品类(汽车)
abstract class Car {
public abstract void drive();
}
// 2. 定义具体产品类(电动车和燃油车)
class ElectricCar extends Car {
@Override
public void drive() {
System.out.println("Driving an Electric Car!");
}
}
class GasolineCar extends Car {
@Override
public void drive() {
System.out.println("Driving a Gasoline Car!");
}
}
// 3. 定义抽象创建者类(汽车工厂)
abstract class CarFactory {
// 工厂方法
public abstract Car createCar();
// 交付汽车的方法
public void deliverCar() {
Car car = createCar();
System.out.print("Factory: Delivering ");
car.drive();
}
}
// 4. 定义具体创建者类(电动车工厂和燃油车工厂)
class ElectricCarFactory extends CarFactory {
@Override
public Car createCar() {
return new ElectricCar();
}
}
class GasolineCarFactory extends CarFactory {
@Override
public Car createCar() {
return new GasolineCar();
}
}
// 5. 客户端代码
public class FactoryMethodExample {
public static void main(String[] args) {
System.out.println("Client: Ordering an Electric Car");
CarFactory electricFactory = new ElectricCarFactory();
electricFactory.deliverCar();
System.out.println("\nClient: Ordering a Gasoline Car");
CarFactory gasolineFactory = new GasolineCarFactory();
gasolineFactory.deliverCar();
}
}

这是一个简单工厂的实现,将Car具体类的创建职责从Client中剥离出来,放到CarFactory中。
考虑一个新需求,当需要新增加一个混动类型的车型时,首先需要增加Car的的子类HybridCar,这个动作属于扩展,不需要修改其他类,符合开闭原则,接着需要CarFactory支持混动车型的制造,需要修改CarFactory的代码,不符合开闭原则。发现没有,对新需求支持时进行横向扩展,而不用修改旧的代码逻辑,是每个设计模式都要考虑的事情,更直白简单的描述,设计模式就是在不同的角度来支持新需求能够扩展而非修改。所谓不同角度,包括职责的扩展、新对象生成的扩展、订阅者的扩展等等。
如何解决,常规套路了,利用扩展子类来替代修改原有类,将CarFactory这个具体类向上抽离出超类。如此改造后,就演化出工厂方法模式了。

// 1. 定义抽象产品类(汽车)
abstract class Car {
public abstract void drive();
}
// 2. 定义具体产品类(电动车和燃油车)
class ElectricCar extends Car {
@Override
public void drive() {
System.out.println("Driving an Electric Car!");
}
}
class GasolineCar extends Car {
@Override
public void drive() {
System.out.println("Driving a Gasoline Car!");
}
}
// 3. 定义抽象创建者类(汽车工厂)
abstract class CarFactory {
// 工厂方法
public abstract Car createCar();
// 交付汽车的方法
public void deliverCar() {
Car car = createCar();
System.out.print("Factory: Delivering ");
car.drive();
}
}
// 4. 定义具体创建者类(电动车工厂和燃油车工厂)
class ElectricCarFactory extends CarFactory {
@Override
public Car createCar() {
return new ElectricCar();
}
}
class GasolineCarFactory extends CarFactory {
@Override
public Car createCar() {
return new GasolineCar();
}
}
// 5. 客户端代码
public class Client {
public static void main(String[] args) {
System.out.println("Client: Ordering an Electric Car");
CarFactory electricFactory = new ElectricCarFactory();
electricFactory.deliverCar();
System.out.println("\nClient: Ordering a Gasoline Car");
CarFactory gasolineFactory = new GasolineCarFactory();
gasolineFactory.deliverCar();
}
}
再次强调,在类图中可以看到,我们利用的抽象类的继承,而不是接口的实现,这两者的主要区别在于子类是否有共享的逻辑,如果有则选择抽象继承,如果没有则选择接口实现,并不影响模式本身的结构。
需求再变,汽车工厂除了生产汽车外,还要生产相配套的产品,如轮胎,要如何实现。燃油车工厂生产燃油车和燃油车轮胎,电车工厂生产电车和电车轮胎,车和轮胎是一个产品族。而“产品族”正是抽象工厂的模式意图,虽然类图上看着与工厂方法很相似,实现上也是自然的衍生,主要的区别是设计意图,当抽象工厂模式只涉及一个产品时,它的代码结构和工厂方法模式几乎一样。

// 1. 抽象产品:汽车
abstract class Car {
public abstract void drive();
}
// 2. 具体产品:电动车
class ElectricCar extends Car {
@Override
public void drive() {
System.out.println("Driving an Electric Car!");
}
}
// 3. 具体产品:燃油车
class GasolineCar extends Car {
@Override
public void drive() {
System.out.println("Driving a Gasoline Car!");
}
}
// 4. 抽象产品:轮胎
abstract class Tire {
public abstract void inflate();
}
// 5. 具体产品:电动车轮胎
class ElectricCarTire extends Tire {
@Override
public void inflate() {
System.out.println("Inflating Electric Car Tire!");
}
}
// 6. 具体产品:燃油车轮胎
class GasolineCarTire extends Tire {
@Override
public void inflate() {
System.out.println("Inflating Gasoline Car Tire!");
}
}
// 7. 抽象工厂
abstract class AbstractCarFactory {
// 创建汽车
public abstract Car createCar();
// 创建轮胎
public abstract Tire createTire();
}
// 8. 具体工厂:电动车工厂
class ElectricCarFactory extends AbstractCarFactory {
@Override
public Car createCar() {
return new ElectricCar();
}
@Override
public Tire createTire() {
return new ElectricCarTire();
}
}
// 9. 具体工厂:燃油车工厂
class GasolineCarFactory extends AbstractCarFactory {
@Override
public Car createCar() {
return new GasolineCar();
}
@Override
public Tire createTire() {
return new GasolineCarTire();
}
}
// 10. 客户端代码
public class AbstractFactoryExample {
public static void main(String[] args) {
// 创建电动车工厂
AbstractCarFactory electricFactory = new ElectricCarFactory();
Car electricCar = electricFactory.createCar();
Tire electricTire = electricFactory.createTire();
System.out.println("Client: Ordering an Electric Car");
electricCar.drive();
electricTire.inflate();
// 创建燃油车工厂
AbstractCarFactory gasolineFactory = new GasolineCarFactory();
Car gasolineCar = gasolineFactory.createCar();
Tire gasolineTire = gasolineFactory.createTire();
System.out.println("\nClient: Ordering a Gasoline Car");
gasolineCar.drive();
gasolineTire.inflate();
}
}
- 工厂方法模式:
- 用于创建单个对象。
- 每个工厂子类只负责创建一种产品。
- 抽象工厂模式:
- 用于创建一组相关对象(产品族)。
- 每个工厂子类负责创建一组相关的产品。
可以看到,从简单工厂到工厂方法再到抽象工厂,都是随着需求而演变的,模式本身是为了更好的解决问题,因此在设计模式选择时,不要死搬硬套,而要与实际场景相结合,任何选择都是有利有弊的,取决于当前哪个考核点是最高优先级。
工厂模式,哪个点最重要,那就是职责 —— “对象创建”。