1.监听模式
设计要点:
(1) 要明确谁是观察者谁是被观察者。一般观察者与被观察者之间是多对一的关系,一个被被观察者对象可以有多个监听对象。如一个编辑框,有鼠标点击的监听者,也有键盘的监听者,还有内容改变的监听者。
(2)Observable 在发送广播的通知的时候,无需制定具体的Observer,Observer可以自己决定是否订阅Subject的通知。
(3)被观察者至少需要三个方法:添加监听者、移除监听者、通知Observer方法。观察者至少需要有一个方法:更新方法、即更新当前的内容,做出相应的处理。
应用场景:
(1)对一个对象状态或数据的更新需要其它对象同步更新,或者一个对象的更新需要依赖另一个对象的更新。
(2)对象仅需要将自己的更新通知给其它对象而不需要知道其它对象的细节,如消息推送。
实战应用:
账号异常登录,发送给手机短信或者邮箱。
2.状态模式
设计要点:
(1)在实现状态模式的时候,实现的场景状态有时非常复杂,决定状态变化的因素也非常多,我们可以把决定状态变化的属性单独抽象成一个类StateInfo,这样判断状态属性是否符合当前的状态IsMatch时就可以传入更多信息
(2)每一种状态应当只有唯一的实例
应用场景:
(1)一个对象的行为取决于它的状态,并且它在运行时可能经常改变它的状态,从而改变它的行为。
(2)一个操作中含有庞大的多分支的条件语句,这些分支依赖于该对象的状态,且每一个分支的业务逻辑都非常复杂时,我们可以使用状态模式来拆分不同的分支逻辑,使程序有更好的可读性和可维护性。
3.中介模式
设计要点:
(1) 交互对象,要进行交互的一系列对象
(2)终结者,负责协调各个对象之间的交互
(3)具体中介者,中介的具体实现
应用场景:
(1)一组对象以定义良好但复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
(2)一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象
(3)想通过一个中间类来封装多个类中的行为,同时又不想生成太多的子类
4.装饰模式
设计要点:
(1)可灵活地给一个对象增加职责或拓展功能。你可任意地穿上自己想穿的衣服。不管穿上什么衣服,你还是那个你,但穿上不同的衣服你就会有不同的外表。
(2)可增加任意多个装饰 你可以只穿一件衣服,也可以只穿一条裤子,也可以衣服和裤子搭配着穿,随你意!
(3)装饰的顺序不同,可能产生不同的效果。
应用场景:
(1)有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长时。
(2)需要动态地增加或撤销功能时。
(3)不能采用生成子类的方法进行扩充时,类的定义不能用于生成子类(如Java中的final类)。
装饰模式的应用场景非常广泛。如在实际项目开发中经常看到的过滤器,便可用装饰模式的方式实现
5.单列模式
应用场景:
(1)你希望这个类只有一个且只能有一个实例。
(2)项目中的一些全局管理类(Manager)可以用单例模式来实现
6.克隆模式
设计要点:
克隆模式也叫原型模式,应用场景非常广泛。在Java中与基类Object融为一体,可以随手就拿来用,只要implements Cloneabble接口就默认拥有了克隆的功能。而在Python中,克隆模式成为了语言本身的一部分,因为Python中对象的赋值就是一个浅拷贝的过程。
在设计克隆模式时,唯一需要注意的是:区分浅拷贝与深拷贝,除非一些特殊情况(如需求本身就要求两个对象一起改变),尽量使用深拷贝的方式。
克隆模式的优缺点
优点:
(1)克隆模式通过内存拷贝的方式进行复制,比new的方式创建对象性能更好。
(2)通过深拷贝的方式,可以方便地创建一个具有相同属性和行为的另一个对象,特别是对于复杂对象,方便性尤为突出。
缺点:
通过克隆的方式创建对象,不会执行类的初始化函数(_init_)。这不一定是缺点,但大家使用的时候需要注意这一点。
应用场景:
(1)如果创建新对象(如复杂对象)成本较高,我们可以利用已有的对象进行复制来获得。
(2)类的初始化需要消耗非常多的资源时,如需要消耗很多的数据、硬件等资源。
(3)可配合备忘录模式做一些备份的工作。
实战应用:
功能设置的操作(如字体、字号、常用快捷键等),也就是说这些功能是可配置和修改的。对于一些专业性的软件(如集成开发工具PyCharm和工程制图软件 AutoCAD),这些配置可能会非常多而且复杂。我们在修改这些配置时,通常希望能备份一下原有的配置,以便在设置不合理或出问题时,还能再切换到之前的配置。这时,通常的做法是:复制一份原来的配置,然后在新的配置上做修改,以符合自己的使用习惯,当配置出问题时,再切换到原来的配置。
7.职责模式
设计要点:
(1)请求者与请求内容:确认谁要发送请求,发送请求的对象称为请求者。请求的内容通过发送请求时的参数进行传递。
(2)有哪些责任人:责任人是构成责任链的关键要素。请求的流动方向是链条中的线,而责任人则是链条上的节点,线和节点共同构成了一条链条。
(3)对责任人进行抽象:真实世界中的责任人多种多样,纷繁复杂,有不同的职责和功能;但他们也有一个共同的特征—都可以处理请求。所以需要对责任人进行抽象,使他们具有责任的可传递性。
(4)责任人可自由组合:责任链上的责任人可以根据业务的具体逻辑进行自由的组合和排序。
职责模式的优缺点:
优点:
(1)降低耦合度。它将请求的发送者和接收者解耦。
(2)简化了对象。它使得对象不需要知道链的结构。
(3)增强给对象指派职责的灵活性。可改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任人。
(4)增加新的处理类很方便。
缺点:
(1)不能保证请求一定被接收。
(2)系统性能将受到一定的影响,而且在进行代码调试时不太方便,可能会造成循环调用。
应用场景:
(1)有多个对象可以处理同一个请求,具体哪个对象处理该请求在运行时刻自动确定。
(2)请求的处理具有明显的一层层传递关系。
(3)请求的处理流程和顺序需要程序运行时动态确定。
(4)常见的审批流程(账务报销、转岗申请等)。
8.代理模式
设计要点:
代理模式中主要有三个角色,在设计代理模式时要找到并区分这些角色。
(1)主题(Subject):定义操作、活动、任务的接口类。
(2)真实主题(RealSubject):真正完成操作、活动、任务的具体类。
(3)代理主题(ProxySubject):代替真实主题完成操作、活动、任务的代理类。
代理模式的优缺点:
优点:
(1)代理模式能够协调调用者和被调用者,在一定程度上降低系统的耦合度。
(2)可以灵活地隐藏被代理对象的部分功能和服务,也可以增加额外的功能和服务。
缺点:
(1)由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
(2)实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
应用场景:
(1)不想或者不能直接引用一个对象时,如在移动端加载网页信息时,因为下载真实大图比较耗费流量、影响性能,可以用一个小图代替进行渲染(用一个代理对象去下载小图),在真正点击图片时,才下载大图,显示大图效果。还有HTML中的占位符,其实也是代理模式的思想。
(2)想对一个对象的功能进行加强时,如在字体(Font)渲染时,对粗体(BoldFont)进行渲染时,可使用字体Font对象进行代理,只要在对Font进行渲染后进行加粗的操作即可。
(3)各种特殊用途的代理:远程代理、虚拟代理、Copy-on-Write 代理、保护(Protect or Access)代理、Cache代理、防火墙(Firewall)代理、同步化(Synchronization)代理、智能引用(Smart Reference)代理。
9.外观模式
设计要点:
外观模式是最简单的设计模式之一,只有以下两个角色。
● 外观角色(Façade):为子系统封装统一的对外接口,如同子系统的门面。这个类一般不负责具体的业务逻辑,只是一个委托类,具体的业务逻辑由子系统完成。
● 子系统(SubSystem):由多个类组成的具有某一特定功能的子系统。可以是第三方库,也可以是自己的基础库,还可以是一个子服务,为整个系统提供特定的功能或服务。
外观模式的优缺点:
优点:
(1)实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响调用它的客户端。
(2)简化了客户端对子系统的使用难度,客户端(用户)无须关心子系统的具体实现方式,而只需要和外观进行交互即可。
(3)为不同的用户提供了统一的调用接口,方便了系统的管理和维护。
缺点:
因为统一了调用的接口,降低了系统功能的灵活性。
实战应用:
在互联网世界中,文件的压缩与解压缩是一项非常重要的功能,它不仅能减小文件的存储空间,还能减少网络带宽,现在最常用的压缩文件格式有ZIP、RAR、7Z。从压缩率看:ZIP <RAR < 7Z(即7Z的压缩比最高),从压缩时间看:ZIP < RAR < 7Z(即ZIP的压缩速度最快)。从普及率上看,ZIP应该是应用最广泛的,因为出现的时间最早,格式开放且免费;而7Z因为其极高的压缩比和开放性,大有赶超之势。
假设我们有一个压缩与解压缩系统专门处理文件的压缩和解压缩,这个系统有三个模块:ZIPModel、RARModel、ZModel,分别处理ZIP、RAR、7Z三种文件格式的压缩与解压缩。现在这一系统要提供给上层应用程序使用。