【Design Pattern】Creational - Factory

Posted by 西维蜀黍 on 2018-11-11, Last Modified on 2023-01-10

工厂模式具体包括三种:

  • 简单工厂模式(Simple Factory Pattern)/静态工厂方法模式(Static Factory Method Pattern)
  • 工厂方法模式(Factory Method Pattern)
  • 抽象工厂模式(Abstruct Factory Pattern)

1 简单工厂模式(Simple Factory Pattern)/静态工厂方法模式(Static Factory Method Pattern)

定义

简单工厂模式(Simple Factory Pattern),又称为静态工厂方法模式(Static Factory Method Pattern),它属于创建式模式。

在简单工厂模式中,包含一个工厂类,在这个工厂类中,包含一个静态方法;在调用该静态方法时,需要传入一个参数,这个参数标识了我们具体需要哪一种产品类。

客户端在调用了这个静态方法后,将返回一个被指定的产品类的实例。

组成

简单工厂模式包含如下角色:

  • Product(抽象产品角色):抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
  • ConcreteProduct(具体产品角色):具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
  • Factory(工厂角色):工厂角色负责实现创建所有实例的内部逻辑

例子

比如,一个软件系统提供多个外观不同的按钮(如圆形按钮、方形按钮),这些按钮都继承于同一个基类(称为按钮类)。在继承基类之后,各个按钮类通过修改基类的属性,从而实现显示出不同的形状。

当我们需要使用到某一个具体的按钮对象(如圆形按钮)时,仅需调用一个生成具体按钮对象的静态方法,并传入标识该具体按钮类的参数(如一个枚举值,ButtonType.RoundButton),即可得到这个具体按钮类的实例。

抽象按钮类

abstract class Button {
    public abstract void draw();
}

圆形按钮类

class RoundButton extends Button {
    public void draw() {
        // draw round button
    }
}

方形按钮类

class SquareButton extends Button {
    public void draw() {
        // draw square button
    }
}

枚举

enum ButtonType {
    RoundButton,
    SquareButton
}

按钮工厂类

class ButtonFactory {
    public static Button CreateButton(ButtonType buttonType) {
        switch (buttonType) {
            case ButtonType.RoundButton:
                return new RoundButton();
            case ButtonType.SquareButton:
                return new SquareButton();
            default:
                return null;
        }
    }
}

调用

class Program {
    static void main(string[] args) {
        Button button = ButtonFactory.CreateButton(ButtonType.RoundButton);
        if (button != null) {
            button.draw();
        }
    }
}

应用场景

在真实的系统中,产品可以形成复杂的等级结构,比如下图所示的树形结构上就有许多抽象产品类和具体产品类。如下图:

这个时候,简单工厂模式采取的是同一使用同一个工厂类,来处理同一产品类(抽象)。如下图:

这样做的好处是设计简单,产品类的等级结构不过反映到工厂类中来,从而产品类的等级结构的变化也不会影响工厂类。但这样做的缺点是,增加新的产品必将导致工厂类的修改。

优缺点

优点

  • 对调用者来说,获得一个具体产品对象非常简单。当需要一个圆形按钮对象时,只需要传入一个圆形按钮标识参数,即可获得一个圆形按钮对象,而无需了解其创建细节;
  • 去除了调用者对具体产品类的依赖(即调用者并不需要与RoundButton类产生耦合,本质上,是利用了面向对象的多态特性)。

缺点

  • 简单工厂模式最大的问题在于工厂类的职责相对较重,工厂类中的方法逻辑较为复杂;
  • 而且,当每增加一种具体产品时,就要修改工厂类中方法中的判断逻辑,这一修改违反了 SOLID 原则中的开闭原则(The Open Closed Principle)

2 工厂方法模式(Factory Method Pattern)

背景

由于一个工厂类负责所有产品的创建,增加新的产品必将导致工厂类的修改,将必要的逻辑加入到工厂类中。因此,简单工厂模式(Simple Factory Pattern)的缺点是违反了开闭原则(The Open Closed Principle)。

现在对该实现进行改进,不再设计一个按钮工厂类来统一负责所有具体按钮产品的实例创建,而是将具体按钮产品的实例创建交给专门的工厂子类(每个具体的按钮产品都有一个对应的工厂类)去完成。

我们先定义一个抽象的按钮工厂类,再定义具体的工厂类来生成【圆形按钮】、【矩形按钮】、【菱形按钮】等,分别称为【圆形按钮工厂】、【矩形按钮工厂】、【菱形按钮工厂】,它们均实现在抽象按钮工厂类中定义的方法。

这种抽象化的结果使这种结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的按钮类型,只需要为这种新类型的按钮创建一个具体的工厂类就可以获得该新按钮的实例,这一特点无疑使得工厂方法模式比简单工厂模式更具有良好的扩展性,同时完全符合开闭原则(The Open Closed Principle)。

定义

工厂方法模式(Factory Method Pattern)又称为工厂模式,它属于类创建型模式。

在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

组成

工厂方法模式包含如下角色:

  • 抽象产品(Abstract Product)
  • 具体产品(Concrete Product)
  • 抽象工厂(Abstract Factory)
  • 具体工厂(Concrete Factory)

例子

产品接口

public interface Product {
}

具体产品类

public class ConcreteProduct1 implements Product {
}

工厂接口

public interface Creator {
    //工厂方法
    public Product factory();
}

具体工厂类

public class ConcreteCreator1 implements Creator {

    public Product factory() {//实现工厂方法
        return new ConcreteProduct1();
    }
}

调用

public class Client {
    private static Creator creator1, creator2;
    private static Product prod1, prod2;

    public static void main(String[] args) {
        creator1 = new ConcreteCreator1();
        prod1 = creator1.factory();
    
        creator2 = new ConcreteCreator2();
        prod2 = creator2.factory();
    }
}

优缺点

优点

  • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
  • 在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,也无须修改现有的具体工厂和具体产品,而只要添加一个新的具体工厂和新的具体产品即可。这样,系统的可扩展性增强了,完全符合“开闭原则”。

缺点

  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度

3 抽象工厂模式(Abstruct Factory Pattern)

抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。

工厂方法模式中,一个具体的工厂类负责生产具体的产品,每一个具体工厂对应一种具体产品。一般情况下,一个具体工厂类中只有一个工厂方法。

但是有时候,我们需要一个工厂可以提供多个创建不同具体产品对象的方法。

当需要一个工程不仅仅只提供某一个具体产品(而是可提供多个具体产品)时,就需要使用抽象工厂模式。

产品等级结构、产品族的概念

产品等级结构:属于同一抽象产品下的所有产品组成了一个产品等级结构,比如像下图中的Button、Text就是二个产品等级结构。

所谓产品族,是指位于不同产品等级结构中,功能相关联的产品组成的家族,比如下图中的UnixButton、UnixText就是一个产品族,而WinButton、WinText又是另一个产品族。看下图会更清楚一点:

比如Button与Text就是不同的两个产品级结构,而Uinx下Button与Text就组成了Unix下的一个产品族,相似地Windows属于另一产品族。

模式定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类,属于对象创建型模式。

模式结构

抽象工厂模式包含如下角色:

  • AbstractFactory:抽象工厂
  • ConcreteFactory:具体工厂
  • AbstractProduct:抽象产品
  • Product:具体产品

代码说明

与工厂方式模式区别

工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。

另外,抽象工厂模式中的工厂等级结构应该像工厂方法模式中的工厂等级结构那样,与产品等级结构是平行的。

Reference