简单工厂模式

简单工厂模式是一种创建型模式。创建型模式关注对象的创建过程,它将对象的创建和使用分离,在使用对象时无须知道对象的创建细节。使得相同的创建过程可以多次复用,且修改两者中的一个对另一个几乎不造成影响,使系统设计更加符合单一职责模式。

同时书上举例一个生活中的例子,我觉得能很好得帮助像我这样的初学者了解创建型模式的概念:在现实生活中如果想吃苹果,可以自己种或者去超市买。自己种肯定费时费力;而去超市买的苹果都是农场经过规范的生产流程进行培育的,更加专业。将苹果的生产和消费分离,可以无须关注苹果的种植过程,提高获取苹果的效率。同时消费者可以随意选择不同品牌的苹果,增加了灵活性。

代码设计中存在的不足

比如,某销售管理系统支持多种支付方式,包括现金支付、信用卡支付以及代金券支付等。感觉我一开始也会进行如下代码设计:

  1. void pay(string type)
  2. {
  3.     if (type == "cash")
  4.     {
  5.          //现金支付处理代码
  6.     }
  7.     else if (type == "creditcard")
  8.     {
  9.          //信用卡支付处理代码
  10.     }
  11.     else if (type == "voucher")
  12.     {
  13.          //代金券处理代码
  14.     }
  15.     else
  16.     {
  17.          // ……
  18.     }
  19. }

由于不同的支付方式的处理方式不一致,因此导致该方法源代码相当冗长,增加新的支付模式的时候,又要修改这段代码。而且前后存在强耦合关系,维护工作量大,测试难度也大,扩展和修改都不灵活。后续使用简单工厂模式对其进行重构。

简单工厂模式

简单工厂模式又称为静态工厂方法模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类

简单工厂模式的结构如下图:

Factory即工厂类,它是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。在工厂类中提供了静态的工厂方法factoryMethod(),它返回一个抽象产品类Product,所有的具体产品都是抽象产品的子类。

不足代码的改进

之前的支付代码改进如下,结构和之前介绍的简单工厂模式结构一样:


  1. class AbstractPay
  2. {
  3. public:
  4.     virtual void pay() = 0;
  5. };
  6.  
  7. class CashPay : public AbstractPay
  8. {
  9. public:
  10.     void pay()
  11.     {
  12.          // 现金支付处理代码
  13.     }
  14. };
  15.  
  16. class CreditcardPay : public AbstractPay
  17. {
  18. public:
  19.     void pay()
  20.     {
  21.          // 信用卡支付处理代码
  22.     }
  23. };
  24.  
  25. class PayMethodFactory
  26. {
  27. public:
  28.     static AbstractPay* getPayMethod(string type)
  29.     {
  30.          if (type == "cash")
  31.              return new CashPay();
  32.          else if (type == "creditcard")
  33.              return new CreditcardPay();
  34.  
  35.          // ……
  36.     }
  37. }

简单工厂模式的优缺点

在使用了简单工厂模式之后,系统中类的个数增加,每一种支付处理方式都封装在单独的类中,而且工厂类中只有简单的判断逻辑代码,不需要关系具体的业务处理过程,很好地满足了“单一职责原则”。

如上面例子,在增加新的支付方式时,只需要添加一个新的具体支付类并实现其中的pay方法,同时对工厂类PayMethodFactory做简单的修改即可,无须对原有代码进行大面积的改动。但这也是简单工厂模式最大的问题,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则相违背,并且产品过多的话会使工厂类的职责相对过重。

所以简单工厂模式适合创建对象类型较少的情况,此时不会造成工厂方法中的业务逻辑太过于复杂。

简单工厂模式的扩展

书中举了Java中使用简单工厂模式的例子:在创建密码器时根据静态工厂方法中传入的参数来决定密码器的类型。

  1. Cipher cp = Cipher.getInstance("DESede");

工厂类可以由抽象产品扮演,一个抽象产品类同时也是子类的工厂,也就是说把静态工厂方法写到抽象产品类中。其结构如下图所示: