工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但允许子类决定实例化哪个类。它将对象的实例化过程委托给子类来完成,从而在不修改客户端代码的情况下,允许客户端代码与具体实例化的类解耦。
主要角色
-
工厂接口(Factory Interface):定义了创建对象的方法,由具体工厂类实现。
-
具体工厂类(Concrete Factory):实现了工厂接口,负责创建具体的产品对象。
-
产品接口(Product Interface):定义了产品对象的接口。
-
具体产品类(Concrete Product):实现了产品接口,是工厂创建的对象。
主要类型
-
简单工厂模式(Simple Factory Pattern):由一个工厂类根据传入的参数决定创建哪种产品类的实例。这种方式违反了开放-封闭原则,因为每次添加新产品时都需要修改工厂类。
-
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪个类。这种方式符合开放-封闭原则,因为添加新产品时只需创建新的具体工厂类即可。
-
抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。这种模式通常以一组工厂类的方式实现,每个工厂类负责创建一组相关的产品。
优点
- 封装了对象的创建过程:客户端代码只需要关心所需产品的接口,无需关心具体的实现细节。
- 提高了代码的可扩展性:通过添加新的具体工厂类或产品类,可以方便地扩展系统的功能。
适用场景
- 当一个类不知道它需要创建的对象的类时。
- 当一个类希望由其子类来指定所创建的对象时。
- 当类将创建对象的职责委托给多个辅助子类中的某一个,并且希望动态决定要实例化哪个对象时。
简单工厂
以下是一个简单工厂模式的简单示例,假设我们有一个图形类,包括圆形(Circle)、矩形(Rectangle)和正方形(Square),我们使用简单工厂模式创建这些图形对象:
// 图形接口
interface Shape {
void draw();
}
// 圆形类
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
// 矩形类
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
// 正方形类
class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
// 简单工厂类
class ShapeFactory {
// 根据传入的参数创建相应的图形对象
public static Shape createShape(String type) {
if (type.equalsIgnoreCase("circle")) {
return new Circle();
} else if (type.equalsIgnoreCase("rectangle")) {
return new Rectangle();
} else if (type.equalsIgnoreCase("square")) {
return new Square();
} else {
throw new IllegalArgumentException("Invalid shape type: " + type);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Shape circle = ShapeFactory.createShape("circle");
circle.draw();
Shape rectangle = ShapeFactory.createShape("rectangle");
rectangle.draw();
Shape square = ShapeFactory.createShape("square");
square.draw();
}
}
在这个示例中,我们定义了三个图形类:Circle、Rectangle 和 Square,它们都实现了 Shape 接口,提供了 draw() 方法来绘制各自的图形。然后我们创建了一个 ShapeFactory 工厂类,根据传入的参数创建对应的图形对象。客户端代码通过调用工厂类的 createShape() 方法来获取图形对象,并调用其 draw() 方法来绘制图形。
这个简单工厂模式示例展示了如何通过一个工厂类来创建不同类型的对象,从而将对象的创建过程与客户端代码解耦。
工厂方法
下面是一个使用工厂方法模式的简单示例,假设我们有一个文档编辑器,可以创建不同类型的文档(如 PDF 文档、Word 文档等),我们使用工厂方法模式创建这些文档对象:
// 文档接口
interface Document {
void open();
void save();
}
// PDF 文档类
class PdfDocument implements Document {
@Override
public void open() {
System.out.println("Opening PDF document.");
}
@Override
public void save() {
System.out.println("Saving PDF document.");
}
}
// Word 文档类
class WordDocument implements Document {
@Override
public void open() {
System.out.println("Opening Word document.");
}
@Override
public void save() {
System.out.println("Saving Word document.");
}
}
// 抽象文档工厂接口
interface DocumentFactory {
Document createDocument();
}
// PDF 文档工厂类
class PdfDocumentFactory implements DocumentFactory {
@Override
public Document createDocument() {
return new PdfDocument();
}
}
// Word 文档工厂类
class WordDocumentFactory implements DocumentFactory {
@Override
public Document createDocument() {
return new WordDocument();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建 PDF 文档
DocumentFactory pdfFactory = new PdfDocumentFactory();
Document pdfDocument = pdfFactory.createDocument();
pdfDocument.open();
pdfDocument.save();
// 创建 Word 文档
DocumentFactory wordFactory = new WordDocumentFactory();
Document wordDocument = wordFactory.createDocument();
wordDocument.open();
wordDocument.save();
}
}
在这个示例中,我们定义了两个文档类:PdfDocument 和 WordDocument,它们都实现了 Document 接口,提供了 open() 和 save() 方法来打开和保存文档。然后我们创建了两个工厂类:PdfDocumentFactory 和 WordDocumentFactory,分别实现了 DocumentFactory 接口,用于创建 PDF 文档和 Word 文档对象。
客户端代码通过实例化不同的工厂类来创建对应的文档对象,并调用其方法来操作文档。工厂方法模式通过定义一个创建对象的接口,让子类来决定实例化哪个类,从而避免了直接在客户端代码中创建对象,降低了代码的耦合度。
抽象工厂
下面是一个使用抽象工厂模式的简单示例,假设我们有一个计算机制造商,可以生产笔记本电脑和台式电脑,我们使用抽象工厂模式创建这些电脑对象:
// 抽象产品接口 - 笔记本电脑
interface Laptop {
void display();
}
// 具体产品 - 笔记本电脑
class LaptopDell implements Laptop {
@Override
public void display() {
System.out.println("This is a Dell Laptop.");
}
}
// 具体产品 - 笔记本电脑
class LaptopHP implements Laptop {
@Override
public void display() {
System.out.println("This is an HP Laptop.");
}
}
// 抽象产品接口 - 台式电脑
interface Desktop {
void display();
}
// 具体产品 - 台式电脑
class DesktopDell implements Desktop {
@Override
public void display() {
System.out.println("This is a Dell Desktop.");
}
}
// 具体产品 - 台式电脑
class DesktopHP implements Desktop {
@Override
public void display() {
System.out.println("This is an HP Desktop.");
}
}
// 抽象工厂接口
interface ComputerFactory {
Laptop createLaptop();
Desktop createDesktop();
}
// 具体工厂 - Dell 电脑工厂
class DellFactory implements ComputerFactory {
@Override
public Laptop createLaptop() {
return new LaptopDell();
}
@Override
public Desktop createDesktop() {
return new DesktopDell();
}
}
// 具体工厂 - HP 电脑工厂
class HPFactory implements ComputerFactory {
@Override
public Laptop createLaptop() {
return new LaptopHP();
}
@Override
public Desktop createDesktop() {
return new DesktopHP();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建 Dell 电脑工厂
ComputerFactory dellFactory = new DellFactory();
Laptop dellLaptop = dellFactory.createLaptop();
Desktop dellDesktop = dellFactory.createDesktop();
dellLaptop.display();
dellDesktop.display();
// 创建 HP 电脑工厂
ComputerFactory hpFactory = new HPFactory();
Laptop hpLaptop = hpFactory.createLaptop();
Desktop hpDesktop = hpFactory.createDesktop();
hpLaptop.display();
hpDesktop.display();
}
}
在这个示例中,我们定义了两个抽象产品接口:Laptop 和 Desktop,分别代表笔记本电脑和台式电脑。然后定义了四个具体产品类,分别是 Dell 和 HP 的笔记本电脑和台式电脑。接着定义了一个抽象工厂接口 ComputerFactory,包含创建笔记本电脑和台式电脑的方法。最后定义了两个具体工厂类 DellFactory 和 HPFactory,分别实现了 ComputerFactory 接口,用于创建 Dell 和 HP 的电脑产品。
客户端代码通过实例化具体工厂类来创建对应的电脑产品,并调用其方法来展示电脑信息。抽象工厂模式通过定义一个工厂接口,让子类来决定创建哪个类的对象,从而使客户端代码与具体产品的创建解耦。
总结
工厂模式在软件开发中得到了广泛应用,特别是在创建复杂对象或需要灵活扩展的场景下,能够有效地降低代码的耦合度,提高系统的可维护性和可扩展性。在很多框架中都有用到,例如JavaEE 中的JDBC,和Spring 框架
-
JavaEE 中的JDBC:Java 数据库连接(JDBC)API 中的 DriverManager 类就使用了工厂模式。它根据数据库连接字符串的不同,动态地选择合适的数据库驱动程序实例。
-
Spring Framework:Spring 框架广泛使用了工厂模式,其中 BeanFactory 和 ApplicationContext 接口就是工厂模式的经典例子。Spring IoC 容器通过工厂方法来管理和创建应用程序中的对象。