首先,让我们考虑一个支持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 模式的强项。