前不久参加了一个为期四天的设计模式培训,公司以前组织过很多次设计模式培训,主题多为'Java与设计模式',自己一直从事C相关的开发,也就不好越界参与这类培训。而这次主题换成了'C++设计模式',我参加也就名正言顺了。按照人力资源部工作人员的说法这是第一次请老师讲C++与设计模式,这个老师也是第一次给我们公司做培训,因为没有先例,无从知道效果如何,不像以前侯捷来公司培训C++,一般参与的同事都清楚那样的培训收获会很大,毕竟讲师水平很高啊。俗话说:要想能讲出一碗水,那自己首先应该先有一桶水才行。

这次做培训的老师,起码从授课上我感觉还是不合格的,其个人水平不敢胡乱评论,毕竟有些人是有水平但讲不出来,我也不知道这位讲师是否属于这种。好了,不管怎样,也还是感谢这位老师四天的唠唠叨叨,起码也让我对设计模式了解的更多了,也算是带着我们浏览了一遍,然后就是'师父领进门,修行在个人'了。

工厂模式三剑客:
在Gang Of Four – GOF的'Design Pattern'一书中其实就只有'Abstract Factory'和'Factory Method'这两种创建型模式,后来逐渐加入了一种简化的简单工厂模式:Simple Factory Pattern,这三种模式我称之为'三剑客',用于在对象创建上发挥光和热。我想之所以有Simple Factory Pattern的存在一是出于从理解Factory模式的需要,二是在现实系统中有很多所谓'Simple Factory Pattern'的设计存在于各个系统中,用'Simple Factory Pattern'来对应这些现有的设计,便于接受向其他两种更复杂的Factory模式的过渡,毕竟简单工厂模式缺点多多。

说工厂模式还是要从'创建对象'说起,在现行的大多数面向对象语言中,如C++、Java等,我们可以遵循如下操作凡是来创建一个类的实例:

//关系图
Client — (invoke)—> Class ConcreteProduct1

//client code
ConcreteProduct1 *p = new ConcreteProduct1();

'Head First Design Pattern'一书告诉我们:when you see 'new', think 'concrete'。new operator给我们的代码加上了一副枷锁,把我们桎梏于其中,动弹不得,想想看如何产品换成了ConcreteProduct2,我们该如何做,Client就要修改了,挨批的总是我们。我们需要更加容易扩展的代码。试试'Simple Factory Pattern'吧,让Factory来produce出我们需要的Product,前提:client可能需要生产出多种ConcreteProducts呀。这个应该没问题,来看看'简单工厂模式'吧。

//如关系图1 ConcreteProduct(s) <=> ConcreteProduct1、ConcreteProduct2、ConcreteProduct3、….、ConcreteProductn
Client –(invoke)–> class ConcreteFactory ——> class ConcreteProduct(s) [derived from class AbstractProduct]

class ConcreteProduct1 : public AbstractProduct { … };
class ConcreteProduct2 : public AbstractProduct { … };
… …

class ConcreteFactory {
 public:
  static Product* produce(int type) {
   switch (type) {
    case 1:
     return new ConcreteProduct1();
     break;
    case 2:
     return new ConcreteProduct2();
     break;
    … …
    case n:
     return new ConcreteProductn();
     break;
    … …
   }

  }
};

//Client code
AbstractProduct *p = ConcreteFactory::produce(real_type);

从上面的关系图或代码可以了解到这里的ConcreteFactory真是责任不小啊,从Product1到Productn样样要生产啊。暗想:是不是有些负担太重了?
1) 如果要是有n(n>100)种产品要生产,那switch code block势必会很大,这样也相当的影响代码的美观程度了,一般此时Bad Smell都会被闻到。
2) 如果新增一个产品的生产,Factory的produce逻辑势必要修改。

不仅我们意识到了这些,GOF们也意识到了,他们总结出来'Factory Method'模式来解决这一问题。Factory Method将拆分Simple Factory中Factory实现中的沉重且复杂逻辑,让其职责更加单一。

