工厂模式是一种创建型设计模式,目的是将对象的创建过程与其使用过程分离,从而提高代码的可维护性、扩展性和灵活性。工厂模式主要包括三种常见的形式:简单工厂模式、工厂方法模式、和抽象工厂模式。每种模式都有各自的特点、应用场景及优缺点。
简单工厂模式又称为静态工厂方法模式,是由一个工厂类决定创建哪一种产品类的实例。客户端通过工厂类的静态方法创建产品,而不需要直接使用new
关键字。
+------------------+
| Product | (抽象产品类)
+------------------+
^
|
+------------------+ +------------------+
| ConcreteProductA | | ConcreteProductB | (具体产品类)
+------------------+ +------------------+
^
|
+------------------+
| SimpleFactory | (工厂类)
+------------------+
| + createProduct(type): Product |
+------------------------------------+
|
+------------------+
| Client | (客户端)
+------------------+
| + useProduct() |
+------------------+
|
v
+------------------+
| Product |
+------------------+
工厂方法模式通过定义一个创建对象的接口,让子类决定实例化哪个类。工厂方法将对象的实例化推迟到子类中实现。
+------------------+
| Product | (抽象产品类)
+------------------+
^
|
+------------------+ +------------------+
| ConcreteProductA | | ConcreteProductB | (具体产品类)
+------------------+ +------------------+
^ ^
| |
+------------------+ +------------------+
| Factory | | Factory | (抽象工厂)
| MethodA | | MethodB |
+------------------+ +------------------+
| + createProduct(): Product | + createProduct(): Product
+------------------+ +------------------+
^ ^
| |
+------------------+ +------------------+
| ConcreteFactoryA | | ConcreteFactoryB | (具体工厂)
+------------------+ +------------------+
| + createProduct(): Product | + createProduct(): Product
+------------------+ +------------------+
| |
+------------------+ +------------------+
| Client | (客户端) | Client |
+------------------+ +------------------+
| + useProduct() | | + useProduct() |
+------------------+ +------------------+
| |
v v
+------------------+ +------------------+
| Product | | Product |
+------------------+ +------------------+
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它通常用于创建一族产品,而不是一个具体的产品。
+------------------------+
| AbstractProductA | (抽象产品类A)
+------------------------+
^
|
+------------------------+
| ConcreteProductA1 | (具体产品A1)
+------------------------+
| ConcreteProductA2 | (具体产品A2)
+------------------------+
+------------------------+
| AbstractProductB | (抽象产品类B)
+------------------------+
^
|
+------------------------+
| ConcreteProductB1 | (具体产品B1)
+------------------------+
| ConcreteProductB2 | (具体产品B2)
+------------------------+
+------------------------+
| AbstractFactory | (抽象工厂类)
+------------------------+
| + createProductA(): AbstractProductA |
| + createProductB(): AbstractProductB |
+---------------------------------------+
^
|
+------------------------+ +------------------------+
| ConcreteFactory1 | | ConcreteFactory2 | (具体工厂类)
+------------------------+ +------------------------+
| + createProductA(): ConcreteProductA1 | + createProductA(): ConcreteProductA2 |
| + createProductB(): ConcreteProductB1 | + createProductB(): ConcreteProductB2 |
+---------------------------------------+ +------------------------------------+
|
+------------------------+
| Client | (客户端)
+------------------------+
| + useProducts() |
+------------------------+
|
v
+------------------------+
| AbstractProductA, |
| AbstractProductB |
+------------------------+
模式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
简单工厂模式 | 1. 简化对象创建 2. 集中管理对象创建 |
1. 不符合开闭原则 2. 扩展性差 |
1. 创建对象较少 2. 客户端不关心产品具体类型 |
工厂方法模式 | 1. 符合开闭原则 2. 更高的灵活性 3. 更符合面向对象设计 |
1. 增加代码复杂度 2. 类数量增加 |
1. 系统结构稳定,新增产品类较多 2. 需要不同的产品创建逻辑 |
抽象工厂模式 | 1. 产品族创建一致性 2. 符合开闭原则 3. 更高的抽象层次 |
1. 难以支持新产品 2. 复杂度高 |
1. 系统需要多个产品族 2. 系统结构稳定 |
假设我们需要为一个跨平台的应用程序开发一套UI组件库。这个应用程序需要支持Windows、macOS和Linux平台,每个平台的UI组件(如按钮、文本框、菜单等)都具有不同的风格和实现。
我们可以创建一个简单工厂类,通过传递操作系统类型来返回相应的UI组件实例:
public class SimpleUIFactory {
public static Button createButton(String osType) {
switch (osType) {
case "Windows":
return new WindowsButton();
case "macOS":
return new MacOSButton();
case "Linux":
return new LinuxButton();
default:
throw new IllegalArgumentException("Unknown OS type");
}
}
}
此方法虽然简单,但当需要增加新平台(如Android)时,需要修改工厂类,违反开闭原则。
为了使系统更灵活,我们可以使用工厂方法模式,为每个平台定义一个工厂接口,并由具体工厂类实现该接口:
public interface UIFactory {
Button createButton();
}
public class WindowsUIFactory implements UIFactory {
public Button createButton() {
return new WindowsButton();
}
}
public class MacOSUIFactory implements UIFactory {
public Button createButton() {
return new MacOSButton();
}
}
这样,当需要支持新平台时,只需新增一个实现UIFactory
接口的工厂类,而无需修改现有代码。
如果我们的应用程序需要创建一整套UI组件,而不仅仅是按钮,那么可以采用抽象工厂模式来管理整个产品族:
public interface UIFactory {
Button createButton();
TextBox createTextBox();
Menu createMenu();
}
public class WindowsUIFactory implements UIFactory {
public Button createButton() {
return new WindowsButton();
}
public TextBox createTextBox() {
return new WindowsTextBox();
}
public Menu createMenu() {
return new WindowsMenu();
}
}
public class MacOSUIFactory implements UIFactory {
public Button createButton() {
return new MacOSButton();
}
public TextBox createTextBox() {
return new MacOSTextBox();
}
public Menu createMenu() {
return new MacOSMenu();
}
}
这样,WindowsUIFactory
和MacOSUIFactory
分别负责创建Windows和macOS平台的整套UI组件,保证了产品族内组件的风格一致性。
在实际项目开发中,选择合适的工厂模式要考虑系统的规模、复杂度以及未来的扩展需求。简单工厂模式适合小型项目或一次性对象创建,而工厂方法模式则适合需要经常扩展的系统。对于需要创建一系列相关对象的大型项目,抽象工厂模式则是最佳选择,但要注意其复杂度。
同时,现代开发中常用的依赖注入框架(如Spring)也可以看作是工厂模式的扩展和演进,进一步提升了代码的解耦和模块化。因此,在使用工厂模式时,结合依赖注入等设计模式,能够让系统设计更加灵活和可扩展。