16.1 麦当劳的鸡腿
时间:1月1日 地点:麦当劳 人物:大B和他的女朋友
这天大B和女朋友去麦当劳吃东西。
大B:“今天你想想去哪玩哩?”
大B的女朋友:“我们好久没去吃汉堡和鸡腿了。”
大B:“是喔!确实好久没吃过了。你想去麦当劳还是肯德基呢?”
大B的女朋友:“都好啦!”
大B:“那我们就去麦当劳吧!”
大B的女朋友:“嗯。好。”
大B:“走吧!”
来到麦当劳。
大B的女朋友:“我要吃鸡腿。”
大B:“好,和服务员说。”
大B的女朋友:“就和你说嘛!”
大B:“为什么。和服务员说:我要鸡腿,肯定不会给你拿来烤羊腿。”
大B的女朋友:“讨厌!哪有人这样的。”
16.2 抽象工厂模式
时间:1月1日 地点:大B房间 人物:大B,小A
大B:“我们可以认为麦当劳和肯德基就是生产食物的工厂,那么理所当然,汉堡和鸡腿是他们共同生产的两种食物,不管你去MDL还是KDJ,说:我要鸡腿,那肯定不会给你拿来烤羊腿。嘿嘿 。这里,我们假定麦当劳和肯德基只生产这两种产品。我们是消费者,我们就是客户,就是产品的消费者,就是程序中对象的调用者。而麦当劳和肯德基,理所当然的,他们就是工厂,一个叫做麦当劳工厂,一个叫做肯德基工厂,他们是真正的生产者,而对于我们这些客户消费者(程序中对象的调用者)来说,不管是去麦当劳还是肯德基,我们都说一样的话(我们的要求是稳定的):我要鸡腿。只要我们提出这个请求,那么肯定会得到我们想要的。而作为工厂(生产者),麦当劳和肯德基都生产鸡腿和汉堡,所以抽象出来的抽象工厂都具有生产鸡腿和生产汉堡的功能,这是接口中的两个方法。因为在这个接口中,还不知道到底要生产谁家的产品,所以只能返回个抽象的鸡腿或汉堡,等到麦当劳或者肯德基工厂生产出来,就知道是谁家的了。(有标志嘛,哈哈,这就是动态创建对象)。管是麦当劳还是肯德基的鸡腿或汉堡,它的本质都是鸡腿或汉堡,所以可以抽象出来。那么鸡腿就派生出麦当劳的鸡腿和肯德基的鸡腿,而汉堡就派生出麦当劳的汉堡和肯德基的汉堡。而对于我们这些客户消费者(程序中对象的调用者)来说,不管是去麦当劳还使肯德基,我们都说一样的话(我们的要求是稳定的):我要鸡腿。只要我们提出这个要求,那么肯定会得到我们想要的。不管是谁家的鸡腿,肯定是鸡腿不会是羊腿。所以,我们只要规定好是鸡腿(接口)就行了,而让工厂去绝对具体的制作过程。我们只伸手接过来一个鸡腿,狠狠的咬一口,恩,真香~:)
到现在为止,我们只和鸡腿(抽象的接口)还有抽象工厂(因为我们不管是麦当劳还是肯德基,我们只要鸡腿)打交道。你现在知不知道什么是抽象工厂模式?”
小A:“抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或Toolkit)模式。”
http://luchar.javaeye.com/blog/179617
如图图16-1 标准抽象工厂模式所示
图16-1 标准抽象工厂模式
大B:“从模式定义中知道这个模式的意图内容为: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。工厂类层次的通信接口只有抽象工厂和创建产品族的各个工厂方法,这些工厂方法不带任何参数,并且返回具有抽象产品类型的具体产品实例。这些使得客户端可以不依赖具体产品的类,从而体现了模式的意图。意图中的‘而无需指定它们具体的类’可以理解为客户端在使用和创建具体产品时不给出具体产品的任何暗示。”
小A:“师兄,抽象工厂模式有什么动机啊?”
大B:“考虑一个支持多种视感( l o o k - a n d - f e e l)标准的用户界面工具包,例如M o t i f和Presentation Manager。不同的视感风格为诸如滚动条、窗口和按钮等用户界面‘窗口组件’定义不同的外观和行为。为保证视感风格标准间的可移植性,一个应用不应该为一个特定的视感外观硬编码它的窗口组件。在整个应用中实例化特定视感风格的窗口组件类将使得以后很难改变视感风格。”
16.3 抽象工厂模式的角色
小A:“抽象工厂模式涉及到哪些角色?”
大B:“抽象工厂模式设计到以下的角色:
抽象工厂角色:担任这个角色的是工厂方法模式的核心,它是与应用系统的商业逻辑无关的。通常使用接口或抽象类实现。
具体工厂角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。通常使用具体的类实现。
抽象产品角色:担任这个角色的类是抽象工厂方法模式所创建的对象的父类,或它们共同拥有的接口。通常使用接口或抽象类实现这一角色。
具体产品角色:抽象工厂模式所创建的任何产品对象都是某一具体产品类的实例。这是客户端最终需要的东西。通常使用具体类实现这个角色。”
16.4 抽象工厂模式的使用
小A:“师兄,什么情况下使用抽象工厂模式?”
大B:“一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。”
16.5 抽象工厂模式的适用
小A:“抽象工厂模式的适用于哪些地方?”
大B:“一个系统要独立于它的产品的创建、组合和表示时。一个系统要由多个产品系列中的一个来配置时。当你要强调一系列相关的产品对象的设计以便进行联合使用时。当你提供一个产品类库,而只想显示它们的接口而不是实现时。”
小A:“能不能举些示例啊?”
大B:“有三种抽象的产品:墙、门、房间。对这三种抽象产品有两组具体实现:卧室和起居室。那么,我们的抽象工厂就可以根据客户的指令(即调用参数)去生产卧室和起居室的房间(墙和门包括在房间里)。”
16.6 抽象工厂模式的优点和缺点
大B:“你知道抽象工厂模式有什么优点吗?”
小A:“1、产品从客户代码中被分离出来。2、容易改变产品的系列。3、将一个系列的产品族统一到一起创建。”
大B:“它的缺点你知道吗?”
小A:“在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口。”
16.7 抽象工厂模式是为了解决什么问题的呢?给了我们怎样的设计思路?
小A:“创建型模式抽象了对象实例化的过程,它帮助系统不依赖于对象如何创建,如何实现,何时创建。个类创建型模式使用继承使对象创建多样化,一个对象创建模式将对象的创建代理到其他类。那抽象工厂模式是为了解决什么问题的呢?给了我们怎样的设计思路?”(www.xing528.com)
大B:“软件开发中我们经常会碰到一系列相关的对象需要创建,如果按照常规做法我们就要为不同的对象创建编写不同的代码,复用性和可维护性都降低了。而且这些相关对象创建的方式也许不同,那么客户代码创建的时候就要针对不同的对象编码,对象创建的方式还是一个容易改变的地方。基于这样的情况提出了抽象工厂模式,抽象工厂模式为创建一系列相关对象提供了统一的接口,客户只要调用这个接口即可,封装了变化,隔离了变化,让客户代码稳定起来。比如这样一个情况,我们做了一个桌面软件,这个软件的界面是可以改变的,它有几种风格:XP风格、Win2000风格、苹果机风格。这个软件就是显示一个窗口,窗口有标题栏、滚动条,XP风格的界面有它自己的标题栏和滚动条,而苹果机风格的又不一样。”
小A:“我们常常怎么做?”
小A:“这样做有什么坏处呢?”
大B:“这个例子太小实际上没有什么坏处,这样写可以。但是人总会出错,你看看下面这个。”
大B:“你的界面将是Win2000的标题栏,XP风格的滚动条,这就造成了不一致性抽象工厂就是为了解决这种一系列相关对象创建工作的。如图16-2抽象工厂的类图”
图16-2 抽象工厂的类图
大B:“在上面这个例子中标题栏和滚动条都是我们的产品,我们还应该写一个WindowManager类,专门来管理这些产品的创建的,而我们的WinXP团队、Win2000团队、苹果机团队实现这个WindowManager,WinXP团队只会制造出XP风格的产品。”
16.8 “工厂模式”与“抽象工厂模式”的区别
小A:“‘工厂模式’与‘抽象工厂模式’有什么区别?”
大B:“在了解他们的区别之间有必须对两个概念做进一步的认识,那就是“产品族”和“产品等级”他们很容易区别在模式设计到底用那种工厂方法。”
小A:“什么是产品族呢?”
大B:“产品等级:简单的说就是不同类的产品就叫不同的产品族,比如电脑,苹果,桌子……等就是一个产品族。他们的物理特性和外型都不相同。”
小A:“什么又是产品等级呢?”
大B:“产品族:就是同一种东西的不同类型。例如,PC有联想的,IBM,方正……的等等,这些对象就构成一个产品等级。而抽象工厂模式解决的就是如果产生不同等级,不同产品族的产品(对象)结构模仿一个果园,假设果园应该能够出产水果,蔬菜,这时水果和蔬菜就是不同的东西,也即使是前面所说的产品等级;水果和蔬菜分别会有北方的,还会有塑料大棚里面生产的热带水果,蔬菜,这时的分类就是产品等级。而这样的结构就可以用文中提到的抽象工厂模式!”
16.9 奥迪audi车
大B:“你喜欢奥迪audi车吗?”
小A:“嘿嘿!喜欢。”
大B:“我就举个奥迪audi车的例子,让你更好地理解抽象工厂模式。”
小A:“好啊!”
大B:“介绍了工厂方法的使用,从那个程序中可以看到,奥迪audi车是从audi_car_factory_imple工厂中创建出来的,而大众3W车是从threeW_car_factory_imple工厂中创建出来的,那么如果这2家汽车生产大厂由总部在北京市,现在发展到上海,深圳等城市创建生气汽车的分厂,该怎么办?是不是得将原来的奥迪汽车工厂类。”
改成类似如下的模样:
小A:“发现一个问题,不同地域的汽车却在一个工厂中出现。”
大B:“这是不合乎常理的,因为北京奥迪在北京分厂创建,上海奥迪在上海分厂创建,这样才对。所以如果遇到分‘大系’来创建对象的时候,抽象工厂方法是肯定要使用的时候了。”
小A:“什么是‘大系’?”
大B:“这里的大系指的就是从地域上来分。这个例子就应该以‘用抽象工厂来定义具体工厂的抽象,而由具体工厂来创建对象’。比如在玩“极品飞车”这款游戏,每个地图处都有造车的工厂,每个造车的工厂都因为有造车的档次不同而划分为高级车厂,低级车厂,那么这样的场景正是应用抽象工厂的好时机,再来理解一下这句话“用抽象工厂来定义具体工厂的抽象,而由具体工厂来创建对象”,用抽象造车工厂来定义具体造车工厂的抽象,而由具体的造车工厂来创建汽车,这就是抽象工厂与工厂方法的不同,工厂方法中对象的创建是由工厂方法来确定的,创建的对象都是不分类并且实现一个接口的,而抽象工厂就是在工厂方法的基础上对创建车的对象的行为进行分类,比如北京车厂,上海车厂等。”
【抽象工厂模式解释】
类型:创建模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
【抽象工厂模式-Java代码实现】
新建抽象工厂接口:
新建抽象工厂接口的高级车adv工厂实现类:
新建抽象工厂接口的普通车low工厂实现类:
上面已经有抽象工厂和具体工厂的实现类了。
新建汽车接口:
新建汽车父类:
新建大众高级车:
新建大众普通车:
新建大众普通车:
新建奥迪普通车:
新建客户端运行类:
程序运行结果如下:
富华版:大众A6 车以专利技术起动了 最高速度为:300
富华版:大众A6 车以专利技术停车了
抓一篇阎宏的小文字:
一开始只在后花园中种蔬菜类的时候可以用简单工厂模式,由工厂负责生成具体的蔬菜类,
但是如果后花园要引进水果类的时候简单模式就行不通了,因此需要使用工厂方法模式,将产品类族分开。
但是如果后花园的规模继续扩大到地域范围的分割时,比如说一个在北京,一个在上海的时候,工厂方法模式就不够了,因为对两个后花园来说,每个后花园的植物是要被种在一起的,并且两个后花园用工厂方法模式是无法体现其区别的
从程序中可以看到,工厂是抽象的,工厂的实现是不样的,不同的工厂创建出不同汽车。而工厂方法仅仅是用一个工厂去创建很多汽车。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。