stand on the shoulders of giants

【设计模式】之 Factory Method 模式

引子

程序架构应该尽可能保证主模块和各个子模块、高层模块和底层模块为松耦合的关系。底层模块和主模块以接口的方式联接起来。
现在有一个汽车测试程序架构:

汽车测试架构

可以看出发生了new的紧耦合关系。所以我们想到这样改造:
AbstractCar car1 = new Volvo();
右边还是紧耦合的关系,再次改造:
public void BuildTestFramework(AbstractCar car1, AbstractCar car2);
主程序:
test.BuildTestFramework(Volvo, Ford);
好像看起来蛮不错,平时我们也是尽量这样做的,写多个BuildTestFramwork函数实现重载。可是系统的扩展性并不好。如果我的context需要加一种新的车,就要改底层的buildtestframwork?
注意:我们要尽量做到扩展,而不是更改。
看看工厂方法模式怎么做:

工厂方法模式实现
如果需要测试新车Toyota,只需要

增加Toyota, ToyotaFactory
主程序增加:test.BuildTestContext(new ToyotaFactory());

结构图


和Abstract Factory来对比,工厂方法模式的图是这样的:

可以看出,工厂方法模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。
工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。

动机

在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?

意图

定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

工厂方法模式实例

Factory method offering flexibility in creating different documents.
The derived Document classes Report and Resume instantiate extended versions of the Document class.
Here, the Factory Method is called in the constructor of the Document base class

Factory Method pattern -- Real World example

Output

Resume -------
 SkillsPage
 EducationPage
 ExperiencePage

Report -------
 IntroductionPage
 ResultsPage
 ConclusionPage
 SummaryPage
 BibliographyPage

工厂模式在组件开发中(吕震宇)

1)由系统架构师设计好抽象产品和抽象工厂。
2.1)多组并行开发具体产品和具体工厂。
2.2)与此同时另外一组使用依赖注入技术开发主程序。在1的工作完成后2.1与2.2是可以并行的。
按上面方案很可能产生3个Assembly。最后通过配置文件完成组装。

从重构来理解Log实例

这个例子在wayfarer的封装变化和TerryLee的工厂方法模式里都提到过。我觉得是重构的一个很典型,并且易于理解的例子。我也放在这里说一下吧。

在程序中我们经常要对发生的异常错误或者关键操作进行日志记录。最简单的日志记录是这样的:

first log class

 

存在的问题很明显,紧耦合,难以扩展。为了扩展为XmlLog, TxtLog,很容易想到的是接口。
第一次重构:

 

接口形式

这样的实现,给扩展性带来了一些好处,如果要扩展Log2DBFile, 只需要增加一个实现ILog的子类。
但是如果要换一种日志记录方式,把程序原来写好的部分,例如上面的Log2XmlFile改为Log2DBFile呢?就不是很方便了。

第二次重构:

注意:下面的应该是虚线箭头,表示依赖关系

LogFactroy类

 

Log代码下载





 

posted @ 2008-11-18 14:40  DylanWind  阅读(376)  评论(0编辑  收藏  举报