当前位置:  首页>> 技术小册>> 经典设计模式Java版

抽象工厂模式

是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。


假设你正在开发一款家具商店模拟器。你的代码中包括一些 类,用于表示:

  1. 一系列相关产品, 例如 椅子 Chair 、 沙发 Sofa 和 咖啡桌 CoffeeTable 。
  2. 系列产品的不同变体。 例如, 你可以使用 现代 Modern 、 维多利亚 Victorian 、 装饰风艺术 ArtDeco 等风格生成 椅子 、 沙发 和 咖啡桌 。

你需要设法单独生成每件家具对象,这样才能确保其风格一 致。如果顾客收到的家具风格不一样,他们可不会开心。

此外, 你也不希望在添加新产品或新风格时修改已有代码。 家具供应商对于产品目录的更新非常频繁,你不会想在每次 更新时都去修改核心代码的。


解决方案

首先,抽象工厂模式建议为系列中的每件产品明确声明接口 (例如椅子、沙发或咖啡桌)。然后,确保所有产品变体都继 承这些接口。例如,所有风格的椅子都实现 椅子 接口;所 有风格的咖啡桌都实现 咖啡桌 接口,以此类推。

接下来,我们需要声明抽象工厂——包含系列中所有产品构 造方法的接口。例如 createChair 创建椅子 、 createSofa 创建沙发 和 createCoffeeTable 创建咖啡桌 。 这些方法必 须返回抽象产品类型,即我们之前抽取的那些接口: 椅子 , 沙发 和 咖啡桌 等等。

那 么 该 如 何 处 理 产 品 变 体 呢? 对 于 系 列 产 品 的 每 个 变 体, 我 们 都 将 基 于 抽象工厂 接 口 创 建 不 同 的 工 厂 类。 每 个 工 厂 类 都 只 能 返 回 特 定 类 别 的 产 品, 例 如, 现代家具工厂 ModernFurnitureFactory 只 能 创 建 现代椅子 ModernChair 、 现代沙发 ModernSofa 和 现代咖啡桌 ModernCoffeeTable 对象。
 
客户端代码可以通过相应的抽象接口调用工厂和产品类。你 无需修改实际客户端代码,就能更改传递给客户端的工厂类, 也能更改客户端代码接收的产品变体。

假设客户端想要工厂创建一把椅子。客户端无需了解工厂类, 也不用管工厂类创建出的椅子类型。无论是现代风格,还是 维多利亚风格的椅子,对于客户端来说没有分别,它只需调 用抽象 椅子 接口就可以了。这样一来,客户端只需知道椅 子以某种方式实现了 sitOn 坐下 方法就足够了。此外,无 论工厂返回的是何种椅子变体,它都会和由同一工厂对象创 建的沙发或咖啡桌风格一致。
 
最后一点说明:如果客户端仅接触抽象接口,那么谁来创建 实际的工厂对象呢?一般情况下,应用程序会在初始化阶段 创建具体工厂对象。而在此之前,应用程序必须根据配置文 件或环境设定选择工厂类别。


  1. 抽象产品(Abstract Product)为构成系列产品的一组不同但 相关的产品声明接口。
  2. 具体产品(Concrete Product)是抽象产品的多种不同类型实 现。所有变体(维多利亚/现代)都必须实现相应的抽象产品 (椅子/沙发)。
  3. 抽象工厂(Abstract Factory)接口声明了一组创建各种抽象 产品的方法。
  4. 具体工厂(Concrete Factory)实现抽象工厂的构建方法。每 个具体工厂都对应特定产品变体,且仅创建此种产品变体。
  5. 尽管具体工厂会对具体产品进行初始化,其构建方法签名必 须返回相应的抽象产品。这样,使用工厂类的客户端代码就 不会与工厂创建的特定产品变体耦合。客户端(Client)只 需通过抽象接口调用工厂和产品对象,就能与任何具体工厂/ 产品变体交互。

代码示例

JAVA版:

跨平台 GUI 组件系列及其创建方式

在本例中,按钮和复选框将被作为产品。它们有两个变体:macOS 版和 Windows 版。

抽象工厂定义了用于创建按钮和复选框的接口。而两个具体工厂都会返回同一变体的两个产品。

客户端代码使用抽象接口与工厂和产品进行交互。同样的代码能与依赖于不同工厂对象类型的多种产品变体进行交互。
buttons:第一个产品层次结构
buttons/Button.java

  1. package design_pattern.abstract_factory.example.buttons;
  2. /**
  3. * Abstract Factory assumes that you have several families of products,
  4. * structured into separate class hierarchies (Button/Checkbox). All products of
  5. * the same family have the common interface.
  6. *
  7. * This is the common interface for buttons family.
  8. */
  9. public interface Button {
  10. void paint();
  11. }

buttons/MacOSButton.java

  1. package design_pattern.abstract_factory.example.buttons;
  2. /**
  3. * All products families have the same varieties (MacOS/Windows).
  4. *
  5. * This is a MacOS variant of a button.
  6. */
  7. public class MacOSButton implements Button {
  8. @Override
  9. public void paint() {
  10. System.out.println("You have created MacOSButton.");
  11. }
  12. }

buttons/WindowsButton.java

  1. package design_pattern.abstract_factory.example.buttons;
  2. /**
  3. * All products families have the same varieties (MacOS/Windows).
  4. *
  5. * This is another variant of a button.
  6. */
  7. public class WindowsButton implements Button {
  8. @Override
  9. public void paint() {
  10. System.out.println("You have created WindowsButton.");
  11. }
  12. }

