抽象工厂模式
是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。
假设你正在开发一款家具商店模拟器。你的代码中包括一些 类,用于表示:
你需要设法单独生成每件家具对象,这样才能确保其风格一 致。如果顾客收到的家具风格不一样,他们可不会开心。
此外, 你也不希望在添加新产品或新风格时修改已有代码。 家具供应商对于产品目录的更新非常频繁,你不会想在每次 更新时都去修改核心代码的。
解决方案
首先,抽象工厂模式建议为系列中的每件产品明确声明接口 (例如椅子、沙发或咖啡桌)。然后,确保所有产品变体都继 承这些接口。例如,所有风格的椅子都实现 椅子 接口;所 有风格的咖啡桌都实现 咖啡桌 接口,以此类推。
接下来,我们需要声明抽象工厂——包含系列中所有产品构 造方法的接口。例如 createChair 创建椅子 、 createSofa 创建沙发 和 createCoffeeTable 创建咖啡桌 。 这些方法必 须返回抽象产品类型,即我们之前抽取的那些接口: 椅子 , 沙发 和 咖啡桌 等等。
那 么 该 如 何 处 理 产 品 变 体 呢? 对 于 系 列 产 品 的 每 个 变 体, 我 们 都 将 基 于 抽象工厂 接 口 创 建 不 同 的 工 厂 类。 每 个 工 厂 类 都 只 能 返 回 特 定 类 别 的 产 品, 例 如, 现代家具工厂 ModernFurnitureFactory 只 能 创 建 现代椅子 ModernChair 、 现代沙发 ModernSofa 和 现代咖啡桌 ModernCoffeeTable 对象。
客户端代码可以通过相应的抽象接口调用工厂和产品类。你 无需修改实际客户端代码,就能更改传递给客户端的工厂类, 也能更改客户端代码接收的产品变体。
假设客户端想要工厂创建一把椅子。客户端无需了解工厂类, 也不用管工厂类创建出的椅子类型。无论是现代风格,还是 维多利亚风格的椅子,对于客户端来说没有分别,它只需调 用抽象 椅子 接口就可以了。这样一来,客户端只需知道椅 子以某种方式实现了 sitOn 坐下 方法就足够了。此外,无 论工厂返回的是何种椅子变体,它都会和由同一工厂对象创 建的沙发或咖啡桌风格一致。
最后一点说明:如果客户端仅接触抽象接口,那么谁来创建 实际的工厂对象呢?一般情况下,应用程序会在初始化阶段 创建具体工厂对象。而在此之前,应用程序必须根据配置文 件或环境设定选择工厂类别。
JAVA版:
在本例中,按钮和复选框将被作为产品。它们有两个变体:macOS 版和 Windows 版。
抽象工厂定义了用于创建按钮和复选框的接口。而两个具体工厂都会返回同一变体的两个产品。
客户端代码使用抽象接口与工厂和产品进行交互。同样的代码能与依赖于不同工厂对象类型的多种产品变体进行交互。
buttons:第一个产品层次结构
buttons/Button.java
package design_pattern.abstract_factory.example.buttons;
/**
* Abstract Factory assumes that you have several families of products,
* structured into separate class hierarchies (Button/Checkbox). All products of
* the same family have the common interface.
*
* This is the common interface for buttons family.
*/
public interface Button {
void paint();
}
buttons/MacOSButton.java
package design_pattern.abstract_factory.example.buttons;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is a MacOS variant of a button.
*/
public class MacOSButton implements Button {
@Override
public void paint() {
System.out.println("You have created MacOSButton.");
}
}
buttons/WindowsButton.java
package design_pattern.abstract_factory.example.buttons;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is another variant of a button.
*/
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("You have created WindowsButton.");
}
}
buttons:第二个产品层次结构
checkboxes/Checkbox.java
package design_pattern.abstract_factory.example.checkboxes;
/**
* Checkboxes is the second product family. It has the same variants as buttons.
*/
public interface Checkbox {
void paint();
}
checkboxes/MacOSCheckbox.java
package design_pattern.abstract_factory.example.checkboxes;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is a variant of a checkbox.
*/
public class MacOSCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("You have created MacOSCheckbox.");
}
}
checkboxes/WindowsCheckbox.java
package design_pattern.abstract_factory.example.checkboxes;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is another variant of a checkbox.
*/
public class WindowsCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("You have created WindowsCheckbox.");
}
}
factories
factories/GUIFactory.java: 抽象工厂
package design_pattern.abstract_factory.example.factories;
import design_pattern.abstract_factory.example.buttons.Button;
import design_pattern.abstract_factory.example.checkboxes.Checkbox;
/**
* Abstract factory knows about all (abstract) product types.
*/
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
factories/MacOSFactory.java: 具体工厂 ( macOS)
package design_pattern.abstract_factory.example.factories;
import design_pattern.abstract_factory.example.buttons.Button;
import design_pattern.abstract_factory.example.buttons.MacOSButton;
import design_pattern.abstract_factory.example.checkboxes.Checkbox;
import design_pattern.abstract_factory.example.checkboxes.MacOSCheckbox;
/**
* Each concrete factory extends basic factory and responsible for creating
* products of a single variety.
*/
public class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public Checkbox createCheckbox() {
return new MacOSCheckbox();
}
}
factories/WindowsFactory.java: 具体工厂 (Windows)
package design_pattern.abstract_factory.example.factories;
import design_pattern.abstract_factory.example.buttons.Button;
import design_pattern.abstract_factory.example.buttons.WindowsButton;
import design_pattern.abstract_factory.example.checkboxes.Checkbox;
import design_pattern.abstract_factory.example.checkboxes.WindowsCheckbox;
/**
* Each concrete factory extends basic factory and responsible for creating
* products of a single variety.
*/
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
app
app/Application.java: 客户端代码
package design_pattern.abstract_factory.example.app;
import design_pattern.abstract_factory.example.buttons.Button;
import design_pattern.abstract_factory.example.checkboxes.Checkbox;
import design_pattern.abstract_factory.example.factories.GUIFactory;
/**
* Factory users don't care which concrete factory they use since they work with
* factories and products through abstract interfaces.
*/
public class Application {
private Button button;
private Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void paint() {
button.paint();
checkbox.paint();
}
}
Demo.java: 程序配置
package design_pattern.abstract_factory.example;
import design_pattern.abstract_factory.example.app.Application;
import design_pattern.abstract_factory.example.factories.GUIFactory;
import design_pattern.abstract_factory.example.factories.MacOSFactory;
import design_pattern.abstract_factory.example.factories.WindowsFactory;
/**
* Demo class. Everything comes together here.
*/
public class Demo {
/**
* Application picks the factory type and creates it in run time (usually at
* initialization stage), depending on the configuration or environment
* variables.
*/
private static Application configureApplication() {
Application app;
GUIFactory factory;
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("mac")) {
factory = new MacOSFactory();
app = new Application(factory);
} else {
factory = new WindowsFactory();
app = new Application(factory);
}
return app;
}
public static void main(String[] args) {
Application app = configureApplication();
app.paint();
}
}
OutputDemo.txt:执行结果
You create WindowsButton.
You created WindowsCheckbox.