掌握设计模式之工厂方法模式
工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定要实例化的具体类。工厂方法模式将对象的创建委托给子类,从而实现了类的实例化延迟和高内聚低耦合的目标。
工厂方法模式的结构
工厂方法模式通常包含以下几个角色:
- Product(产品接口或抽象类):
- 定义产品的公共接口,所有具体产品都应实现这个接口。
- ConcreteProduct(具体产品):
- 实现产品接口,提供具体的实现。
- Creator(抽象工厂类):
- 声明工厂方法,用于返回一个
Product
对象。这个类通常是一个抽象类或接口,定义了产品的创建过程。
- ConcreteCreator(具体工厂类):
- 实现工厂方法,负责实例化具体的产品对象。不同的具体工厂会创建不同的具体产品。
工厂方法模式的优缺点
优点
- 解耦:客户端不需要关心具体产品的创建过程,只需调用工厂方法获取产品,降低了系统的耦合度。
- 统一管理对象创建: 工厂模式可以统一管理对象的创建过程,包括初始化、配置等操作,使得创建过程更加灵活和可控。
- 符合开闭原则:新增产品时,只需要创建新的具体产品类和工厂类,不需要修改现有代码。
- 灵活性:通过继承和多态,子类可以决定创建哪种具体产品。
缺点
- 类的数量增加:为了支持不同类型的产品,必须创建多个具体工厂类,类的数量会增加。
- 可能增加系统复杂性:比简单工厂模式要复杂,可能会使得系统变得更加难以理解和维护。
工厂方法模式的示例代码
假设我们有一个汽车生产工厂,工厂可以生产不同类型的汽车,例如BMW和Audi。
类图
示例代码
产品接口和产品类
public interface Car {
void drive();
}
public class BMW implements Car {
@Override
public void drive() {
System.out.println("Driving a BMW car.");
}
}
public class Audi implements Car {
@Override
public void drive() {
System.out.println("Driving an Audi car.");
}
}
工厂相关的类
public abstract class CarFactory {
// 工厂方法,返回具体产品
public abstract Car createCar();
}
public class BMWFactory extends CarFactory {
@Override
public Car createCar() {
return new BMW(); // 返回具体的BMW对象
}
}
public class AudiFactory extends CarFactory {
@Override
public Car createCar() {
return new Audi(); // 返回具体的Audi对象
}
}
测试代码
public class Client {
public static void main(String[] args) {
// 使用工厂方法创建汽车
CarFactory factory = new BMWFactory(); // 通过BMW工厂创建BMW汽车
Car car = factory.createCar();
car.drive(); // 输出:Driving a BMW car.
factory = new AudiFactory(); // 通过Audi工厂创建Audi汽车
car = factory.createCar();
car.drive(); // 输出:Driving an Audi car.
}
}
测试结果
Driving a BMW car.
Driving an Audi car.
工厂方法模式的变体
除了传统的工厂方法模式,有时在实际应用中还会使用一些变体:
-
抽象工厂模式:如果有多个产品族(即多个系列的产品),可以通过抽象工厂模式来实现每个工厂负责创建一组相关产品。与工厂方法模式的区别在于,工厂方法模式通常只涉及一个产品类的创建,而抽象工厂模式处理多个产品类的创建。
-
工厂方法和单例模式结合:工厂方法可以和单例模式结合使用,确保工厂实例和产品实例的唯一性。
总结
工厂方法模式是一种创建型设计模式,通过将对象的创建过程委托给子类来实现灵活的产品创建。相比于简单工厂模式,工厂方法模式更加灵活,符合开闭原则,适用于需要扩展产品种类的场景,但也可能导致类数量增加。
工厂类提供某个产品的工厂方法来生产产品,隐藏对象的创建过程,使客户端无需了解对象的具体创建逻辑,使得客户端代码与具体类的解耦,减少了依赖,更容易维护和扩展。
-
对象的具体创建逻辑可以使用
反射
、动态代理
或者结合其他创建型设计模式
来完成对象的实例化; -
引入了“中间者”和面向抽象编程使用了多态的特性,起到了解耦的作用;
-
使用者(客户端)面向抽象(接口、抽象类)编程,而不直接依赖于具体产品类。