您的位置:首页 > 编程语言 > Java开发

java与模式笔记(6.1) 缤纷的模式世界之辛勤的园丁——工厂模式——果园的故事。

2007-07-03 19:00 423 查看
辛勤的园丁——工厂模式
工厂模式对于我来说,我宁愿叫他辛勤的园丁。他辛辛苦苦的为客户程序模块创建完整的产品,而不需要客户亲自去处理每一个具体产品,而且客户没有必要知道具体的产品,只需要知道一个抽象的产品就可以了。把所有创建的实现封装起来,实现了开闭原则,或者说他实现了迪米特法则和依赖倒转原则,原因有2,第一个是他使得客户只跟他一个人交流,不用理会具体的产品,只知道抽象产品,第二个是,即使推出了新产品,客户是可以不用修改接口的。
现在我们来看看3个工厂模式,简单工厂模式、工厂方法模式、抽象工厂模式。
对模式的简单概括:
l 简单工厂模式:使用条件转移逻辑通过static方法对客户的请求进行创建或者返回已经创建的产品。
l 工厂方法模式:使用多态替换简单工厂模式的条件转移,并且使客户参与多态处理工厂的创建。
l 抽象工厂模式:拓展了工厂模式的应用范围,使得结构相同的不同系列的产品(产品族)能够使用同一个抽象工厂来处理。
想了好久,一直不知道以什么形式把这3个模式描述。索性按照横向比较的方式来描述。
之前说过了工厂模式的意义,现在举例描述,有2个经典的比喻。一个就是果园的故事,一个是女娲的故事。我们一个一个来说。

果园的故事
有各种水果,是果园的产品。比如苹果,橘子,葡萄。
一个客户需要这些水果。但是亲自去摘,还需要知道每个水果的具体位置,道路比较多的情况,怎么走最省力,最后得到水果等等事情,这是假设水果自己能播种省长程树并结实,否则更麻烦。然而作为一个客户,是不需要这些事情的,因为他是消费水果的,而不是盛产水果的这个角色。这违背接口隔离原则。这时候需要一个我们园丁,也就是我们工厂模式的主角:辛勤的园丁。下面有请我们的主角出场。

简单工厂模式中原定要干的事情比较有条理,他自己做个笔记,记录着如果客户要苹果,那么给的是苹果,如果要的是葡萄,他不会给橘子或者别的。当然如果客户要的是小麦,他会说处理客户的这个要求,并且告诉他,“ hmmm…这不是我的业务范围,你别给我找茬。”也就是他会抛出异常。类似的结构如下:



这个园丁就一个人,要做的事情很多,一个是记录自己有什么产品都叫什么名字,一个是客户要求的时候,去查自己的菜单,客户要什么就给什么,hmmm…满累的说。
在没有园丁的时候客户如果想要一个苹果,他必须实现以下代码:
try
{
Fruit appble = new Appble();
}
有了园丁,客户可以直接叫园丁去做:
try
{
Fruit appble = FruitGardener.Factory(“appble”);
}
这样,客户不再依赖具体的类而是依赖抽象类,而且回避了创建过程,因为创建过程中,可能发生很复杂的事情。

实现的接口重要的代码是:
public static Fruit factory(String msg) throw BadFruitException
{
if(msg.equalsIgnoreCase(“apple”)){
return new Apple();
}else{
throw new BadFruitException(“You ordered a bad name of Fruit”)
}
}

工厂方法模式说完了,简单工厂,我们来看看工厂方法。简单工厂模式,部分实现了开闭原则,在遇到产品种类添加的情况的时候,园丁就不得不修改自己的菜单,使得客户的要求可以对应到新的具体产品,比如新引进了一种鸭梨。这个违反了依赖倒转原则,新的产品的产生是继承抽象产品的,但是他的产生却影响了园丁程序,必须修改才可以。于是我们想到,可以把园丁也抽象出来,变成抽象园丁,这样,就可以雇佣多个园丁来处理新产品的添加和使用。这就是工厂方法产生的原因。他的结构必须跟产品的结构一致:



