抽象工厂(Abstract Factory)设计模式
首先,让我们考虑一个支持look-and-feel 标准的用户界面工具包,例如Motif 和 Presentation Manager。为了保证look and feel 的一致性,应用程序不应该为一个特定的look-and-feel 硬编码其窗口组件。因为这样将会造成以后很难改变窗口的观感。
为了解决这一问题,我们定义了一个 WidgetFactory 类。这个类具有一些方法,用于创建不同的窗口组件。如 createScrollBar 方法将用于创建一个 ScrollBar,createWindow 方法将创建 Window 类。对WidgetFactory 的方法所能创建的每一类窗口组件,都对应一个抽象类。如这里的Window 和 ScrollBar。WidgetFactory 是一个抽象类,其子类将用于创建具体的窗口组件。如下图所示:
从上面可以看出,当我们需要创建另一类 观感时,只需要继承 WidgetFactory 抽象工厂类,并覆盖其方法即可。
这里使用的就是 Abstract Factory 抽象工厂模式。该模式的结构图如下所示:
Abstract Factory 模式具有以下特点:
1. 客户与具体实现分离。客户使用的是抽象产品。实现与使用分离。
2. 易于扩展新的产品类。只需要实现一个新的实体工厂,并继承自抽象工厂,即可轻松获得一个新的产品类别。
3. 产品一致性比较好。一个应用一次只能使用同一系列中的对象,如上面不能将 MotifWindow 和 PMScrollBar 混合起来使用。
4. Abstract Factory 也有一个问题。即不容易扩展新种类的产品。针对这个问题,后面会有一个解决方法。
下面我们看一个抽象工厂类的例子。程序是用Java 写的。
首先是抽象工厂类
AbstractFactory.java:
public abstract class AbstractFactory { Button button; TextBox textbox; public abstract void createButton(); public abstract void createTextbox(); }
可以看出,该类用于产生产品 Button 和 TextBox。Button 和 TextBox 也是抽象类。
Button.java:
public abstract class Button { protected abstract void createShape(); } TextBox.java: public abstract class TextBox { protected abstract void createText(); }
LinuxFactory 和 WindowsFactory 继承自 AbstractFactory。它们的createButton 分别产生 LinuxButton、LinuxTextBox 和 WindowsButton 、WindowsTextBox。
LinuxFactory.java: public class LinuxFactory extends AbstractFactory { public void createButton() { button = new LinuxButton(); button.createShape(); } public void createTextbox() { textbox = new LinuxTextBox(); textbox.createText(); } } WindowsFactory.java: public class WindowsFactory extends AbstractFactory { public void createButton() { button = new WindowsButton(); button.createShape(); } public void createTextbox() { textbox = new WindowsTextBox(); textbox.createText(); } } LinuxButton.java: public class LinuxButton extends Button { protected void createShape() { System.out.println("create Linux Button"); } } LinuxTextBox.java: public class LinuxTextBox extends TextBox { protected void createText() { System.out.println("create linux textbox"); } } WindowsButton.java: public class WindowsButton extends Button { protected void createShape() { System.out.println("create windows button"); } } WindowsTextBox.java: public class WindowsTextBox extends TextBox { protected void createText() { System.out.println("create windows textbox"); } }
下面Client 类显示了抽象工厂模式中对象的使用:
Client.java:
public class Client { public static void main(String args[]) { AbstractFactory factory = new LinuxFactory(); factory.createButton(); factory.createTextbox(); factory = new WindowsFactory(); factory.createButton(); factory.createTextbox(); } }
从Client 类可以看出,在使用抽象工厂模式时,用实体工厂创建创建工厂类,然后通过抽象工厂类创建部件。所创建的实体产品对客户透明。
我们再来看这个设计。我们通过AbstractFactory 可以创建 Button 和 TextBox,但是现在我们需要创建另一种产品 TextField。这就比较难办了。我们需要更改Abstract Factory ,并更改所有继承了 AbstractFactory 的类。显然这样做是非常不合适的。因此 Abstract Factory 模式在扩展新产品时是有一些问题的。
一种解决办法是给创建对象的操作提供一个参数,这个参数用于指定被创建对象的种类。尽管这是一个可用的解决方案,但是也有一定问题。
因此,我们需要知道,扩展新产品不是Abstract Factory 模式的强项。