抽象工厂模式(Abstract Factory Pattern)是一种创建模式(Creational Design Patterns)。抽象工厂模式可被用于创建一组不同类型、但相互协作的对象。通过使用抽象工厂模式,开发人员在开发业务逻辑时,无需考虑创建对象的逻辑,也无需考虑创建出来的、不同类型对象之间是否匹配。当对象创建的逻辑发生变化时,不影响对象使用的逻辑。抽象工厂模式的工作方式与工厂模式的工作方式十分相似;它们都用于创建对象。然而,抽象工厂模式在工厂模式之上又添加了一层抽象层。抽象工厂模式与工厂模式的区别如下:
在抽象工厂模式中,有五个参与方。
图一 抽象工厂模式结构图
我们将使用配置笔记本电脑(Laptop)的例子来介绍抽象工厂模式的使用方法。在例子中,我们只关心笔记本电脑的处理器(Processor)和操作系统(Operating System)的配置。
我们首先定义Processor接口,表示处理器。并且,我们还定义了两个子类IntelProcessor和M1Processor,用来表示英特尔(Intel)处理器和苹果自研的M1处理器。成员方法install()表示在给定的Laptop对象上安装处理器。在本例中,我们假设苹果的MacBook只使用苹果自研的M1处理器。
interface Processor {
void install(Laptop laptop);
}
public class IntelProcessor extends Processor {
@Override
public void install(Laptop laptop) {
System.out.println("Install an Intel processor ...");
}
}
public class M1Processor extends Processor {
@Override
public void install(Laptop laptop) {
System.out.println("Install an M1 processor ...");
}
}
然后,我们再定义操作系统接口OperatingSystem,和两个实现类Linux和MacOS。成员方法install()表示在给定的Laptop对象上安装操作系统。
interface OperatingSystem {
void install(Laptop laptop);
}
public class Linux extends OperatingSystem {
@Override
public void install(Laptop laptop) {
System.out.println("Install Linux ...");
}
}
public class MacOS extends OperatingSystem {
@Override
public void install(Laptop laptop) {
System.out.println("Install macOS ...");
}
}
Laptop类包含Processor成员变量和OperatingSystem成员变量。构造函数接受Processor和OperatingSystem两个参数。
public class Laptop {
protected Processor processor = null;
protected OperatingSystem os = null;
public Laptop (Processor processor, OperatingSystem os) {
this.processor = processor;
this.os = os;
}
}
我们再创造两个接口ProcessorFactory和OperatingSystemFactory,用于创建笔记本的两个部件。这是一个工厂模式的应用。它们分别定义了一个方法create(),用于创建处理器Processor或者操作系统OperatingSystem对象。IntelProcessorFactory和M1ProcessorFactory实现了ProcessorFactory接口,用于创建Intel处理器对象和M1处理器对象。LinuxFactory和MacOSFactory实现了OperatingSystemFactory接口,用于创建Linux操作系统对象和MacOS操作系统对象。
interface ProcessorFactory {
Processor create();
}
public class IntelProcessorFactory implements ProcessorFactory {
@Override
public Processor create() {
return new IntelProcessor();
}
}
public class M1ProcessorFactory implements ProcessorFactory {
@Override
public Processor create() {
return new M1Processor();
}
}
interface OperatingSystemFactory {
OperatingSystem create();
}
public class LinuxFactory implements OperatingSystemFactory {
@Override
public OperatingSystem create() {
return new Linux();
}
}
public class MacOSFactory implements OperatingSystemFactory {
@Override
public OperatingSystem create() {
return new MacOs();
}
}
最后,我们使用LaptopFactory类创建Laptop对象。LaptopFactory使用了抽象工厂模式,它的newInstance()方法接收一个参数,用于表明待创建的Laptop对象的种类。它的create()方法用于创建并组装笔记本对象。两个具体实现类LinuxLaptopFactory和MacbookFactory分别用于创建LinuxLaptop和Macbook对象。
public abstract class LaptopFactory {
private ProcessorFactory processorFactory = null;
private OperatingSystemFactory operatingSystemFactory = null;
public LaptopFactory(ProcessorFactory pf, OperatingSystemFactory osf) {
this.processorFactory = pf;
this.operatingSystemFactory = osf;
}
public Laptop create() {
Processor processor = this.processorFactory.create();
OperatingSystem os = this.operatingSystemFactory.create();
Laptop laptop = new Laptop(this.processor, this.os);
this.processor.install(laptop);
this.os.install(laptop);
return laptop;
}
public static LaptopFactory newInstance(String type) throws IllegalArgumentException {
if ("Linux".equals(type)) {
return new LinuxLaptopFactory();
} else if ("MacOS".equals(type)) {
return new MacbookFactory();
} else {
throw new IllegalArgumentException();
}
}
}
public class LinuxLaptopFactory extends LaptopFactory {
public LinuxLaptop() {
super(new IntelProcessorFactory(), new LinuxFactory());
}
}
public class MacbookFactory extends LaptopFactory {
public Macbook() {
super(new M1ProcessorFactory(), new MacOSFactory());
}
}
因此,在客户端处,我们可以使用如下代码创建指定的Laptop对象。
public class LaptopCreationClient {
public static void main(String[] args) {
LaptopFactory linuxLaptopfactory = LaptopFactory.newInstance("Linux");
Laptop linuxLaptop = linuxLaptopfactory.create();
LaptopFactory macOSFactory = LaptopFactory.newInstance("MacOS");
Laptop macOSLaptop = macOSFactory.create();
}
}
这个例子展现了一个抽象工厂模式与工厂模式的主要区别。抽象工厂模式能够将创造出来的对象结合在一起。假如我们需要创建一个LinuxLaptop的对象,如果我们只使用工厂模式创建处理器和操作系统的话,开发人员还需要了解LinuxLaptop对象使用的是Intel处理器对象和Linux操作系统对象。如果这两项搭配错误的话,代码逻辑将是错误的。所以,如果我们使用抽象工厂模式,将部件之间的搭配封装在新增加的抽象层中,以确保创建出的LinuxLaptop对象使用的是Intel处理器对象和Linux操作系统对象,而创建出的Macbook对象使用的是M1处理器对象和MacOS操作系统对象。在对象的使用过程中,开发人员无需担心部件之间的搭配问题。
而且,当我们需要新增一款WindowsLaptop对象时,我们可以新增一个WindowsLaptopFactory类,实现LaptopFactory接口。开发人员无需修改使用端(LaptopCreationClient类)的代码。
抽象工厂模式广泛的应用于各种项目之中,在Java的标准库中也有不少应用。我们在本节中将介绍javax.xml.parsers.DocumentBuilderFactory类中使用的抽象工厂模式。其他的例子还有javax.xml.transform.TransformerFactory和javax.xml.xpath.XPathFactory。读者可自行阅读其源代码。
在DocumentBuilderFactory类中,静态方法newInstance()创建一个默认的DocumentBuilderFactory对象。该对象的newDocumentBuilder()是一个抽象方法,其实现细节在DocumentBuilderFactory类的子类中。
// OpenJDK 15
package javax.xml.parsers;
public abstract class DocumentBuilderFactory {
...
public static DocumentBuilderFactory newInstance() {
return FactoryFinder.find(DocumentBuilderFactory.class, DEFAULT_IMPL);
}
public abstract DocumentBuilder newDocumentBuilder() throws ParserConfigurationException;
...
}
在DocumentBuilderFactory的子类DocumentBuilderFactoryImpl中,newDocumentBuild()方法返回一个DocumentBuilder对象,并在该对象中设置了多项相关的配置信息,以保证DocumentBuilder对象能正常工作。
// OpenJDK 15
package com.sun.org.apache.xerces.internal.jaxp;
public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory {
public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
if (grammar != null && attributes != null) {
...
}
try {
return new DocumentBuilderImpl(this, attributes, features, fSecureProcess);
} catch (SAXException se) {
throw new ParserConfigurationException(se.getMessage());
}
}
}
在使用DocumentBuilderFactory对象创建XML文档的过程中,我们首先会用abstractFactory对象生成出一个factory对象。这个factory对象是用于创建Document对象的。因此,DocumentBuilderFactory使用的是抽象工厂模式。
public class AbstractFactoryClient {
public static void main(String[] args) {
String xml = "<document><body><guitar>Ibanez</guitar><guitar>Gibson</guitar></body></document>";
ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
DocumentBuilderFactory abstractFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder factory = abstractFactory.newDocumentBuilder();
Document doc = factory.parse(bais);
doc.getDocumentElement().normalize();
System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
}
}
本章介绍了抽象工厂模式的结构和使用方法。抽象工厂模式在工厂模式的基础上新增加了一层抽象,将创建出的不同类型的对象有效的结合起来,创建出一个新的、更复杂的对象。这种设计方法能够分离对象之间的逻辑关系,帮助开发人员简化对象使用端的代码逻辑。
注册用户登陆后可留言