2007年五月月 发布的文章

工厂模式三剑客

前不久参加了一个为期四天的设计模式培训,公司以前组织过很多次设计模式培训,主题多为'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的子类,如果这些子类不负责生产新增系列产品的话。

附工厂模式关系图

国足输泰国,我不意外

于前两天就得知今天有两场国字号比赛,分别是国奥对乌拉圭以及国足对泰国,其实我是更想看国奥的比赛,毕竟这批国奥踢球时间还不长,深受国内联赛毒害还尚浅。但是由于这场比赛在下午4点开始,正处在上班时间,也就作罢了。相比于这一场晚上7点半开始的国足比赛是在是没有什么看点吸引我。国足赢了属于合情合理,国足输了,如果国足输了这场球你愿意看吗,呵呵,而且这么让人窝囊的输球,相信也真的没有人愿意看,看了也后悔。

没看国足的球,自己抽空看了最近上映的一部片子'龙骑士',剧情虽有些老套,但是影片制作尚可,如果票价为20元时还是可以在周二到影院去看看的,周二半价^_^。遗憾的是片子仍未完,估计如果票房尚可的话,来个'龙骑士2'实属情理之中。

好了,不谈'龙骑士'了,看完片之后,打开新浪体育,红色大标题映入眼帘,国足0:1负于泰国虎,旁边一个'评论'的链接我都不愿意点进去看了,除了骂,我相信球迷们应该不会有其他语言了。再看国足表现,如果是运气不佳也就罢了,结果技术统计一出炉,把我也下了一跳:射门6:13,射正1:3,角球3:9,攻入前场30米区域9:14。我想随意换一支中甲球队也未必如此呀,起码人家还懂得一个男人该如何去做呀。唉,如果不想进国家队,就直说,自己不行,还像个牌位似的占着地方,进了国家队还不好好珍惜机会,不好好踢。我想国内很多中超中甲的年轻球员在那苦苦等待这样的锻炼机会呢。另外朱指导是不是也累了,累了就休息休息,再渡渡金,然后从头再来吗,人家70多岁还做主教练参加世界杯呢,机会还有多是。

真是不知道该说些什么了,唉,反正没什么感到意外的,我想在目前这支朱家军身上什么都有可能发生。不看不知道,朱家军真奇妙啊!

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats