23种模式的比喻启发

创建型模式
       
        1、FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory
       
        工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。
       
        2、BUILDER—MM最爱听的就是“我爱你”这句话了,见到不同地方的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM我只要按对应的键,它就能够用相应的语言说出“我爱你”这句话了,国外的MM也可以轻松搞掂,这就是我的“我爱你”builder。(这一定比美军在伊拉克用的翻译机好卖)
       
        建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。
       
        3、FACTORY METHOD—请MM去麦当劳吃汉堡,不同的MM有不同的口味,要每个都记住是一件烦人的事情,我一般采用Factory Method模式,带着MM到服务员那儿,说“要一个汉堡”,具体要什么样的汉堡呢,让MM直接跟服务员说就行了。
       
        工厂方法模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
       
        4、PROTOTYPE—跟MM用QQ聊天,一定要说些深情的话语了,我搜集了好多肉麻的情话,需要时只要copy出来放到QQ里面就行了,这就是我的情话prototype了。(100块钱一份,你要不要)
       
        原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。
       
        5、SINGLETON—俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Sigleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)
       
        单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。
       
        结构型模式
       
        6、ADAPTER—在朋友聚会上碰到了一个美女Sarah,从香港来的,可我不会说粤语,她不会说普通话,只好求助于我的朋友kent了,他作为我和Sarah之间的Adapter,让我和Sarah可以相互交谈了(也不知道他会不会耍我)
       
        适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
       
        7、BRIDGE—早上碰到MM,要说早上好,晚上碰到MM,要说晚上好;碰到MM穿了件新衣服,要说你的衣服好漂亮哦,碰到MM新做的发型,要说你的头发好漂亮哦。不要问我“早上碰到MM新做了个发型怎么说”这种问题,自己用BRIDGE组合一下不就行了
       
        桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。
       
        8、COMPOSITE—Mary今天过生日。“我过生日,你要送我一件礼物。”“嗯,好吧,去商店,你自己挑。”“这件T恤挺漂亮,买,这条裙子好看,买,这个包也不错,买。”“喂,买了三件了呀,我只答应送一件礼物的哦。”“什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻烦你包起来。”“……”,MM都会用Composite模式了,你会了没有?
       
        合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。
       
        9、DECORATOR—Mary过完轮到Sarly过生日,还是不要叫她自己挑了,不然这个月伙食费肯定玩完,拿出我去年在华山顶上照的照片,在背面写上“最好的的礼物,就是爱你的Fita”,再到街上礼品店买了个像框(卖礼品的MM也很漂亮哦),再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来……,我们都是Decorator,最终都在修饰我这个人呀,怎么样,看懂了吗?
       
        装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。
       
        10、FACADE—我有一个专业的Nikon相机,我就喜欢自己手动调光圈、快门,这样照出来的照片才专业,但MM可不懂这些,教了半天也不会。幸好相机有Facade设计模式,把相机调整到自动档,只要对准目标按快门就行了,一切由相机自动调整,这样MM也可以用这个相机给我拍张照片了。
       
        门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。
       
        11、FLYWEIGHT—每天跟MM发短信,手指都累死了,最近买了个新手机,可以把一些常用的句子存在手机里,要用的时候,直接拿出来,在前面加上MM的名字就可以发送了,再不用一个字一个字敲了。共享的句子就是Flyweight,MM的名字就是提取出来的外部特征,根据上下文情况使用。
       
        享元模式:FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。
       
        12、PROXY—跟MM在网上聊天,一开头总是“hi,你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这些话,真烦人,写个程序做为我的Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。
       
        代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
       
        行为模式
       
        13、CHAIN OF RESPONSIBLEITY—晚上去上英语课,为了好开溜坐到了最后一排,哇,前面坐了好几个漂亮的MM哎,找张纸条,写上“Hi,可以做我的女朋友吗?如果不愿意请向前传”,纸条就一个接一个的传上去了,糟糕,传到第一排的MM把纸条传给老师了,听说是个老处女呀,快跑!
       
        责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接
       
        起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。
       
        14、COMMAND—俺有一个MM家里管得特别严,没法见面,只好借助于她弟弟在我们俩之间传送信息,她对我有什么指示,就写一张纸条让她弟弟带给我。这不,她弟弟又传送过来一个COMMAND,为了感谢他,我请他吃了碗杂酱面,哪知道他说:“我同时给我姐姐三个男朋友送COMMAND,就数你最小气,才请我吃面。”,:-(
       
        命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。
       
        15、INTERPRETER—俺有一个《泡MM真经》,上面有各种泡MM的攻略,比如说去吃西餐的步骤、去看电影的方法等等,跟MM约会时,只要做一个Interpreter,照着上面的脚本执行就可以了。
       
        解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。
       
       
       
        16、ITERATOR—我爱上了Mary,不顾一切的向她求婚。
       
        Mary:“想要我跟你结婚,得答应我的条件”
       
        我:“什么条件我都答应,你说吧”
       
        Mary:“我看上了那个一克拉的钻石”
       
        我:“我买,我买,还有吗?”
       
        Mary:“我看上了湖边的那栋别墅”
       
        我:“我买,我买,还有吗?”
       
        Mary:“你的小弟弟必须要有50cm长”
       
        我脑袋嗡的一声,坐在椅子上,一咬牙:“我剪,我剪,还有吗?”
       
        ……
       
        迭代子模式:迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中,从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。
       
        17、MEDIATOR—四个MM打麻将,相互之间谁应该给谁多少钱算不清楚了,幸亏当时我在旁边,按照各自的筹码数算钱,赚了钱的从我这里拿,赔了钱的也付给我,一切就OK啦,俺得到了四个MM的电话。
       
        调停者模式:调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。
       
        18、MEMENTO—同时跟几个MM聊天时,一定要记清楚刚才跟MM说了些什么话,不然MM发现了会不高兴的哦,幸亏我有个备忘录,刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存,这样可以随时察看以前的记录啦。
       
        备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。
       
        19、OBSERVER—想知道咱们公司最新MM情报吗?加入公司的MM情报邮件组就行了,tom负责搜集情报,他发现的新情报不用一个一个通知我们,直接发布给邮件组,我们作为订阅者(观察者)就可以及时收到情报啦
       
        观察者模式:观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
       
        20、STATE—跟MM交往时,一定要注意她的状态哦,在不同的状态时她的行为会有不同,比如你约她今天晚上去看电影,对你没兴趣的MM就会说“有事情啦”,对你不讨厌但还没喜欢上的MM就会说“好啊,不过可以带上我同事么?”,已经喜欢上你的MM就会说“几点钟?看完电影再去泡吧怎么样?”,当然你看电影过程中表现良好的话,也可以把MM的状态从不讨厌不喜欢变成喜欢哦。
       
        状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。
       
        21、STRATEGY—跟不同类型的MM约会,要用不同的策略,有的请电影比较好,有的则去吃小吃效果不错,有的去海边浪漫最合适,单目的都是为了得到MM的芳心,我的追MM锦囊中有好多Strategy哦。
       
        策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。
       
        22、TEMPLATE METHOD——看过《如何说服女生上床》这部经典文章吗?女生从认识到上床的不变的步骤分为巧遇、打破僵局、展开追求、接吻、前戏、动手、爱抚、进去八大步骤(Template method),但每个步骤针对不同的情况,都有不一样的做法,这就要看你随机应变啦(具体实现);
       
        模板方法模式:模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。
       
        23、VISITOR—情人节到了,要给每个MM送一束鲜花和一张卡片,可是每个MM送的花都要针对她个人的特点,每张卡片也要根据个人的特点来挑,我一个人哪搞得清楚,还是找花店老板和礼品店老板做一下Visitor,让花店老板根据MM的特点选一束花,让礼品店老板也根据每个人特点选一张卡,这样就轻松多了;
       
        访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。
前言:呵呵,拿了第一页出来,还没反应过来,就被兄弟们惨骂一顿,前面实在象目录,^_^, 不过大家别急嘛,好歹给我点休息时间。

不多说,下面开始记笔记!^_^

设计模式(Design Patterns)笔记之一:Abstract Factory

定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。提供创建对象的接。

工厂模式是我们最常用的模式,是用来创建对象的,它就相当于创建对象的new。
例如我们有一个类Example,我们要创建Example的对象:

Example example=new Example();

Example example=new Example(参数);

如果创建Example时做的事情不是如赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那明显的就违背了面向对象的原则.
我们需要将创建实例的责任与使用实例的责任分开, 使得

Example example=new Example(参数);

就是简单的责任:使用Example这个实例;而创建Example的任务就交给了Factory工厂模式.

按照传统方法,我们如果需要继承Example类,生成MyExample,就需要定义Example为Interface,然后,不断继承这个Interface,生成许多子类,造成以后代码维护是如此的困难。

如果,我们开始就采用了工厂模式,也许就没有这么多的烦恼了。

我们生成一个Factory,它专门负责生成Example的实例。
public class Factory {
     public static Example getIntance() {
   ......
          if(flag == 1)
             return new MyExample();
          if(flag == 2)
             return new YourExample();
     }
}

然后,那么在你的程序中,如果要实例化MyExample时.就使用

Example example=Factory.getIntance();//还有其它标志,不具体写了。

具体使用:
工厂模式有以下三种:
1. 简单工厂(Simple Factory)
2. 工厂方法(Factory Method);
3. 抽象工厂(Abstract Factory)。

我们先看一段代码
public abstract class Factory{
  public abstract MyExample creator();
  public abstract YourExample creator();
}

public class FirstFactory extends Factory{
  public MyExample creator(){
    ......
  }
  public YourExample creator(){
    ......
  }
}

public class SecondFactory extends Factory{
  public MyExample creator(){
    ......
  }
  public YourExample creator(){
    ......
  }
}

这里,我们需要创建多个对象,复杂性提高,于是需要采用Abstract Factory来封装共同属性和方法,而将不同的属性和方法通过子类来实现。

简而言之,工厂模式的目的就是用来实现实例分发。

工厂模式中几种类型的一些差别:
简单工厂模式是根据参数来决定产生实例;
简单工厂模式, 核心是一个实类;
工厂方法模式的核心是一个抽象工厂类;
工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合;
工厂方法一般只创建一个实例,而Abstract Factory创建多个实例。

前言:呵呵,从这起开始,我们换种记录方法怎么样?学学人家的,寓教于乐。第一次尝试,见笑了。^_^

定义:Adapter:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

角色设定:
Helen,初次接触设计模式的美女程序员(没有BF)。
AndyTao,高手,战斗力达到N级,对设计模式有相当程度的了解。

问题的提出:
Helen埋首在公司自己的小空间里写着代码,(旁白:她虽然是个美女,但是写代码的水平还是不错的。)有点问题正在埋头苦想,这时,AndyTao从旁边冒出来,“嗨,美女,到点了,一起吃饭吧?”“不行,我正烦着呢!”Helen皱着眉头说。“哇,谁,谁欺负咱们Helen???”“切,谁敢欺负我啊。”“那怎么了?”AndyTao一副义愤填膺的样子(这小子,司马昭之心)。
“没有啦,我这里程序不好处理。”“噢,我看看!”AndyTao不知什么时候已经在Helen的身后了。
屏幕上一段代码:
public class DrawCircle {
 public void DrawCircle() {
 ……
 }
   public void insert(String msg){
     System.out.println("DrawCircle insert():"+msg);
 }
 ……
}
public class DrawAngle {
 public void DrawAngle() {
 ……
 }
   public void insert(String msg){
     System.out.println("DrawAngle insert():"+msg);
 }
 ……
}
“我现在要在DrawCircle中调用DrawAngle的方法,可是类的已经分发出去了,不能修改,我该怎么办?”
看着美女皱眉头的样子,AndyTao一阵心痛,“这样啊,我给你提示,再写个Adapter类吧。”“什么是Adapter?”
“呵呵,在实际编码过程中,由于某种需要,我们经常要将两个毫无关系的类交互。于是我们需要进行某种修正,修改各个类的接口,这通常不符合编码要求,而且,如果没有源代码,我们又该怎么办?于是,我们就要用到Adapter了,也就是适配器的意思。象你上面的程序,我们不能修改类接口,于是,我们再写一个Adapter类。”

public class DrawAdapter extends DrawCircle {

 private DrawAngle drawangle;
 public DrawAdapter(DrawAngle angle) {
  this.drawangle=angle;
 }
 public void insert(String msg) {
  drawangle.insert(str);
 }
 ……
}

“在上面代码中,DrawAngle属于Adaptee,是被适配者。DrawAdapter是Adapter,将Adaptee(被适配者DrawAngle)和Target(目标DrawCircle)进行适配。实际上这是将组合方法(composition)和继承(inheritance)方法综合运用的一个例子。这样,你就无需对原来的类修改,甚至无需要知道其内部结构和源代码。”

“上面我们说的是对象适配器(Object Adapter),它允许client和Adaptee完全无关,只有适配器知道它们两者的存在。另外,还有一种是类适配器(Class Adapter),它使用多重继承来实现。象对象适配器(Object Adapter)中,就是上个例子,DrawAdapter继承了DrawCircle,但是,DrawAdapter同样可以继承DrawAngle。由于Java不支持多重继承,这就是说,我们的某个类必须定义为接口(interface)。我们可以把DrawAngle定义为接口IDrawAngle,这样代码如下。”

public interface IDrawAngle {
   public void insert(String msg);
 ……
}

public class DrawAngle implements IDrawAngle {
 public void DrawAngle() {
 ……
 }
   public void insert(String msg){
     System.out.println("DrawAngle insert():"+msg);
 }
 ……
}

public class DrawAdapter extends DrawCircle implements IDrawAngle {

 private DrawAngle drawangle;
 public DrawAdapter(DrawAngle angle) {
  this.drawangle=angle;
 }
 public void insert(String msg) {
  drawangle.insert(str);
 }
 ……
}

“看到了么,这样我们就实现了类适配器(Adapter)模式。不过,类适配器(Adapter)有一个问题,如果我们的Target和Adaptee有一个相同名字的方法,Adapter不能保证这两个方法具有相同的含义或者行为,这是非常危险的。所以要注意这种情况!”

“哦,我知道了,Adapter模式的用处就在于使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。从而解决我现在的问题。”
“美女不笨嘛。这顿你请,以后我请,嘿嘿……”
“想追我?这顿我请,以后嘛,呵呵,再说吧。谢谢,走吧。”“OK!”

欲知后事如何,请待下回。^_^

前言:不好意思,前段时间由于各方面的原因,没顾上写了。这就加油补上。^_^

概念:
Bridge:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

--------------------------------------
烈日,当空;没有一丝风,真的让人感觉透不过气来。想起去年夏天在没有空调的房子里写代码,^_^,真是对人性的一种考验。AndyTao正想着,不觉笑了。午休时间也快过了,继续写我的代码吧。

“Andy,过来帮我看看嘛!”一串银铃声传了过来。

“唉,美女相邀,怎能不动啊。”AndyTao心里想着,没敢说出口。“我说,你又怎么了?就你事多。”

“上次技术讨论会上听你说过,如果一个抽象类或者接口有多个具体的实现类(concrete subclass)的时候,为了不至于由于使用单纯继承进行抽象类或接口的具体实现而导致代码混乱和可重用性不强,你说应当采用Bridge设计模式,这是怎么一回事啊?你看我现在这个例子采用继承不是很好吗?”

“哦,我看看。”

public interface Draw {
 public void paint();
}

public class DrawCircle implements Draw {
    public void paint(){
  System.out.println("paint Circle");
  ……
  }
  ……
}

public class DrawAngle implements Draw {
    public void paint(){
  System.out.println("paint Angle");
  ……
  }
  ……
}

“你看看,我这里不是各干其事,做得挺好嘛。”

“呵呵,听我细细讲来。通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以下两种情况:第一种是,这多个具体实现之间恰好是并列关系,就像你的这段代码,有两个concrete class:画圆和画三角;这两个形状上的图形是并列的,没有相对概念上的重复,那么我们只要使用继承就可以了。……”

“别卖关子了好不好!”“……”“好啦好啦,我请你喝可乐可以吧?”

嘿嘿,奸计得逞,AndyTao继续说道,“但是,我们要考虑到第二种情况,如果我们两个或多个具体实现之间有概念重复,那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象部分和行为部分。”

“好抽象啊,我听不懂!”

“那好,我们来举个例子,嗯……,就拿可乐来说吧,我们喝的可乐有大杯和小杯之分,而又有加冰和不加冰之分,这样,如果我们采用单纯继承来实现这四个具体实现(大杯加冰,大杯不加冰,小杯加冰,小杯不加冰),那么很容易造成相互之间的概念重叠,而且代码混乱,不容易维护。所以……”

“所以,怎么?继续继续。”

“所以啊,我们就要采用Bridge模式来重新设计类的结构。如果采用Bridge模式,我们就需要定义两个接口或抽象类,为的是把抽象部分和行为部分分隔开来。”

“稍等稍等,喝口水先。”“来来来,用我的吧。”“那……,真不好意思了,嘿嘿……”

“我们就用可乐作例子吧。将可乐定义为抽象类,有一部分共同的实现代码可以放到里面,加冰和不加冰属于行为,那么我们就把它定义成为行为接口。”

“然后,我们可以实现下面的抽象类。”

public abstract class Coke {
   CokeImp cokeImp;

   public void setCokeImp(CokeImp cokeImp) {
     this.cokeImp = cokeImp;
   }

   public CokeImp getCokeImp() {
  return this.cokeImp;
 }

   public abstract void distributeCoke();
}

public abstract class CokeImp {
   public abstract void distributeCokeImp();
}

“现在,我们就有了两个抽象类(或接口)。上面,Coke是抽象部分,CokeImp是定义的行为抽象类。为了实现我们所说的四种类动态结合的功能,我们需要在具体实现类上下点功夫罗。”

“这是大可乐:”

public class BigCoke extends Coke
{
  public BigCoke() {}

  public void distributeCoke()
  {
    System.out.print("BigCoke ");
    CokeImp cokeImp = this.getCokeImp();
    cokeImp.distributeCokeImp();
  }
}

“这是小可乐:”

public class SmallCoke extends Coke
{
  public SmallCoke() {}

  public void distributeCoke()
  {
    System.out.print("SmallCoke ");
    CokeImp cokeImp = this.getCokeImp();
    cokeImp.distributeCokeImp();
  }
}

“我要加冰:”

public class IceCokeImp extends CokeImp
{
  IceCokeImp() {}

  public void distributeCokeImp()
  {
    System.out.print("Ice added");
  }
}


“不要冰了:”

public class NonIceCokeImp extends CokeImp
{
  NonIceCokeImp() {}

  public void distributeCokeImp()
  {
    System.out.print("Havn't ice");
  }
}

“这里需要注意了,由于我们的CokeImp和Coke是一对一的关系,所以
前言:看着csdn渐渐让人失望,本来打算不写了。可是老师们教我善始善终,呵呵,那就坚持一回吧。

概念:
Builder:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

---------------------------------------------------------------------------------------

“嘿,Andy,来帮帮忙,帮我装装机子吧。”,Helen又在那喳喳呼呼了。

“好的,好的,喔……,新机诶!”,走过去一看,AndyTao眼一亮。唉,看到人家的新配置,他就有一种据为己有的冲动。说实在的,咱玩电脑的,没几个不这山望着那山高的。。。

“这么大个丫头,到现在还是不会装机器。你怎么学的啊?”AndyTao嘴上这么说,心里想,“最好永远学不会!”

“好的,好的,谢谢你嘛!不过,如果能把你的脑子也装过来就好了。”

“嘿,不是吧,要求过分。。。。。。这样吧,嗯,顺便给你说说设计模式吧!”

“这装机也是个设计模式?”

“听下去!”

“哦。。。”,Helen噘嘴的样子真TMD可爱,AndyTao不觉想入非非了。

“我就给你说说设计模式里的Builder模式好了。Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们。用户不知道内部的具体构建细节。”

“诶,这个和抽象工厂模式不是很相似么?”

“Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到。待会我讲讲Builder和Abstract Factory模式之间的一些区别好了。”

“它一般用在下面两种情况下:
 1、当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
 2、当构造过程必须允许被构造的对象有不同的表示时。
上面的说法太抽象。简单点来说,它是为了将构建复杂对象的过程和它的部件解耦,从而达到将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”

“不懂……具体的来说呢?”

“因为一个复杂的对象,有大量组成部分,有时候多得让人头晕,就拿PC机来说吧:PC机有很多部件:

主板,CPU,硬盘,显示器……还有各种小零件,配件等等;部件很多,如何将这些部件装配成一台PC?

这个装配过程也很复杂,需要很好的组装技术(还吓不着你?),那么我们为了更好的组织PC机这个大对象,就需要一种相应的方法来进行装配。我们要说的Builder模式也就是为了将部件和组装过程分开而产生的。”

“不明白……”

“唉,笨笨,拿你没办法……”

“这样吧,我们说说具体怎么使用先!”

“首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示。”

“首先,需要一个接口,它定义如何创建复杂对象的各个部件:

public interface Builder {

  //创建部件A 比如生产主板
  void buildPartA();
  //创建部件B  比如生产CPU
  void buildPartB();
  //创建部件C  比如生产硬盘
  void buildPartC();
    ……
  //返回最后组装成品结果 (返回最后装配好的PC)
  //成品的组装过程不在这里进行,而是转移到下面的Director类中进行。
  //从而实现了过程和部件的分离
  Product getProduct();
}
 

用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这

些部件组成的),也就是说Director的内容是如何将部件最后组装成成品:

public class Director {

  private Builder builder;

  public Director( Builder builder ) {
    this.builder = builder;
  }
  // 将部件partA partB partC最后组成复杂对象
  //这里是将主板、CPU和硬盘组装成PC的过程
  public void construct() {
    builder.buildPartA();
    builder.buildPartB();
    builder.buildPartC();
  }
}
 

Builder的具体实现ConcreteBuilder:
通过具体完成接口Builder来构建或装配产品的部件;
定义并明确它所要创建的是什么具体东西;
提供一个可以重新获取产品的接口:

public class ConcreteBuilder implements Builder {

  Part partA, partB, partC;
  public void buildPartA() {
    //这里是具体如何构建partA的代码
  };
  public void buildPartB() {
    //这里是具体如何构建partB的代码
  };
   public void buildPartC() {
    //这里是具体如何构建partB的代码
  };
   public Product getProduct() {
    //返回最后组装成品结果
  };
}
 
复杂对象:产品Product:

public interface Product { } 

复杂对象的部件:

public interface Part { }

我们看看如何调用Builder模式:
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getProduct(); ”

“上面所讲的就是Builder模式的一般性使用方法了。至于Builder和Abstract Factory模式的区别,Builder强调的是整体是由部分组成的这个概念,比如你想要得到PC这个复杂对象,那你一定要先准备好主板,CPU,硬盘等等这些构造PC所必须的简单对象,之后调用Builder的get操作得到PC这个最终产品;

而Abstract Factory模式则并不强调这种关系,或者可以说是构造上的‘松耦合’。”

“嗯,咱们来个形象点的比喻吧:Builder模式是用来制造产品的,你的角色相当于产品制造商,知道怎么用部件来制造产品,而部件来自部件制造商,你可以利用不同种类的部件,也可以用同种类的部件采用不同的制造方法。而Abstract Factory是从用户角度来考虑的,主要是给用户提供产品系列,用户可以方便的使用这些产品系列,但是用户没有可能去改变产品,只能使用已有的产品系列。
例如:Builder模式适用于计算机发烧友,经常DIY的;而Abstract Factory模式适用于喜欢稳定的品牌机,像IBM,联想之类的。”

“你的意思是不是,constructor依次调用Builder的buildPart方法,全部完成后再调用getProduct方法得到整个product?那为什么不在Builder中加一个construct方法,依次调用自己的buildPart方法呢?这样还可以减少constructor和Builder之间的耦合。或者说,这种调用是运行时确定的,所以无法写在Builder中间吗?”

“还是上面所说的,如果将构造过程放在Builder里来作,那就失去的构造的灵活性。还拿PC来说吧,如果你在Builder里构造一种PC,80G硬盘的;但是你又想构造另外一种PC,100G硬盘的;你绝对不愿意再修改你的Builder吧,所以Builder用来构造Part,而整体的结构就由另外的一个Director来得到。简单点来说,就是由你自己去组合这些零件,最后调用get方法得到你要的product。”

“在Java实际使用中,我们经常用到‘池’(Pool)的概念,当资源提供者无法提供足够的资源,并且这些资源需要被很多用户反复共享时,就需要使用池了。‘池’实际是一段内存,当池中有一些复杂的资源的‘残余’(比如数据库的连接池,也许有时一个连接会中断),如果循环再利用这些‘残余’,将提高内存使用效率,提高池的性能。重在组装!”

“哦也,我有点明白了……你真行啊!”

“哪里哪里!!!”

“你以为我夸你哪???我说你弄半天还没有帮我把机子装好,你真行啊!!!”

“我晕……倒!你个小妮子!”

作者:杨宁(来自grapecity)

第一章 引言

1. 本文不适合…
本文不适合想通过本文来装修房子的读者;

本文不适合面向对象编程高手,会浪费你的时间。如果你愿意抽出时间来阅读本文,并提出宝贵的建议,非常感谢!什么?你没有听说过设计模式?那你也敢称高手?

2. 本文适合…
如果你对面向对象编程感兴趣,而又没有时间去读Gang of Four的“Design Patterns Elements of Reusable Object-Oriented Software”(以下简称《设计模式》)。那么,本篇文章将帮助你了解23种设计模式。

我第一次读这本书是在每次晚睡之前,几乎每次都先睡着。《设计模式》以一种严谨,系统化的风格来论述23种设计模式,原书可以说是面向对象编程的一个基础教程,但是要领会其精髓,必须要花费一定的精力。本文的目的是为了帮助你更加方便地理解每一种设计模式,并不想成为原书的替代读物。

本文无意于介绍面向对象的基本知识。因此,假设本文的读者已经对面向对象的封装性、继承性和多态性有足够的了解和认识。并能够认识到可复用的面向对象设计的两个原则:  ● 针对接口编程,而不是针对实现编程;
 ● 优先使用对象组合,而不是类继承。


3. 设计模式是什么?
设计模式概念是由建筑设计师Christopher Alexander提出:“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。”上述的定义是对设计模式的广义定义。我们将其应用到面向对象软件的领域内,就形成了对设计模式的狭义定义。

我们可以简单的认为:设计模式就是解决某个特定的面向对象软件问题的特定方法。但严格的来说上述的认识是不准确的,难道面向对象软件中只有区区23个问题?当然不是。

为了能够更加准确地理解这个概念,我们引入另外一个术语:框架(Framework)。框架这个词汇在当今有了各种各样的应用和含义。在设计模式中:框架(Framework)是构成一类特定软件可复用设计的一组相互协作的类。

框架可以认为是一个适用于某个领域的软件包。这个软件包提供了相应领域的各个问题的解决方法。那么,它和设计模式有什么区别?  ● 设计模式和框架针对的问题域不同:
 设计模式针对面向对象的问题域;框架针对特定业务的问题域;


  ● 设计模式比框架更为抽象:
 设计模式在碰到具体问题后,才能产生代码;框架已经可以用代码表示。
 ● 设计模式是比框架更小的体系结构元素:
 框架中可以包括多个设计模式。


Tips:设计模式就像是在武功中基本的招式。我们将这些招式合理地组合起来,就形成套路(框架)。

4. 为什么要用设计模式?
作为程序员都知道良好程序的一个基本标准:高聚合,低耦合。面向对象语言比结构化语言要复杂的多,不良或者没有充分考虑的设计将会导致软件重新设计和开发。然而实际的设计过程中,设计人员更多的考虑如何解决业务问题,对于软件内部结构考虑较少;设计模式则补充了这个缺陷,它主要考虑如何减少对象之间的依赖性,降低耦合程度,使得系统更易于扩展,提高了对象可复用性。因此,设计人员正确的使用设计模式就可以优化系统内部的结构。

第二章 概要简介

在《设计模式》一书中,共包含23个模式。根据目的的不同,将它们分为三类:  ● 创建型(Creational):解决如何创建对象的问题。
 ● 结构型(Structural):解决如何正确的组合类或对象的问题。
 ● 行为型(Behavioral):解决类或对象之间如何交互和如何分配职责的问题。


Tips:设计模式中经常会用到抽象(Abstract)和具体(Concrete)这两个词。抽象的含义是指它所描述的类(方法)是接口类(方法),具体的含义是指它所描述的类(方法)实现了相应的抽象类(方法)。

第三章 抽象工厂(Abstract factory)

1. 意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

2. 分类
创建型模式。

3. 问题是什么?
对于不熟悉这个模式的人都会对工厂(Factory)这个词感到奇怪,为什么会用这个词?之后,我们还会碰到另一个模式——工厂方法(Factory method),所以先解释一下工厂的意义:

房子是由墙,门,窗户,地板,天花板,柱子组成的。如果我们为客户编写一个建造房子的软件,我们会把墙,门,窗户,地板,天花板,柱子看成不同的类:WallClass, DoorClass, WindowClass, CeilingClass, PillarClass。

现在我们建立一个新类A,这个类中有CreateWall(), CreateDoor(), CreateFloor(), CreateCeiling(), CreatePillar()五个方法,每个方法的功能就是创建并返回相应的对象。如果把WallClass, DoorClass, WindowClass, CeilingClass, FloorClass, PillarClass的实例看成产品的话,那么类A就像是一个生产这些产品的工厂。这就是使用工厂这个词的原因。

Tips:A这个名字太糟,如果用HouseFactory会好一些。一般情况下,在你的系统使用某个模式,最好使用模式相应的关键字作为类或者方法的名字的一部分,这样,你的同伴或者系统的代码维护者就会明白你的用意。

我们的软件完成了,客户非常满意。不过,我们的客户想把这个软件出口,他发现一个问题,这个软件太本地化了,建造出来的都是中国式的房屋。因此他希望我们的软件能够建造出不同地域风格的房子。

这就是我们的问题!我们需要重新设计原系统,而且一次完成世界各地不同建筑风格是不可能的。我们会先完成部分风格(客户第一要投放软件的国家的),然后再增加其他的…

4. 解决方法
1) 建立一个抽象工厂(Abstract Factory)类HouseFactory,在这个类中声明:  CreateWall ()
 CreateDoor ()
 CreateFloor ()
 CreateCeiling ()
 CreatePillar ()


2) 建立相应的抽象产品(Abstract Product)类集:

Wall, Door, Floor, Ceiling, Pillar

3) 为不同风格建立相应的具体工厂(Concrete Factory)类(不要忘了实现关系),例如:  ChinaHouseFactory : HouseFactory
 GreeceHouseFactory : HouseFactory
 …


4) 为不同的风格建立相应的具体产品(Concrete Product)类(实现相应的抽象产品),例如:  ChinaWall : Wall
 ChinaDoor : Door
 …
 GreeceWall : Wall
 GreeceDoor : Door
 …


5. 杂谈
我想你一定明白如何灵活的创建和使用上面的一大堆类:  ● 重复最后两个步骤,就可以方便的增加新风格;
 ● 使用前面两个步骤中声明的抽象类来实现操作。


抽象工厂模式的重点不是声明的那个抽象工厂类,而是它声明的一系列抽象产品类,我们通过使用这些抽象产品类可以操作我们已经实现或者还未实现的具体产品类,并且保证了它们的一致性。

你可能已经发现这个软件不能建造你的两层别墅,因为它没有楼梯。为此,我们要定义Stair抽象类,还要增加CreateStair抽象方法;最重要的是我们要在已经完成的76种风格中增加相应的Stair类,这可是个大麻烦。确实,抽象工厂模式在适应新的产品方面的能力是比较弱的。这是它的一个缺点。

 

第四章 生成器(Builder)

1. 意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

2. 分类
创建型模式。

3. 问题是什么?
在抽象工厂一章中,我们了解到了在全球建房系统中如何支持多种房屋的风格。新的问题是:用户希望看到同样结构下,不同风格房屋的外观。比如:这个房子有一个地板,一个天花板,四面墙,一个门,一个窗户。他希望看到中国风格房屋和希腊风格房屋的相应式样。

4. 解决方法


1) 创建一个生成器(Buider)类: Class HouseBuider
 {
  BuildHouse(){}
  BuildWall(int){}
  BuildDoor(int){}
  BuildWindow(int) {}
  BuildFloor(){}
  BuildCeiling() {}
  BuildPillar(){}
  GetHouse() { return Null;}
 }

 


在这个类中,我们对每一种房屋组成元素都定义了一个Build方法。并且定义了一个返回构造结果的方法GetHouse。

2) 对每一种风格都定义一个具体的生成器(Concrete Builder)类: ChinaHouseBuilder: HouseBuilder
GreeceHouseBuilder: HouseBuilder

 


并且在这些类中重载父类的方法。

3) 还有,各种类型的房屋类: ChinaHouse
GreeceHouse

 


5. 如何使用
我们可以用下面的方法使用上面的类来解决我们的问题。 Class HosueSystem
{
object Create( builder HouseBuilder)
{
 builder.BuildHouse();
 builder.BuildFloor();
 builder.BuildCeiling();
 builder.BuildWall(1);
 builder.BuildWall(2);
 builder.BuildWall(3);
 builder.BuildWall(4);
 builder.Door(1);  // 在Wall1上建一个门
 builder.Window(2);  // 在Wall2上建一个窗户

 return builder.GetHouse();
}
}

 


只要向通过HouseSystem.Create方法传入不同的生成器就可以得到不同风格的结果。

事实上,HouseSystem也是生成器模式的一个参与者,叫做导向者(Director)。注意的问题:  ● 生成器(HouseBuilder)类中要包含每一种构件元素的生成方法。比如:楼梯这个元素在某些建筑风格中没有,在其他风格中有,也要加上BuilderStair方法在HouseBuilder中。
 ● 生成器(HouseBuilder)类不是抽象类,它的每一个生成方法一般情况下什么都不做。这样,具体生成器就不必考虑和它无关的元素的生成方法。


6. 杂谈


1) 也许你有这样的想法:生成器模式似乎过于复杂,可以直接在具体House类中定义CreateHouse方法就可以了,例如:

Class ChinaHouse
{
 ChinaHouse CreateHouse()
{ ChinaHouse house;
house = new ChinaHouse();
house.Add(new Floor());
house.Add(new Ceiling());
house.Add(new Wall(1));
house.Add(new Wall(2));
house.Add(new Wall(3));
house.Add(new Wall(4));
house.Add(new Door(1));  // 在Wall1上建一个门
house.Add(new Window(2));  // 在Wall2上建一个窗户

return house;
}
}

 


而生成器模式至少用了两个类来解决这个问题:导向者类和具体生成器类。

那么,生成器模式好在哪里?答案就是职责分配。生成器模式将一个复杂对象的生成这一职责作了一个很好的分配。它把构造过程放到导向者的方法中,把装配过程放到具体生成器类中。我们看看下面的说明。

2) HouseSystem类(导向者)可以非常精细的来构造House。而这个生成过程,对于产品类(ChinaHouse, GreeceHouse …)和生成器类 (ChinaHouseBuilder, GreeceHouseBuilder)都没有必要关心。具体生成器类则考虑装配元素的问题。

7. 活用
生成器模式可以应用在以下的问题上: 

● 将系统的文档格式转换到其他的格式上(每一种格式的文档都相当于一个产品)。
● 编译问题(语法分析器是导向者,编译结果是产品)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值