标签 Java 下的文章

工厂模式三剑客

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

附工厂模式关系图

重操旧业

2005年7月8日是我入司一周年纪念日,本想写篇Blog纪念一下,可是思维的小溪总是难以汇聚成大江大河,始终觉得无话可说,再加之最近的项目十分紧迫,So我放弃了。这周末公司去海边旅游放松,带着一身的疲惫回来后,坐在电脑前,突然觉得该写些东西了

纵然C语言是我通往软件开发世界的领路人,但曾经(大二)一度认为C已经是明日黄花,之后便不再认真钻研之。入司被分到C组,平时开发的方式和大部分刚入司的新员工一样"照猫画虎",事实证明这是最快捷的上手途径,这也并没有错。错就错在我对C的消极态度。代码写完了就写完了,几乎从来不去重构、优化,现在看来那些代码真是有些“不堪入目”,也许这个词包含些夸张成分^_^。由于长时间缺乏对C的钻研,我有时居然犯一些及其低级的错误。直到最近的这个项目我逐渐清醒了一些,在和leader的平时交流中他也一针见血的指出我的不足之处之一就是“杂而不专”,虽说一定的知识面是很重要的,但是作为作技术的,不能在一个方向上“露头”,又怎能让领导重视你呢,你的价值又体现在哪呢?“大家不可能因为某个人能学,就认可他”这是另一句触动我很深的话。曾经有段时间想过转移到Java方向,自己也在Java上面投入了大量的时间,阅读了大量的材料和书籍(我的时间没有浪费,只是没放在行上,就暂且将C定位本行吧^_^)。但由于多种原因没能走向Java,这个结果对于我来说意味着什么呢,我不能不承认我学到了很多东西,但失去的也同样很多,比如在本行“露头”的机会。最近的项目让我感到自己在C上的欠缺,不得不加班加点恶补。

相信很多公司的员工手册或文化手册中都有这么一点:“追求个人与公司的共同发展”,那么“重操旧业”就算是我“响应号召”的一个起点吧!

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! 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