这就相当于,园丁他不再是一个人,这么个原定组织,他们提供向客户提供水果产品的服务,就在这个时候,每一个园丁负责一种具体水果产品,没什么好多说的,直接看类图:



于是就有了客户调用工厂生产产品的代码:
try
{
Creator creator1 = new Creator1();
Creator creator2 = new Creator2();
Product prod1 = creator1.factory();
Product prod2 = creator2.factory();

}

这样做的好处是使得程序的条件转移逻辑变成了多态来实现,从而符合了依赖倒转原则,弥补了简单工厂模式的对于开闭原则的不足。至于为什么是用跟产品的同结构来创建工厂,我觉得应该这样考虑,首先我们的个体单元需要的是复用面对同样是苹果,架设苹果又分为富士苹果和果光苹果2个产品,这时候我们的确可以把苹果的这2个品种对于工厂我们建立跟葡萄一样的园丁等级的园丁。但是,面临的是程序复用出现了问题,这里就不是工厂模式要考虑的了,而是我设计的这个工厂是否符合那5大原则。先说产品,单纯的苹果是有等级的:抽象苹果和具体的苹果。假设管理苹果的园丁收割苹果的方法都是一样的从树上摘的话,那么他们拥有一段一模一样的种植的代码。作为维护来说,这段代码是假定所有苹果的采摘都是一样的方法,不包含不同苹果不一样的说法,维护的时候,一旦方法需要改变,那么就需要改变所有的具体的苹果园丁的实例类。于是,可以认定,如果按照假设的来设计,它必须考虑复用的问题。一旦苹果产品多了,那么复用势在必行,一旦考虑复用,无非就是聚合和继承(目前只考虑面向对象的复用,不包括过程中的共通函数),然而明显是is a的关系,所以要继承,hmmm...我也没有看过为什么工厂要保持跟产品一样的结构,但是我觉得我的推理很正确的说。

抽象工厂模式。这个模式是对工厂方法模式的抽象推广。也就是说,产品根产品之间可以没有必然的联系,只要他们的结构一致,就可以通过相同的一个结构的工厂来创建具体产品实例。这是又引进一个叫产品族的概念。相同结构下的多个抽象产品所带领的它们的子孙们各自形成一个体系。然而如果他们的继承结构都是一模一样的,而且所有继承下来的抽象类的具体子类都具有相同的数目。那么我们就可以引出产品族这一说法了。所谓产品族就是在各个体系中的相同继承位置的具体类所组成的一个分类。比如下边的这个图片描述的就是一个产品族。



我们可以创造出一个同样结构的工厂,来统一创建这些没有表面上没有关系的产品。



然而,这又相当于我们的果园故事中的什么事情发生了呢?果园搞了一个热带大棚技术,分别种植热带水果和蔬菜,还有亚热带水果和蔬菜,然而水果和蔬菜不是一个产品体系,各有各自的结构,面对不同的客户人群——喜热带水果蔬菜的,喜亚热带的。hmmm...抽象园丁就开始想了,我该节省人力资源阿,一个人管理一个种类的具体产品类有点屈才了,也浪费了已经设计好的这么一个管理结构,何不让一个人及负责一块自己熟悉的热带或者亚热带的水果的同时,也去熟悉同是热带或者亚热带的蔬菜呢?hmmm...于是,每个具体的员工类就有了自己的新的责任,要负责同是一块热带或者亚热带的蔬菜,hmmm...其实并不辛苦的说。因为他们各自的父类都已经把一些共同的大家需要的知识和方法一起定义好了,这样,就不用从新请另外一个工厂来处理了,何况已经设计好的工厂结构与新的热带和亚热带的分组的结构相同。这就是的,事情迎刃而解了。来看看结构图:



有了工厂方法模式,我想,代码就不要累赘了吧。hmmm...我很懒的说。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: