一 创建型模式
简单工厂模式
将具有相同特征的产品类的创建交给专门的工厂,由工厂负责提供产品的new过程。外部通过抽象的产品引用来使用具体的产品类。Operation
工厂方法模式
进一步提炼抽象工厂类。抽象工厂类生产抽象产品,具体工厂类生产具体产品。
抽象工厂模式
具体工厂生产不止一种产品。抽象工厂更加抽象,可以生产任何及多种抽象产品。
建造者模式
创建的对象有共同的特征或者是组成部分,但是具体的阶段或者构成部分又有特殊,可通过该模式将建造过程和具体建造组件分离开来。BuildPart
比如Android中的对话框构建。
原型模式
创建的是相同结构的对象,为了简化对象的创建行为,克隆已有对象从而创建新的对象。Clone
深拷贝与浅拷贝
单例模式
涉及对象创建,使用时,如果未创建,则新创建;否则,引用已创建的对象实例。GetInstance
因此,只有一个全局对象实例存在
双重锁定
比如应用程序本身、全局组件等。
二 结构型模式
组合模式
类的组织结构是一种开枝散叶的树形形式,整体包含部分,部分同整体具有高度相似的结构。
桥接模式
事物不同角度获得的特征通过桥梁关联起来,因为本质上他们都归属于同一个目标物。
代理模式
通过代理对象隐藏了真实对象本身。对真实对象的访问通过代理间接完成。代理包含了所有访问真实对象所需的接口。
适配器模式
待接入对象与已有抽象类功能类似,接口不同,通过适配器做匹配转换,使得已有对象能够使用标准接口访问被接入对象。
适配容易给人一种向上对齐的感觉,其实这里所作工作是向下适应。适配器选择或者组合外部对象接口,使其行为意图趋同于适配器接口。
比如生活中的电源适配器或者接口适配器。
外观模式
体现的也是一种隐藏细节的思想。通过外观类隐藏背后的类、类操作、类交互,提供给使用者简介、集中、高内聚特性的接口。外观类作为隐藏分界线,需要保持稳定。
享元模式
该模式让多个客户共享同一个类实例。对于存在大量同类对象的情况,使用享元模式,可以有效节省存储。通过定义一个工厂类,生成享元实例,提供给外部使用,避免创建大量实例。
装饰模式
当对一个对象的个性化、定制化修改可以独立出来时,可以使用装饰模式,将差异化部分作为独立类封装起来,独立变化,从而更灵活的应对外部需求。
三 行为型模式
中介者模式
中介者拥有交互多方的信息,交互者通过中介转发,达成信息传递目标。交互者相互之间的连接断开,均挂接到中介者上。
备忘录模式
将关注信息抽取出来,由专门的类负责,达到关联信息集中,内聚加强,方便开发活动进行。
模板方法模式
算法的步骤、流程、环节固定,每个步骤、流程、环节具体动作有差异,则将算法过程抽象为一组接口,作为模板,具体每个接口实现可提供多种方式完成。
Android中OnCreate、OnPause、OnSuspend、OnResume、OnStart、OnStop等行动过程,就是模板方法模式的应用。
观察者模式
抽象出主题和观察者,在它们之间建立映射关系,当具体主题变化时,自动通知调用具体观察者。
比如,多个类对同一个事件感兴趣,在事件发生时,系统通知到所有注册到事件上的对象,则适用此模式。
Android中的很多observer可以看作是此模式的应用。比如触摸方式、鼠标移动、弹出框的变化等。
策略模式
同一个目的有多个策略可以达成时,将不同的策略封装成独立的类,不同条件下使用不同的策略。这样便于策略扩展、扩充、修改,而不影响目标意图的使用方。
这里的关键是表达意图的接口是稳定的。这样,就比较容易抽象出该接口。
迭代器模式
面对集合元素的遍历需求时,可以使用迭代器模式。抽象迭代器可以突出目标要求,比如获取第一个,最后一个,按顺序全部获取,按逆序全部获取等。
至于具体的实现方式,可以面对不同的集合类型,有不同的实现。这样,使用方和实现方均可对齐到统一接口上,各自关注各自的部分。
Android中的for-in循环处理,C++的迭代器遍历等都是此模式的应用。
职责链模式
如果一条消息顺序流过多个节点,每个节点都可能根据具体条件,对消息作出响应或者处理,比如视而不见或者截留,而且中间节点数目、顺序可能存在变化,此时可使用职责链模式。
职责链模式抽象节点的共性特征,比如处理消息,传递消息等,依赖此特征,实现具体的节点处理对象。使用方构造职责链,触发消息流动。
链是这个模式的一个显著特征。
状态模式
如果一个对象有很多种状态,每种状态对应的行为不同,则可考虑采用状态模式,将每种状态的处理独立出来,形成一个一个的处理类,再抽象出其共性的处理接口,产生抽象状态类。
采用这种模式,状态的增加(扩展)比较方便,状态的修改,限定在一个小范围内,避免了无序扩散,从而简化了行为的处理。
典型的,长串的if-else很可能就适用此模式。
命令模式
有三个关键要素,消息接收者、命令、命令接收者。消息接收者接收命令,执行命令。命令由配置的关联命令接收者具体处理。这里,抽象出命令框架,实现各种具体的命令。
对每一个具体命令,需要指定命令接收者,命令接收者执行具体动作。通过这种安排,命令拥有者和命令执行者就分隔开了。命令拥有者可以重复执行命令,可以撤销命令,
在命令具体执行前,有机会过滤命令。而命令执行者,并不关心命令的拥有者,只关注执行命令相关的动作即可。这在每个具体命令生成时就已经确定了。
解释器模式
解释器模式可处理这样一类问题,这类问题可以通过满足一定规则的文法树来表示,此时对问题的处理转变为对文法树的解析与相关操作。
针对具体实现,可以定义抽象的文法处理接口,然后派生各个具体的文法解析器,通过统一的处理接口接收数据,并进行针对性的解析处理。
同样,采用这种模式,可以将解析工作的变化限制在一个相对小的范围内,通过文法树这个核心稳定器实现问题空间与解空间的解耦。
满足文法树的问题表现千变万种,但是都可以通过统一的模式和机制来处理。当前,可以这样做的前提是文法规则要稳定。如果规则变化了,解释器就会变化,变化就会带来复杂度,导致解决方案不再优雅。
访问者模式
当被访问的对象集中包含的元素类型稳定不变时,可以抽象出访问者,定义好对每种类型元素的操作接口。实现具体访问者时,实现对每种具体元素的操作动作。这样,可方便的增加和修改访问者。
采用这种模式的前提是数据元素种类稳定不变,这样才可以在抽象类中预定义对每种类型数据的访问接口。否则,当数据种类变化时,抽象类就需要改变,这会导致变化蔓延到所有具体访问者类。
四 总结:
虽然有这么多的模式,但,有些需求,可能不止一种模式可以套用,可能也没有一种模式精确对标。实践中,更可能是你不知不觉的应用了其中的思想,而不知自己用了某某模式。所以,这里的关键是什么?其实这么多模式,过一遍,你就会有所感觉,其中强烈的表达了抽象的观点。面向对象的核心思想,就是抽象。抽象的作用是反映本质,而本质的东西,最大的好处是稳定,不易变化。通过分离抽象和具体,使用抽象的接口,调用具体的实现,达成以不变应万变的效果。进一步的,设计模式中为各种抽象设定了对应的场景和角色,通过这种方式,实现了抽象和抽象的分离。这种分离带来的好处就是高内聚、低耦合。在相关描述中,常用“独立变化”,“方便扩展,减少修改”等术语,就是具体的体现。