最近几天有心把GofF的《设计模式》好好读下,看一遍中文,看一遍英文,再用本身的语言整理下。之前也曾零零碎碎地看过与设计模式相关的材料,但一直没有系统地学习,对一个比较复杂的知识体系来讲,若是不能好好消化就只剩一些纷杂的概念,反而形成困扰。下文就打算用一个男猪脚小C一天的生活(一天的所见所闻以及相关的感悟甚至由此引起的一些异想天开的想法)来阐述各类设计模式。总体的脉络是尽可能沿着原书章节的顺序,即先讲建立型,再讲结构型,最后是行为型模式。这篇文章的一部分做用是本身学习完以后的总结提炼,以便温故而知新;另一方面若是能引起读者的兴趣的话,就推荐闲暇之余读下原书,只能说经典就是经典。一人之言,其中不免有些牵强之处,不到位之处烦请指正。另外从网上找了一些截图和各位前辈提供的资料混杂于其中,没法一一指出,但在此一并表示感谢。 java
顺道说一下23种设计模式咋看起来就让人产生望而生畏之感,我说一下本身记忆它们的方式,就是根据共性或是其首字母来的。 程序员
Abstract Factory(抽象工厂),Factory Method(工厂方法),Builder(建造者),Singleton(单例),Prototype(原型); 算法
Adapter(适配器), Bridge(桥接), Composite(组合), Decorator(装饰器), Façade(外观), Flyweight(享元), Proxy(代理); 编程
Chain of Responsibility(责任链), Command(命令), Interpreter(解释器), Iterator(迭代器), Mediator(中间人), Memento(备忘录), State(状态), Strategy(策略), Visitor(访问者), Observer(观察者), Template Method(模板方法) 设计模式
建立型模式主要涉及的是关于对象的建立,设计模式里面两个主要的思路一是面向接口编程,二是用组合取代继承,根本目的就是为了支持动态绑定以支持灵活替换的场景,体如今对象的建立上就是将new X()封装起来。 服务器
小C早上开着他的宇宙牌汽车去上班,看到一路的车水马龙,小C忍不住感慨汽车工业的发展。回顾起一百多年来的汽车史,小C仿佛看到了软件的设计模式在也隐藏于这种繁华表面的背后。 网络
以工厂方法为例,该设计模式目的是将类的实例化延迟到子类进行实现。假定有两类人,这两类人有一共同父类,该父类要建造个工厂(这个生成工厂的方法就叫工厂方法),因而继承下来的两类人各自开办本身的工厂,显然只有到了这两类具体的人身上他们才知道本身要建的是什么厂,假设这两类人一类是德国人,一类是日本人,那好吧,德国人实现的那个工厂方法就是建设一个奔驰车厂,日本人相应地建设一个本田车厂,这就叫哪一国的人开办哪一国的厂,只有他们本身清楚。外部客户的调用不用去管他们这种内部的闲事,我实例出来的如果德国人,那我调用工厂方法获得的厂子就是奔驰厂,我用就是了,德国人实例内部已经帮我处理好这种细节了。 框架
泛化的UML如图1: 函数
图1 工具
针对场景的UML如图2:
图2
说完了工厂方法,咱们再讲一下单例模式,单例模式的做用保证一个类只有一个实例,这种场景在计算机的世界很常见,好比咱们运行的程序就只有一个窗口系统的实例,而后由这个窗口系统实例去建立按钮、对话框、列表框等各类各样的实例。回到小C对车的认识来看,咱们很差说全世界就只有一个奔驰车厂或是一个丰田车厂,但咱们转变一个角度,不管是奔驰或是本田这两个牌子都是全球惟一的,提及奔驰,咱们就知道它是德国的著名汽车厂商,为了确保我每次使用的都是这个德国牌的奔驰,咱们要确保它只能被实例化一次,之后不管在哪一个地方使用的都是它。具体的作法即是将这个奔驰类的构造函数非公开化,而用一个公开的方法得到该指向该类的一个引用,调用该方法时,先检查下静态的引用是否有效,若是没有则建立一个实例,有则将它返回给调用方。
泛化的UML如图3:
图3
针对场景的UML如图4:
图4
仍然以车厂为例,讲完了德国人建设的单例奔驰厂,咱们再聊一下像这个奔驰厂、本田厂生产的产品,没有什么道理可说,车厂就是生产车的,可是细提及来这车又能够分为小轿车(Car),大客车(Bus)和货车(Trunk),对应的牌子又是五花八门的,有奔驰的小轿车,丰田的大客车,还有法拉利的跑车呢。而通常来讲,客户在使用的过程当中是以一个系列化产品家族进行使用的,那么咱们怎么样来对此进行抽象了。抽象工厂(Abstract Factory)便提供了这样一种抽象的方式,在抽象工厂类中,定义了几种生产车的虚方法,它们分别是生产小轿车,生产大客车,生产货车的方法;而在具体的工厂类如奔驰车厂或是本田车厂,它们就按照各自的牌子生产属于本身的小轿车、大客车和货车。当抽象工厂的引用或指针被一个具体的工厂所替换后,生产出来的便天然是该牌子的车,这点就无需客户区担心了。
泛化的UML如图5:
图5
针对场景的UML如图6:
图6
稍微总结一下抽象工厂、工厂方法和单例模式,由上分析它们有时能够串联在一块儿使用,由定义工厂方法的子类得到一个具体工厂的单例,该具体工厂就能够建立具备该工厂特点的一系列产品了。实际使用过程当中,因为工厂方法时最为简单的,是考虑问题的第一选择,由此逐渐进行演化。工厂方法的变形就是根据参数生成具体的对象,应用了模板的话还能将具体对象类型做为一个参数传入进去也就无需定义工厂方法的类继承体系。
建立型模式剩余两种分别是建造者模式和原型模式,下面一一道来。小C在上班路上对汽车工业浮想联翩了一大段后,想到要将本身的宇宙牌汽车改造一把。想到这里,小C以为建造者模式在此即可大显身手。众所周知,最简单的汽车是能够由底盘、发动机、轮子、传动器、制动器等组装而成。如今有几种改装方案给小C挑选,一种是极限漂移风格,一种是绅士低调风格,一种是豪华张扬风格。呵呵,而不管小C最终采用哪一种风格进行改装,改装出来的仍是一辆车,而不是一架飞机或是潜水艇;而改装所用到的原料仍是上文提到的那些底盘、发动机、轮子什么的。Ok!讲到这里,你们应该知道建造者模式是什么了吧,通俗来说,建造者模式就是把一个对象里面零零碎碎的东西交给专业的对象去作,本身把控整个过程就好了。在应用程序的世界,一个明显的好处就是一个对象能够在运行时随时替换建造者以改变本身的内部固有属性。
泛化的UML如图7:
图7
针对场景的UML如图8:
图8
小C正在对着他改装宇宙牌汽车想入非非的时候,突然看到路边《变形金刚4》的巨幅电影海报,小C突然感受被浇了一把冷水。是啊,若是小C也有个大黄蜂通常的汽车人还整什么改装车啊,让汽车人一个变身,一个自动复制,要啥车不都是眼到擒来。到那时,我组建一个劳斯莱斯车队和法拉利车队,清一色呵。这里的复制便体现了原型模式(Prototye),这种模式对对象型语言如C++做用比较大,由于C++不是设计针对类型的语言,不能根据类信息来产生出一个对象,原型模式在这里就大有用处。不能用类型来产生对象,也不经过构造方法,我只须要拿到一个对象,调用它的拷贝动做,我就能获得一个如出一辙的对象,固然前提是该对象的类定义了拷贝方法,而至于深拷贝、浅拷贝的问题,感兴趣的话请参见相关书籍。
泛化的UML如图9:
针对场景的UML如图10:
回顾一下,建立型模式包含了五种,分别是抽象工厂、简单工厂、单例、建造者和原型。它们主要面向于对象建立的过程,或是将建立具体对象的过程延迟到子类才指定真正的目标对象类型,或是建立一系列的产品家族,或是限制对象的全局惟一性,或是将对象的构造过程封装起来并委托给其它对象进行实施,或是经过复制自身来进行建立,总而言之就是对new动做进行了一层改造、封装或是分离。
说完了建立型模式,紧接着的结构型模式主题是如何组合类和对象以得到功能更为丰富或是组织更为灵活的结构。 由于能够在运行时改变对象组合关系,因此对象组合方式具备更大的灵活性,而这种机制用静态类继承是不可能实现的。
言归正传,小C一路上班路上对汽车工业的大发感慨也总算到头了。这不,小C刚一进入办公室,就被前台的漂亮小妹喊住了。小妹甜甜地对小C说:“Hi, 帅哥,饮水机没水了,能不能帮我装下桶装水啊。”小C责无旁贷,三下五除二就把水换了,对小妹抛的媚眼呵呵一笑就到座位上了。这不能责怪小C不解风情啊,小C早就心有所属了,弱水三千,我只取一瓢饮。更况且小C由刚才发生的这件小事又联想到第一种最经常使用的结构型模式,即适配器模式(Adapter)。怎么说呢,你看,前台小妹是一个对象,小C也是一个对象,饮水机没水了,小妹要装水,の,不太小妹气力不够干不了这粗活,不要紧,这事交给小C不就得了。对应到专业术语里面,小妹是Adapter, 小C是Adaptee,小妹实现不了装水这个接口,但小妹能把小C喊来,由小C负责干这活就好了。
泛化的UML如图11:
图11
针对场景的UML如图12:
图12
小C上班后的第一件事就是看一下昨天发给客户的邮件收到回复了没有,这个项目的客户是一家汽车4S店,小C日常与他们打交道多了也就知道了汽车保养的一些事。对汽车保养这事来讲,其实里面也蕴藏了一个设计模式,那就是桥接模式(Bridge)。由上一章节的分析可知,咱们对车辆类有个继承体系,如今咱们简化一下专门针对汽车就好了,子类分别是奔驰、宝马、捷达,他们继承于汽车。Ok,这三种车要作保养的话,有如下几种资质的保养商供选择,分别是国际一流钻石品质、24K黄金品质和银色至纯品质。这里就出现了一个问题,不管是奔驰宝马捷达均可以选用任何一种资质的保养商提供保养服务,若是将车型和保养商以多继承体系耦合到一块儿的话,三三得九,要产生的类的个数立刻就爆炸式增加,但咱们分析一下,其实保养商的类体系实际上是能够独立于汽车类的。
对汽车来讲,它关注的是保养这个动做,而这个动做交由具体哪个保养商来实施是能够在具体实施前在进行确认的。从软件工程商来看,整个的设计思想就是将类的抽象与实现进行分离,这就是桥接模式的本质。
泛化的UML如图13:
图13
针对场景的UML如图14:
图14
说完了汽车保养,咱们来认识一下车的本质,其实做为一种交通工具,汽车最本质的做用就是帮助咱们从一个地方转移到另一个地方,而在这两个地方之间,不可避免存在着各类路网,路网里面有高速公路、有城市的快速路、国道、省道、县道、乡道,这些路有些部分又组成了乡镇、城市、区域(如珠三角)。汽车在路网上行驶,帮助咱们从出发地到底目的地。这种路网的结构就能够当作是一种组合模式(Compsite),在路网的组合模式里,一切都是路,无论是大路小路,高速公路或是乡村土路,CBD或是旅游风景区。组合模式帮助咱们一视同仁,创建这种层层划分的路网体系,在基类里声明了对子路网的管理接口,如在子路山上的操做,遍历子路,添加一条子路(或是一个子路网),删除一条一条子路(或是一个子路网)等。
泛化的UML如图15:
图15
针对场景的UML如图16:
小C过了不久便处理完了与公司客户相关的邮件,正好收到了客户发过来的促销邮件呵,说能够给小C的爱车提供在基础保养服务外8折的高级养护。小C想着本身那辆宇宙牌破车成天东奔西跑,也该好好保养保养了,便仔细浏览了下促销邮件内容。不看不知道,原来一份简单的促销邮件也暗藏了一种设计模式。且看邮件的大概内容,原来该4S店有几种基础保养服务,分别是全身水洗,整车干洗,另外还有几种高级养护,好比抛光啊,打蜡啊,车身贴膜啊等等。这里便体现了装饰器(Decorator)模式的妙用,若是将全身水洗服务套进抛光服务便获得服务套餐A,将服务套餐A套进打蜡服务便获得服务套餐B,整个服务套餐B一解开获得的顺序服务即是全身水洗+抛光+打蜡。
泛化的UML如图17:
针对场景的UML如图18:
早上的时间过得很快,小C的工做效率也很高,把早上要完成的设计文档写得差很少后。中午休息的时候小C逛了下电子商务网站,买了个U盘。整个购买流程很简单,小C在网上选中了一款,选择货到付款,确认定货后小C就等快递员的电话了,确实很方便。一样,在这简单的操做流程背后也有一种设计模式在发挥做用,那就是外观模式(Facade)。整个电子商务的运行机制实际上是线上和线下有机配合完成的,在线网站提供了商品浏览、商品对比、商品评论、订单生成,线下部分负责仓库调配、商品出货、物流中转、快递员派送,各类流程在系统的各个部分进行交互,最终确保了U盘在最短期送达小C手上。
泛化的UML如图19:
图19
针对场景的UML如图20:
图20
中午吃饭时间到了,小C和同事们一块儿到食堂吃饭。由于小C日常有空的时候也会本身作饭,深知作饭也是一门大学问,在其中也不能小看了设计模式的做用。这不,小C点了个15元的套餐,两荤一素,看着色香味俱全的饭菜,小C最喜欢的就是这家店的麻婆豆腐,并且小C对豆腐的各类作法可算是深有研究。你看小小的豆腐,以它为主原料,咱们能够作出麻婆豆腐、千叶豆腐、家常豆腐、鱼香豆腐、肉末豆腐等等。在这里,就体现除了一种享元模式(Flyweight),其特色就是聚拢了对象的本质特征,将外部的特征做为context传入进来,由上可知就是一种豆腐作出了五花八门的豆腐宴,一样的道理也发生在鸡的身上,无鸡不成宴,以鸡为主料能够作出宫保鸡丁、口水鸡、盐焗鸡、啤酒鸡、土豆焖鸡各类各样的菜色。餐馆里提供了鸡、鸭、牛肉、豆腐等主料,客人有须要的话便能根据这些主料作出相应地菜色。
泛化的UML如图21:
图21
针对场景的UML如图22:
图22
吃过午餐后,小C小憩了一会就继续精神饱满地上班了。不过下午发生了点小意外,小C正在链接实验室的服务器调试程序。忽然不知道怎么就连不上服务器了,小C赶快找来实验室管理员小D请他排查故障缘由。小D知道后立刻赶往实验室,不到半个小时小D就找到了问题缘由,原来是清洁阿姨打扫卫生的时候不当心碰掉了网线致使链接断开,小D固定好连线以后问题就解决了。从这里咱们能够看到小D其实就是做为小C的代理人帮助他解决特定的问题,体现了代理模式(Proxy),不过要注意的是该模式与以前提到的适配器模式从结构上来讲比较类似,区别就是在此小C和小D都是公司员工,一个是开发程序员,一个是实验室管理员,能够简单认为他们都是继承于员工类;另外代理模式有个做用就是在远程过程调用它能够隐藏对象存在不一样地址空间的事实,而且能够代理能够延缓真正负责动做的对象的实例化阶段以节省内存开销或是对它进行权限验证。
泛化的UML如图23:
图23
针对场景的UML如图24:
场景24
总结一下结构型的设计模式,除了少数的像适配器也能够用类的多重继承来实现外,包括适配器在内等设计模式都是着眼于对象结构的设计,要么是经过偷梁换柱的作法,在其中包含一个其它类对象的引用,本身作不了的事情就转交给别人来干(适配器和代理模式都是属于这一种);要么是虽然有些事原本是得交由两个类一块儿来作,但将它们经过继承体系来搞实在太糟糕,灵活性和规模性都大打折扣,索性还不如就让它们本身去演变得了,这就体现了将类的抽象于实现分离,这是桥接模式,而虽然说是分离,但藕断丝连,在它们之间的有一条链接的桥梁,这条桥梁是要搭到哪个实现类就体现了灵活性嘛。而装饰器和组合模式有一个共同的特色就是子类包含有父类的引用,但装饰器用到这个父类引用的地方主要就是在子类干活的过程当中可让父类引用指向的真正对象帮它干一些活;而组合模式更增强调的是对象在外部看来的一致性,你管我究竟是不可分解的原子仍是有这些原子组成的块块,我提供管理接口给你,你就能够一视同仁地对待,你要遍历我就帮你所有遍历出来,要加个块块或是去掉个原子对你来讲并无必要区分它究竟是个块块仍是原子。剩下的两个模式理念都比较简单,外观模式其实就是封装了内部的呈现,提供给外部调用简洁的接口;享元模式则提取出一些公共元素,放入一个公共池中,要用的时候再传递给它合适的上下文就好了。
小C一开始对做者将设计模式分为这几类是抱有怀疑态度的,怎么分很差,非要这么分,难以理解又难以记忆。不过随着小C的深刻理解,对做者的敬佩之情就更增强烈了。建立型的设计模式自没必要说,主要就是针对对象建立的几种场景而设;结构型模式虽然说也涉及一些控制流程,不过涉及到的关系大抵都是相对简单的,基本上都是单线联系,最重要是体现类之间的设计结构和责任分配;而行为型模式就稍微有点复杂了,从类的设计结构来看虽然说不怎么复杂,可是它最重要的是体现了在运行阶段对象的交互过程。好比这个对象持有另外一个对象的应用,在委托它干一些事情的时候得把本身的相关信息一开始就传递过去,当它干到一半的时候,忽然又想换人了,这种复杂的控制流程在行为型的设计模式很广泛。因此行为型的设计模式重点就在于怎样将复杂的控制流程转换为对象间的相关协做,只要紧紧把握住这一主线,不少问题就好理解了。
闲话少说,咱们开始分解行为型设计模式。下午发生的小插曲实验室网络故障很快就修复了,小C继续投入工做。小C今天要干得事情还真很多,小C想把明天要作的大部分工做在今天干完,由于小C的大学室友明天结婚摆喜酒,小C要过去给他当伴郎,明天要请假一天。咱们就来看看请假这事是怎么体现了责任链这种设计模式。小C请假一天这种小事,首先呈报给项目经理,项目经理大笔一挥就能够批准了;但假如小C要是请假一周,估计项目经理就没这个权限批准,得上报给部门经理;更夸张的话,如果小C由于特殊缘故要请个十天半个月的,那部门经理估计也没这个权限,还得继续上报给技术总监,批不批就看小C的理由够不够充分呵。很明显,这里就体现了一个请求在一条链上是怎么走的,这条链就叫责任链,是事先设计好的。一个请求过来后,根据责任链一环扣一环,在中间环节能够处理的话就返回结果;如果传递到最后一环,该请求是获得默认处理仍是做废就看具体需求而定。
泛化的UML如图25:
图25
针对场景的UML如图26:
图26
小C请假的事情获得经理批准后,咱们的责任链设计模式也就告一段落了,正在此时,小C忽然接到领导的一项紧急任务,要求他提供一份以前一款产品的系统分析报告,这里就涉及到了命令模式(Command)的应用。不过讲到这里有点纠结的地方是命令模式说简单就简单,但说复杂它一扩展的话仍是有些要说的。那咱们就从简单提及,命令模式最简单的状况就是封装命令,让具体的命令对象能够自组织运行,假设我以命令为基类,里面声明了一个虚函数为执行一个动做,只要实现了该接口的类就均可以认为其已经具备了命令类型,它能够真正地实现这个命令动做。就好比领导布置了一项任务,这项具体任务的完成也许是制做一个产品宣传材料、写一篇系统分析报告、作一个会议准备等等。稍微有点复杂的状况就是命令颁布后老是须要有具体的人来完成,就好像刚才领导发布的任务是安排给小C来作的。具体的命令对象实例化的时候老是要给它分配一个实际上完成动做实施的具体人员。按照前面的分析,小C是某系统的设计师,系统分析报告由他来撰写;小E是负责市场营销的,那产品宣传材料就交给他了;而小F是部门的文员,协助领导准备会议相关工做。而更加复杂的场景就是命令链的模式,若是咱们认为小C、小E、小F三我的的工做是存在依赖性的话,好比说小E要写得宣传材料必须得等小C的系统分析报告给他才能让他包装后呈现给客户,而小F须要等小E的宣传材料作出来发送给与会人员进行预审。在这条任务链的模式下,有一个统筹者是项目经理(起到Invoker的责任吧),他会管理这条命令链,能够沿着命令链撤销或重作某一个命令(固然他也只是负责发号施令而已),整个过程就像咱们平时用Office办公软件来重作或撤销一个命令同样。
泛化的UML如图27:
针对场景的UML如图28:
图28
接下来本就该讲讲解释器模式(Interpreter),但苦于小编对该模式的理解也不够深入,感受该模式除了在编译器里面生成语法树外应用场景不多,一时半会找不到合适的例子,暂且略过,后续再进行补充,若是读者有好的建议的话也请帮忙提供。
泛化的UML如图29:
图29
针对场景的UML如图30:
图30
不知不觉,已经到了下午三点半。这时项目组群里已经有人起哄了,小C赶快去买下午茶啊。小C这会才忽然想起又到了每周四的下午茶时间了,这回轮到小C去买了。项目组十来号人,大伙吃下午茶却是挺兴高采烈,但叫谁去买下午茶你们又推来推去。后来无法,你们一致经过按姓名首字母排序,每周一人去买下午茶。这不,这回轮到小C了。小C刚写了两个小时的文档,手都快抽筋了,正好去买下午茶就当休息休息。一路上,小C从买下午茶这个事又联想到了迭代器设计模式(Iterator)。小C果真是有一颗敏感的心啊。迭代器是一种很重要也很经常使用的设计模式,有很多语言如java直接提供了支持方案,像C++的STL也有本身迭代器实现。小C他们项目组十几号人,以前为谁去买下午茶推来推去,后来定了经过首字母排序来确认谁去买下午茶的方案;而当时其它备选的方案有根据工号大小来排序,更有甚者经过出生年月来排的。不管选用哪一种方案,咱们都可以保证项目组里面的每一个人在必定周期内都获得有且只有一次的买下午茶机会。这里面体现的设计思想就是将一个聚合对象的访问和遍历从聚合中分离出来放入一个迭代器,具体的迭代机制具体则由迭代器负责实现。为了完成抽象的遍历和访问功能,抽象迭代器必须声明几个方法,他们分别是定位迭代首位置first(),转移到下一个迭代位置next(),判断迭代是否到头isDone(),得到当前项目currentItem(),而具体的迭代实现类就根据聚合类传递过来的聚合类型实现具体的迭代策略,到底根据首字母仍是根据出生年月遍历。这里在稍微提到一点,由于聚合类也是抽象的,因此聚合类通常会定义一个工厂方法生成迭代对象,而具体的聚合类则实现了这个工厂方法将本聚合类型传递给具体的迭代类构造函数以生成具体的迭代对象,体现了多态迭代的灵活性。
泛化的UML如图31:
图31
针对场景的UML如图32:
图32
小C买完了下午茶回来后,你们围坐在会议桌旁边享受下午茶可贵的休闲时光,天南海北开始侃侃而谈。小C和人力资源部的小G美眉闲聊着,小G提及最近负责接待新员工入职的事情,一我的要协调各类事务,忙得都不可开交了。小C赞叹小G美眉这是能者多劳啊,要是没有小G做为接口人帮助新人处理这些事情,他们不熟悉流程的话两眼一抹黑就像小C刚入职的时候像个二愣子似的办一件事情就要挨个部门问一遍。跟小G美眉聊完天后,小C对比起本身以往的经历,发觉这里由于应用了一种设计模式大大方便了新员工的入职手续流程办理。这种模式就叫中间人模式(Mediator)。怎么说呢?其实,之前小C办理入职的时候要找不一样的人帮他建立内部帐号、分配权限、录入我的资料、申请电脑、安排座位等等,若是当时有小G美眉做为中间人的话,小C就只须要与小G打交道就好了,把相关材料交给小G,小G是知道到底该找谁分配帐号权限、去哪申领电脑、找谁安排座位,也知道各个流程之间的前后步骤。中间人模式与上结构型模式中的外观模式有必定的类似性,不过前者主要是体现类设计与对象交互流程的联系,然后者则是着眼于子系统层面的。
泛化的UML如图33:
图33
针对场景的UML如图34:
图34
小C他们项目组最近在开发一款新的导航仪,小C是这款导航仪的系统设计师。这不,你们吃完下午茶事后,项目经理过来找小C问有没有设计出新的款式出来,以前小C就已经在市场上成熟产品的基础上加了一点小创新搞出了一个原型,这回小C也不藏拙,就将他全新设计的产品原型给经理看,不过也声明了时间紧迫,这款原型还有一年半载没办法产品化,因此经理最终仍是决定让小C采用原先的设计方案尽快投产。在这里就体现了备忘录设计模式(Memento)。从专业术语来说,小C就是做为一个原发器(Originator),负责维护备忘录对象的建立与还原,这里的备忘录显然就是导航仪,而项目经理做为利益相关人(Caretaker),他看过了小C以前设计的成熟导航仪原型,他有权力决定最终投产时要采用哪一款导航仪,而直接跟导航仪打交道的固然仍是小C,因此他要求小C将设计方案恢复到原先的那款成熟的设计上去。
泛化的UML如图35:
图35
针对场景的UML如图36:
图36
吃完了下午茶,小C回到办公位上处理了几封电子邮件后差很少就到了下班时间,小C已经把明天要作的工做也作得差很少,剩下的也委托好相关同事处理了,因而时间一到就闪人了。下班路上,小C开着那辆宇宙牌汽车加入了下班的车流中。今天下班比较早,按照往常的经验小C预感到路上会有点堵,正在小C犹豫着要不要绕道的时候,手机收到了一条语音提示,原来是前几天小C订购了个“交通小助手”的服务,旨在根据实时路况信息提醒车主避开车流高峰,小C接受了服务指示信息,走了另一条路,虽然绕远了一点点,不过一路上畅通无阻。小C心情舒畅,就小小分析了一下在这种订购服务背后隐藏的设计模式,原来这里有观察者模式(Observer)在起做用。像小C这样订购了“交通小助手”的用户应该为数很多,毕竟随着城市的发展,交通压力也是愈来愈大。这些用户不管是小C、小D仍是小E什么的在这里都统一称为是观察者,他们在观察什么呢,他们观察着整个交通的动向以便本身随时作出行驶路线调整。因此“交通小助手”就维护了这样一批订购用户列表(能够增长新的订购用户或是删除老的订购用户),当交通状况发生变化时,就一一通知车主(notify)根据本助手发布的最新信息调整本身的行车路线。
泛化的UML如图37:
图37
针对场景的UML如图38:
图38
小C下班回到家里,女友小Y已经买好菜了。他们两人有一块儿作饭的习惯,小Y最拿手的菜就是水煮鱼和红烧鱼了。这不,小Y买了一条鱼回来,小C大显身手的时候到来了。其实这作水煮鱼和红烧鱼的的具体步骤是挺相似的,买来的时候鱼已经杀好,具体都步骤都是先把鱼切好,准备好相关的调料,而后就是烧鱼了。提及来简单,作起来可不是这么容易,细节之处就体现了大师和菜鸟之间的差异哦。由于这里体现了一种叫作模板方法(Template Method)的设计模式。都是那三板斧,但具体的作法的差别但是很大嘀。就好比说,作水煮鱼须要把鱼肉切成厚薄适中的鱼片,而红烧鱼的话只须要在鱼的两面各划几刀以便汤汁渗透便可;准备调料的过程更是差别明显,水煮鱼的话要准备好黄豆芽,香芹,葱、姜、蒜,花椒,干辣椒,而红烧鱼则要准备料酒、生抽 姜丝和盐;烧鱼的时候水煮鱼是熬成大杂烩,红烧鱼则须要煎鱼后在逐步放入各类调料。看到了吧,这就是模板方法的妙用,作鱼是一件很抽象的东西,三步,切鱼,准备调料,和烧鱼,这里只定义了一个基本的框架和步骤,具体到了作水煮鱼仍是作红烧鱼的时候就由具体对象去定义具体的细节。
泛化的UML如图39:
图39
针对场景的UML如图40:
图40
小C和女友小Y一块儿吃完晚饭后,小Y提议去逛街。小C最怕就是陪女人逛街了,不太小Y一撒娇小C岂敢不从,因而乎两人就高高兴兴出门去了。转眼到了换季的季节,步行街上的专卖店处处都是打折促销的消息。小C跟在女友后面看着她兴致勃勃地挑这挑那,小C却想到了一个更为普遍的问题,话说咱们天天都要穿衣服,并且一年四季都是在根据不一样的季节穿不一样的衣服,夏天穿短裤短袖,冬天穿棉裤棉袄,这里就体现出了一种叫状态(State)的设计模式。状态模式有个好处就是能够简化各类if-else组合起来的判断条件,它可以根据传入的状态对象肯定实际采用的动做。
泛化的UML如图41:
图41
针对场景的UML如图42:
图42
小C和他女友小Y逛街逛得差很少了,小Y说要作个头发,呵呵,女人兴致一来了挡都挡不住,小C只能硬着头皮跟着她进了理发店,看着小Y和店员兴高采烈地讨论哪一种发型好看。小C只能拿起一本时尚杂志消遣,看着看着倒勾起了小C的兴趣,结合作小Y作头发和各位理发师的专长,小C琢磨出了这其中策略模式(Strategy)。假设这店里的理发师每一个人都有两把刷子,有的擅长设计潮流时尚型的,有的擅长设计复古典雅的,有时擅长设计清新飘逸的,有的擅长设计爆炸动感的,这些理发师各类表明了一种策略,而小Y其实是将本身一头秀发委托给了设计师进行造型处理。策略模式在程序设计的时候主要是用来作算法替换,因此才有了策略这么一个名字,好比有一个乱序的数列,将这个数列交给不一样的算法对象如快速排序、归并排序、堆排序、冒泡排序等进行处理。
泛化的UML如图43:
图43
针对场景的UML如图44:
图44
小C看她女友最终肯定要作一个清新飘逸的发型,估摸起来得花半个小时以上,本身摸了一下头发好像也有点长了,那就顺便在这家店也剪了吧。因而小C让理发师帮本身剪短一下,不过发型设计师立刻就开始推销他擅长的发型设计说搞个像贝克汉姆的鸡冠头很不错什么的,不过惋惜了,小C就一普通青年,既不是而是2B青年也不是什么文艺青年,将就着剪短一下就好了。这样一来,小C和她女友小Y都在同一家店理发了,换了另一个角度来看,这里又体现了另一种叫访问者的设计模式(Visitor)。咱们暂且认为小C或是小Y都有一个本身的专职发型设计师,这是他们能够自由选择的权利嘛。首先,小C和小Y性别不一样,暂且就认为他们都是继承于Person;另外,小C和小Y剪头发这个事严格意义上来讲是理发师完成的,而刚才说了,理发师分了各类类别,有潮流时尚型的,也有清新飘逸型的;而不管哪一种类型的发型设计师,就这个场景来说,他们能够操纵的类别也就是男人女人两种。访问者设计模式的精髓在于在同一继承体系下的不一样的对象接受同一个访问者会呈现出不一样的效果,同一对象能够改变它的访问对象对同一操做也会呈现出不一样的效果。
泛化的UML如图45:
图45
针对场景的UML如图46:
图46
设计模式博大精深,这篇软文只是本身闲暇之余的消遣,以加深对设计模式的理解和便于记忆,若是可以对读者有所帮助那就更加使人高兴了。当初GofF把设计模式整理成书的一个很重要缘由就是为了定义这么一套术语以便大伙交流学习使用,咱们在理解面向对象和设计模式的基础上,在实际工做过程当中不必定要拘泥于某种设计模式,由于每每是多个模式相辅相成以达到灵活设计的效果,这样大概能够算是张三丰学太极拳最后什么都忘了以后也算学会了道理差很少。该文大部分的内容仍是描述性的,等有空的话我也许会分别用C++和java进行实现,并实现一些场景须要同时复合多种模式,之后再说。