buttons:第二个产品层次结构
checkboxes/Checkbox.java

  1. package design_pattern.abstract_factory.example.checkboxes;
  2. /**
  3. * Checkboxes is the second product family. It has the same variants as buttons.
  4. */
  5. public interface Checkbox {
  6. void paint();
  7. }

checkboxes/MacOSCheckbox.java

  1. package design_pattern.abstract_factory.example.checkboxes;
  2. /**
  3. * All products families have the same varieties (MacOS/Windows).
  4. *
  5. * This is a variant of a checkbox.
  6. */
  7. public class MacOSCheckbox implements Checkbox {
  8. @Override
  9. public void paint() {
  10. System.out.println("You have created MacOSCheckbox.");
  11. }
  12. }

checkboxes/WindowsCheckbox.java

  1. package design_pattern.abstract_factory.example.checkboxes;
  2. /**
  3. * All products families have the same varieties (MacOS/Windows).
  4. *
  5. * This is another variant of a checkbox.
  6. */
  7. public class WindowsCheckbox implements Checkbox {
  8. @Override
  9. public void paint() {
  10. System.out.println("You have created WindowsCheckbox.");
  11. }
  12. }

factories
factories/GUIFactory.java: 抽象工厂

  1. package design_pattern.abstract_factory.example.factories;
  2. import design_pattern.abstract_factory.example.buttons.Button;
  3. import design_pattern.abstract_factory.example.checkboxes.Checkbox;
  4. /**
  5. * Abstract factory knows about all (abstract) product types.
  6. */
  7. public interface GUIFactory {
  8. Button createButton();
  9. Checkbox createCheckbox();
  10. }

factories/MacOSFactory.java: 具体工厂 ( mac­OS)

  1. package design_pattern.abstract_factory.example.factories;
  2. import design_pattern.abstract_factory.example.buttons.Button;
  3. import design_pattern.abstract_factory.example.buttons.MacOSButton;
  4. import design_pattern.abstract_factory.example.checkboxes.Checkbox;
  5. import design_pattern.abstract_factory.example.checkboxes.MacOSCheckbox;
  6. /**
  7. * Each concrete factory extends basic factory and responsible for creating
  8. * products of a single variety.
  9. */
  10. public class MacOSFactory implements GUIFactory {
  11. @Override
  12. public Button createButton() {
  13. return new MacOSButton();
  14. }
  15. @Override
  16. public Checkbox createCheckbox() {
  17. return new MacOSCheckbox();
  18. }
  19. }

factories/WindowsFactory.java: 具体工厂 (Windows)

  1. package design_pattern.abstract_factory.example.factories;
  2. import design_pattern.abstract_factory.example.buttons.Button;
  3. import design_pattern.abstract_factory.example.buttons.WindowsButton;
  4. import design_pattern.abstract_factory.example.checkboxes.Checkbox;
  5. import design_pattern.abstract_factory.example.checkboxes.WindowsCheckbox;
  6. /**
  7. * Each concrete factory extends basic factory and responsible for creating
  8. * products of a single variety.
  9. */
  10. public class WindowsFactory implements GUIFactory {
  11. @Override
  12. public Button createButton() {
  13. return new WindowsButton();
  14. }
  15. @Override
  16. public Checkbox createCheckbox() {
  17. return new WindowsCheckbox();
  18. }
  19. }

app

  1. app/Application.java: 客户端代码
  2. package design_pattern.abstract_factory.example.app;
  3. import design_pattern.abstract_factory.example.buttons.Button;
  4. import design_pattern.abstract_factory.example.checkboxes.Checkbox;
  5. import design_pattern.abstract_factory.example.factories.GUIFactory;
  6. /**
  7. * Factory users don't care which concrete factory they use since they work with
  8. * factories and products through abstract interfaces.
  9. */
  10. public class Application {
  11. private Button button;
  12. private Checkbox checkbox;
  13. public Application(GUIFactory factory) {
  14. button = factory.createButton();
  15. checkbox = factory.createCheckbox();
  16. }
  17. public void paint() {
  18. button.paint();
  19. checkbox.paint();
  20. }
  21. }

Demo.java: 程序配置

  1. package design_pattern.abstract_factory.example;
  2. import design_pattern.abstract_factory.example.app.Application;
  3. import design_pattern.abstract_factory.example.factories.GUIFactory;
  4. import design_pattern.abstract_factory.example.factories.MacOSFactory;
  5. import design_pattern.abstract_factory.example.factories.WindowsFactory;
  6. /**
  7. * Demo class. Everything comes together here.
  8. */
  9. public class Demo {
  10. /**
  11. * Application picks the factory type and creates it in run time (usually at
  12. * initialization stage), depending on the configuration or environment
  13. * variables.
  14. */
  15. private static Application configureApplication() {
  16. Application app;
  17. GUIFactory factory;
  18. String osName = System.getProperty("os.name").toLowerCase();
  19. if (osName.contains("mac")) {
  20. factory = new MacOSFactory();
  21. app = new Application(factory);
  22. } else {
  23. factory = new WindowsFactory();
  24. app = new Application(factory);
  25. }
  26. return app;
  27. }
  28. public static void main(String[] args) {
  29. Application app = configureApplication();
  30. app.paint();
  31. }
  32. }

OutputDemo.txt:执行结果

  1. You create WindowsButton.
  2. You created WindowsCheckbox.


该分类下的相关小册推荐: