抽象工厂模式

129 阅读5分钟

Abstract Factory Pattern.

别名:Kit

定义

提供创建一系列相关或相互依赖对象的接口,且不需指定它们具体的类。

相关概念:

产品等级结构 与 产品族

产品族| A1 B1 C1

| A2 B2 C2

| A3 B3 C3

—— —— —— —— 产品等级结构

产品族:主要同一厂家的产品

产品等级结构:不同厂家都有可能创建的东西

eg:

手机品牌(Apple,XiaoMi,HUAWEI)都有自己的手机、平板、电脑产品线。

通过产品等级结构和产品族来表现即:

iPhone | iPad | Mac

--- Apple 产品线 ---

XiaoMI | MiPad | MIComputer

--- XiaoMi 产品线 ---

Mate | MatePad | MateComputer

--- HUAWEI 产品线 ---

手机 | 平板 | 电脑


应用场景

1.代码需要与多个不同系列的相关产品交互,但无法提前获知其相关信息。或者出于对未来扩展性的考虑,而你不希望代码基于产品的具体类进行构建。

抽象工厂为你提供了一个接口,可用于创建于每个系列产品的对象。只要代码通过该接口创建对象,那么你就不会生成与应用程序已生成的产品类型不一致的产品。

2.有一个基于一组抽象方法的类,且其主要功能因此变得不明确。

在设计良好的程序中, 每一个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。


实现方法

1.以不同的产品类型与产品变体为维度绘制矩阵

2.为所有产品声明抽象产品接口。然后让所有具体产品类实现这些接口

3.声明抽象工厂接口,并且在接口中为所有抽象产品提供一组构建方法

4.为每种变体实现一个具体工厂类

5.在应用程序中开发初始化代码。该代码根据应用程序配置或当前环境,对特定具体工厂类进行初始化。然后对该工厂对象传递所有需要创建产品的类

6.找出代码中所有对产品构造函数的直接调用,将其替换为对工厂对象中相应构建方法的调用

AbstractFactory将产品对象的创建延迟到它的ConcreteFactory子类


优缺点

优点

1.可以确保同一工厂生成的产品相互匹配

2.可以避免客户端和具体产品代码的耦合

3.单一职责原则。可以将产品生成代码抽取到同一位置,使代码易于维护

4.开闭原则。向应用程序中引入新产品变体时,你无需修改客户端代码

缺点

1.采用该模式需要向应用中引入众多接口和类,代码可能会比之前更加复杂,难以支持新种类的产品


结构

UML图

classDiagram
ProductA <|-- ConcreteProductA1
ProductA <|-- ConcreteProductA2
ProductB <|-- ConcreteProductB1
ProductB <|-- ConcreteProductB2
ConcreteFactory1 ..> ConcreteProductA1
ConcreteFactory1 ..> ConcreteProductB1
ConcreteFactory2 ..> ConcreteProductA2
ConcreteFactory2 ..> ConcreteProductB2
AbstractFactory<|..ConcreteFactory1
AbstractFactory<|..ConcreteFactory2
Client-->AbstractFactory
class AbstractFactory{
	<<interface>>
	+createProductA() ProductA
	+createProductB() ProductB
}

class Client{
	-factory:AbstractFactory
	+Client(f:AbstractFactory)
	+someOperation()
}

参与者

1.抽象产品( Abstract Product ) :为构成系统产品的一组不同但相关的产品声明接口

2.具体产品( Concrete Product ) :是抽象产品的多种不同类型实现。所有变体都必须实现相应的抽象产品

3.抽象工厂( Abstract Factory ) :接口声明了一组创建各种抽象产品的方法

4.具体工厂( Concrete Factory ) :实现抽象工厂的构建方法。每个具体工厂都对应特定产品变体,且仅创建此种产品变体

5.客户端( Client ) :只需通过抽象接口调用工厂和产品对象,就能与任何具体工厂/产品变体交互


通用写法

public abstract class ProductA {
   void doA(){};
}
​
public abstract class ProductB {
   void doB(){};
}
​
public class ConcreteProductA1 extends ProductA{
   @Override
   void doA() {
       System.out.println("这是由 Factory1 生产出来的 ProductA");
  }
}
​
public class ConcreteProductB1 extends ProductB{
   @Override
   void doB() {
       System.out.println("这是由 Factory1 生产出来的 ProductB");
  }
}
​
public class ConcreteProductA2 extends ProductA{
   @Override
   void doA() {
       System.out.println("这是由 Factory2 生产出来的 ProductA");
  }
}
​
public class ConcreteProductB2 extends ProductB{
   @Override
   void doB() {
       System.out.println("这是由 Factory2 生产出来的 ProductB");
  }
}
​
public interface AbstractFactory { 
   ProductA createProductA();
   
   ProductB createProductB();
}
​
public class ConcreteFactory1 implements AbstractFactory{
   @Override
   public ProductA createProductA() {
       return new ConcreteProductA1();
  }
​
   @Override
   public ProductB createProductB() {
       return new ConcreteProductB1();
  }
}
​
public class ConcreteFactory2 implements AbstractFactory{
   @Override
   public ProductA createProductA() {
       return new ConcreteProductA2();
  }
​
   @Override
   public ProductB createProductB() {
       return new ConcreteProductB2();
  }
}
​
public class Client {
   public static void main(String[] args) {
       AbstractFactory factory = new ConcreteFactory1();
​
       ProductA productA = factory.createProductA();
       ProductB productB = factory.createProductB();
​
       productA.doA();
       productB.doB();
​
       factory = new ConcreteFactory2();
       factory.createProductA().doA();
       factory.createProductB().doB();
  }
}

案例

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

按钮和复选框作为产品。其中它们的变体为: macOS & Windows

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

客户端代码使用抽象接口与工厂和产品进行交互。

Button

public interface Button {
   void paint();
}
public class MacOSButton implements Button{
   @Override
   public void paint() {
       System.out.println("You created MacOSButton");
  }
}
public class WindowsButton implements Button{
   @Override
   public void paint() {
       System.out.println("You created WindowsButton");
  }
}
​

CheckBox

public interface CheckBox {
   void paint();
}
public class MacOSCheckbox implements CheckBox{
   @Override
   public void paint() {
       System.out.println("You created MacOSCheckbox.");
  }
}
public class WindowsCheckbox implements CheckBox{
   @Override
   public void paint() {
       System.out.println("You created WindowsCheckbox.");
  }
}

factories

public interface GUIFactory {
   Button createButton();
   CheckBox createCheckbox();
}
public class MacOSFactory implements GUIFactory{
   @Override
   public Button createButton() {
       return new MacOSButton();
  }
​
   @Override
   public CheckBox createCheckbox() {
       return new MacOSCheckbox();
  }
}
public class WindowsFactory implements GUIFactory{
   @Override
   public Button createButton() {
       return new WindowsButton();
  }
​
   @Override
   public CheckBox createCheckbox() {
       return new WindowsCheckbox();
  }
}

客户端

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();
  }
}
​
public class Client {
   private static Application configureApplication() {
       Application app;
       GUIFactory factory;
       String osName = "mac";
       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();
  }
}