//如关系图2  Product(s)Factory <=>  Product1Factory、 Product2Factory、 Product3Factory、….、ProductnFactory
Client –(invoke) –> class Product(s)Factory [derived from class AbstractFactory] ——-> class ConcreteProduct(s) [derived from class AbstractProduct] 

class ConcreteProduct1 : public AbstractProduct { … };
class ConcreteProduct2 : public AbstractProduct { … };
… …

class AbstractFactory {
 public:
  virtual AbstractProduct* produce() = 0;
};

class Product1Factory : public AbstractFactory {
 public:
  AbstractProduct* produce() {
   return new ConcreteProduct1();
  }
};

class Product2Factory : public AbstractFactory {
 public:
  AbstractProduct* produce() {
   return new ConcreteProduct2();
  }
};
… …

//Client Code
void Assembly(AbstractFactory *af) {
 AbstractProduct *p = af->produce();
 … …
}

这样当我们新增一个ConcreteProduct的生产时完全不需要修改Factory的代码以及Client端的实现,增加一个新的ConcreteFactory来生产这种新的ConcreteProduct即可。

从上面的Factory Method模式关系可以看到,所有的ConcreteProduct产品均继承自一个抽象类Product,我们可以理解为这些ConcreteProduct属于一个系列的产品;而我们的AbstractFactory也是只生产这一个系列产品的Factory。但是如果现在要求生产另一个系列AnotherProduct的产品时,我们的Factory Method就暂不支持了,需要进行调整了。而调整后的支持多系列产品的模式我们就称之为'Abstract Factory'模式,即抽象工厂模式。

//如关系图3
class SeriesProduct(s)Factory [derived from class AbstractSeriesFactory] ——-> class ConcreteProduct(s) [derived from class AbstractProduct]
class SeriesProduct(s)Factory [derived from class AbstractSeriesFactory] ——-> class ConcreteAnotherProduct(s) [derived from class AbstractAnotherProduct]

class ConcreteProduct1 : public AbstractProduct { … };
class ConcreteProduct2 : public AbstractProduct { … };
class ConcreteAnotherProduct1 : public AbstractAnotherProduct { … };
class ConcreteAnotherProduct2 : public AbstractAnotherProduct { … };
… …

class AbstractSeriesFactory {
 public:
  virtual AbstractProduct* produce() = 0;
  virtual AbstractAnotherProduct* produce() = 0;
};

class SeriesProduct1Factory : public AbstractFactory {
 public:
  AbstractProduct* produceSeries1() {
   return new ConcreteProduct1();
  }

  AbstractAnotherProduct* produceSeries2() {
   return new ConcreteAnotherProduct1();
  }

};

class SeriesProduct2Factory : public AbstractFactory {
 public:
  AbstractProduct* produceSeries1() {
   return new ConcreteProduct2();
  }

  AbstractAnotherProduct* produceSeries2() {
   return new ConcreteAnotherProduct2();
  }
};
… …

>//Client code
void Assembly(AbstractSeriesFactory *asf) {
 AbstractProduct *p1 = asf->produceSeries1();
 AbstractAnotherProduct *p2 = asf->produceSeries2();
 … …
}

从上面可以看出Abstract Factory模式其实是以Factory Method模式做基础的。Abstract Factory模式已经是工厂类模式的全景了,但是同样它也是有其缺陷的,比如我们如果新增一个产品系列,这样的修改就是伤筋动骨的了,首当其冲的就是AbstractFactory需要增加一个接口,而随之而来的是继承该接口的子类也都要实现该接口,这里可以考虑给每个AbstractFactory声明的接口一个'空实现',这样即使增加接口了也不会影响到已继承该AbstractFactory的子类,如果这些子类不负责生产新增系列产品的话。

附工厂模式关系图

© 2007, bigwhite. 版权所有.

Related posts:

  1. Effective Java阅读笔记-item1
  2. C++咬文嚼字-'Evil cast'
  3. Effective Java阅读笔记-item18
  4. Effective Java阅读笔记-item16
  5. 学习重构