标签 程序员 下的文章

工厂模式三剑客

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

附工厂模式关系图

Unix体验中心开张

晚上收到一封mail,来自ecommunity@gceclub.com,mail中提到Unix体验中心开始提供免费服务了。Mail中写道:'Unix体验中心(Unix-Center.Net)的目标是为研究、学习和使用各种版本的Unix和类Unix操作系统的教师、学生和工程技术人员提供一个体验和测试各种版本的Unix和类Unix系统的软硬件平台。该平台能够为所有注册用户免费提供如下服务:SSH登录以及各种语言开发开发工具'。虽说有Sun宣传产品之嫌,不过这样的一个平台还是可以让很多人体验到伟大的Unix的,现在的学生可是真幸福呀。

要想体验Unix环境,首先需要注册一下,很简单的注册流程。然后就是按照其'常见问题解答'中的方法一步一步登陆到其服务器上。由于采用SSH2登陆,需要下载一个putty工具,我下载了一个绿色的putty包,免安装,直接可用。解包后里面有好多个putty系列工具,启动'putty'即可。在主机名称中输入IP地址(公众网:x4100.unix-center.net;教育网:x4100-edu.unix-center.net),然后点击'打开',你就会看到登陆窗口,你输入你注册时的user和passwd即可成功登陆。环境默认采用Bash Shell。里面有vim, emacs等编辑器,还有C,C++,Java等语言的编译器,供实验使用。大家不妨去试试。

还有一点要注意的是:既然人家给提供这样的免费服务,大家就不要在上面太乱来。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系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