八、抽象工厂模式(Abstract Factory)
1、介绍
抽象工厂模式(Abstract Factory)是一种创建型设计模式,主要用于解决系统中涉及到多个品牌、多个系列或多个主题的产品创建问题。抽象工厂模式可以提供一个接口,用于创建一系列相关或互相依赖的对象,而无需指定它们具体的类。
以电子设备为例,假设一个电子品牌有多个产品线,如手机、电视和笔记本电脑。每个产品线又有不同的系列,如高端系列、中端系列和低端系列。这时,如果使用传统的工厂方法模式,那么需要为每种产品线和每种系列都创建一个工厂,这样会导致工厂类的数量非常多,不便于管理。
而如果使用抽象工厂模式,我们只需要为每个系列创建一个工厂,每个工厂可以创建该系列的所有产品。这样就大大减少了工厂类的数量,使得代码更加清晰和易于维护。
抽象工厂模式主要解决的问题是如何在不指定具体类的情况下创建一组相关或互相依赖的对象。这样,无论系统中的产品如何变化(比如增加新的产品线,或者增加新的系列),都不需要修改客户端的代码。只需要增加新的工厂类,或者修改现有的工厂类即可。这样的设计提高了系统的灵活性和可扩展性。
抽象工厂模式被广泛应用于需要处理复杂对象创建问题的场景,比如 GUI 组件的创建,多数据库平台数据访问解决方案的创建,等等。
2、生活实例
假设你正在打造你的新家,你需要各种不同的家具,例如椅子、桌子和沙发等。你可能想要所有的家具风格一致,例如,你可能想要所有家具都是现代风格,或者都是古典风格。在这种情况下,你会去找一个现代家具的制造商,或者一个古典家具的制造商,而不是去找一个只制造椅子的制造商,或者只制造桌子的制造商。这个家具制造商就像是一个"抽象工厂",它可以为你提供一整套的产品。
3、java代码实例
下面是抽象工厂模式的一个Java实现,假设我们有两种类型的家具:现代风格和古典风格。我们首先定义一个抽象工厂类,然后定义两个具体的工厂类:现代风格工厂类和古典风格工厂类。
// 定义产品接口
interface Chair {
void sitOn();
}
interface Table {
void use();
}
// 定义抽象工厂
interface FurnitureFactory {
Chair createChair();
Table createTable();
}
// 定义具体产品
class ModernChair implements Chair {
public void sitOn() {
System.out.println("Sitting on a modern chair");
}
}
class ModernTable implements Table {
public void use() {
System.out.println("Using a modern table");
}
}
class ClassicChair implements Chair {
public void sitOn() {
System.out.println("Sitting on a classic chair");
}
}
class ClassicTable implements Table {
public void use() {
System.out.println("Using a classic table");
}
}
// 定义具体工厂
class ModernFurnitureFactory implements FurnitureFactory {
public Chair createChair() {
return new ModernChair();
}
public Table createTable() {
return new ModernTable();
}
}
class ClassicFurnitureFactory implements FurnitureFactory {
public Chair createChair() {
return new ClassicChair();
}
public Table createTable() {
return new ClassicTable();
}
}
在客户端代码中,我们可以通过具体的工厂来创建一整套的产品,而不需要关心这些产品是如何被创建的:
FurnitureFactory factory = new ModernFurnitureFactory();
Chair chair = factory.createChair();
Table table = factory.createTable();
chair.sitOn(); // Output: Sitting on a modern chair
table.use(); // Output: Using a modern table
通过这个例子,我们可以看到抽象工厂模式的优势:我们可以在不知道具体产品实现的情况下,创建一组相关联的产品。这使得我们的代码更加灵活和可维护。
4、其它例子
Java 的 DocumentBuilderFactory
类以及它在抽象工厂模式中的应用。
在 Java 中,处理 XML 文档通常使用 DOM (Document Object Model) 解析器。为了创建 DOM 解析器,我们需要使用 DocumentBuilderFactory
类。这个类的名字中包含 "Factory" 是因为它用于生成 DocumentBuilder
对象,DocumentBuilder
对象是用来解析 XML 文档并生成 DOM 对象的实际工具。
这是一个基本的创建和使用 DOM 解析器的步骤:
-
使用
DocumentBuilderFactory.newInstance()
方法获取DocumentBuilderFactory
实例。这个方法是一个静态工厂方法,它返回一个DocumentBuilderFactory
实例。实际返回的DocumentBuilderFactory
类型依赖于系统配置或者 Java 的服务提供者接口 (SPI) 机制。DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-
通过
DocumentBuilderFactory
实例创建DocumentBuilder
实例:DocumentBuilder builder = factory.newDocumentBuilder();
-
使用
DocumentBuilder
实例解析 XML 文件:Document document = builder.parse(new File("path_to_your_xml_file"));
从上述步骤中我们可以看出,DocumentBuilderFactory
是一个抽象工厂,它创建具体的 DocumentBuilder
实例,而 DocumentBuilder
则用于创建具体的 Document
对象。具体的 DocumentBuilderFactory
和 DocumentBuilder
类型取决于运行环境,但是使用者无需关心这些具体的类型,只需要通过抽象工厂获取所需的对象即可。这就是抽象工厂模式的运用。
这种模式允许易于扩展,例如,如果你想添加新的 DocumentBuilder
实现来处理特殊的 XML 文档,只需要创建相应的 DocumentBuilderFactory
和 DocumentBuilder
即可,无需修改现有的代码。
5、工厂方法模式和抽象工厂模式的区别
首先,工厂方法模式和抽象工厂模式都属于创建型设计模式,都是用来创建对象的。工厂方法模式关注的是创建单一类型的产品,而抽象工厂模式关注的是创建系列产品。
在工厂方法模式中,我们会有一个工厂接口(或者抽象类),它定义了创建对象的方法,然后我们会有多个工厂类实现这个接口(或者继承这个抽象类),每个工厂类负责创建一种具体的对象。
而在抽象工厂模式中,我们也会有一个工厂接口(或者抽象类),但这个接口(或者抽象类)中定义了创建多种对象的方法,每种对象都代表一个产品,这些产品通常是相关联的。然后我们会有多个工厂类实现这个接口(或者继承这个抽象类),每个工厂类负责创建一系列具体的对象。
对于 Java 的 DocumentBuilderFactory
,为什么我们说它是抽象工厂模式而不是工厂方法模式呢?
在 DocumentBuilderFactory
的情况下,我们有一个抽象的工厂(DocumentBuilderFactory
),它能创建多种产品,如 DocumentBuilder
、Transformer
等。虽然最常用的产品可能是 DocumentBuilder
,但 DocumentBuilderFactory
还有能力创建其他类型的产品,如 XPathFactory
,这一点在抽象工厂模式中是很常见的。所以,DocumentBuilderFactory
更接近于抽象工厂模式。
然而,设计模式并不是非黑即白的,有时候一个类可能同时含有多种设计模式的特性。关键是理解这些设计模式背后的思想,并能在合适的场景下应用它们。