设计模式总结篇二

本文是设计模式阶段性总结的最后一篇,在上一篇中对设计模式做了简单的归类,并对创建型模式进行了梳理对比,接下来继续梳理结构型和行为型相关的设计模式,其中结构型设计模式7种,行为型模式11种。结构型设计模式是对类和对象的组织方式进行的介绍,行为型设计模式是对类和对象之间通信进行的介绍,结构和行为设计也是软件设计中非常最要的一个环节。

学习并理解设计模式是“做什么”的可能比较容易,但是“为什么”可能需要更深层次的理解,因为这个”为什么“正是设计模式需要解决的问题。

设计模式划分

目的
创建型 结构型 行为型
范围 简单工厂(Simple Factory)
工厂方法(Factory Method)
类适配器(Adapter) 解释器(Interpreter)
模板方法(Template Method)
对象 抽象工厂(Abstract Factory)
构建者(Builder)
原型(Prototype)
单例(Singleton)
对象适配器(Adapter)
桥接(Bridge)
组合(Composite)
委托(Delegate)
装饰(Decorator)
外观(Facade)
享元(Flyweight)
代理(Proxy)
责任链(Chain of Responsibility)
命令(Command)
迭代器(Iterator)
中介者(Mediator)
备忘录(Memento)
观察者(Observer)
状态(State)
策略(Strategy)
访问者(Visitor)

结构型模式

适配器模式(Adapter):将一个类的接口转换为客户希望的另一个接口。适配器模式可以让原配不兼容的接口一起合作无间。适配器分为类适配器和对象适配器,类适配器是基于类继承实现的,而对象适配器是基于对象组合实现。在GUI开发中,还有一种适配器比较常用,被称为缺省适配器。

桥接模式(Bridge):将抽象部分和实现部分相分离,使它们可以独立地变化。其实这里的抽象实现术语有些过于学术了,很难从定义中理解该模式的应用场景,个人理解该模式更直观的建议应该是告诉我们要学会向不同维度抽象。

上图可以很好的诠释桥接模式的精髓所在,将颜色相关的类都抽取到作为颜色类子类,然后在形状类中添加一个颜色类的引用。那么,形状类就可以将颜色相关的工作委托给颜色对象完成,这样的引用就成为了形状和颜色之间的桥梁。此后,新增颜色将不再需要修改形状的类层次,反之亦然。

组合模式(Composite): 将对象整理成树形结构以表示“部分-整体”的层次结构,它可以使用户对单个对象和组合对象的操作具有一致性。组合模式分为透明组合模式和安全组合模式,在抽象组件Component中定义了管理成员对象的方法即是透明组合模式,将管理成员的方法都定义在了Composite容器组件中即是安全组合模式,透明组合模式是组合模式的标准形式。

委托模式(Delegate):委托模式虽然并没有被归类在23中常用的设计模式之中,但是在开发中确实也是比较常用的软件设计模式之一,在J2EE开发中业务委托模式在已经作为了官方的一种设计模式。可以把委托模式作为一种特殊形式的组合设计模式。

装饰模式(Decorator):动态地给一个对象添加一些额外的职责。若要扩展功能,装饰这提供了比继承更有弹性的替代方案。装饰模式的核心在于不改变对象原功能基础上,动态地新增功能,一般将装饰者与组件对象继承自相同的父类。

外观模式(Facade):提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。

享元模式(Flyweight):有时叫蝇量模式或者轻量级模式,享元模式是运用共享技术有效地支持大量细粒度对象的复用。

代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。代理模式分为静态代理和动态代理,静态代理要求代理类和委托类需要有相同的父类或者接口。动态代理又分为JDK动态代理和cglib动态代理,JDK动态代理可以直接生成接口的实例,而不需要要创建子类实现该接口后再创建实例。cglib动态代理可以直接生成某个对象的代理对象,即使该对象没有实现任何接口。

结构型模式介绍如何将类和对象组合成更大的结构,并保持结构的灵活和高效。一个良好的架构一定是建立在一个非常高效且灵活的结构层次上的,如果熟悉HTML、CSS和JavaScript,应该了解HTML代表的就是结构,CSS是样式,JavaScript则是行为,有些非常酷炫的交互是可以在HTML和CSS结合下可以完成的,完全不需要JavaScript。如果在软件设计时类和对象的结构组织非常清晰且有条理,一定可以为后续的开发带来难以想象的便利。

在23种设计模式中,虽然行为型模式占据11种,但是这些行为模式一定建立在类和对象良好结构基础之上的,所以结构型和行为型模式界限其实并不是如想象中那样清晰明了的。

组合模式和装饰模式在类结构图上很相似,两者在类和对象的组织上确实有许多共同点,不过目的却有很大的不同。组合模式在于将多个相关对象能够以统一的方式处理,而装饰模式目的是不新增子类就可以动态为对象添加新的责任。

装饰模式与代理模式也有很多相似之处,差异性也是在于两者的目的不同。两种模式都描述了怎样为对象提供一定程度上的间接引用,代理对象和装饰对象的实现部分都保留了指向另一个对象的引用。代理模式是当直接访问一个实体不方便或不符合需要时,为这个实体提供一个替代者,它更强调的是一种关系,代理对象和原对象的关系。在装饰模式中,原对象(组件)仅提供部分功能,其余的功能由一个或多个Decorator负责完成。

外观模式(Facade)与中介者模式的不同之处在于它是对一个对象子系统进行抽象,从而提供了一个更为方便的接口。它的协议是单向的,即Facade对象对这个子系统类提出请求,但反之则不行。

行为型模式

责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

责任链可以分为纯的和不纯的责任链。一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:一个是承担责任,另一个是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又将责任向下传的情况。在一个纯的职责链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的职责链模式里面,一个请求可以最终不被任何接收端对象所接收。

命令模式(Command):将请求封装成对象,以便使用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

命令模式中,一般请求对象(Invoker)持有一个Command对象引用,Command持有一个Receiver对象的引用,执行对象Receiver并不会持有Command或者Invoker。

命令模式通过增加了一个中间层(Command),将请求的对象(Invoker)和执行对象(Receiver)进行了解耦。被解耦的两者之间是通过命令对象进行通信的。命令对象封装了接收者的一个或者一组动作。

命令模式中接收者(Receiver)不是必需的,即直接使用命令完成请求执行的的操作。只是这样实现的解耦程度不如使用接收者的结构。

// 创建接收者
Receiver receiver = new Receiver();
// 创建命令对象,设定其接收者
Command command = new ConcreteCommand(receiver);
// 创建请求者,把命令对象设置进去
Invoker invoker = new Invoker(command);
// 执行方法
invoker.action();

解释器模式(Interpreter):定义一个语言的文法,并建立一个解释器用于解释该文法表示的句子。

迭代器模式(Iterator):提供了一种顺序方法用于访问聚合对象中的各个元素,而又不暴露该对象的内部表示。

中介者模式(Mediator): 用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

备忘录模式(Memento):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

状态模式(State):允许一个对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

策略模式(Strategy):针对一系列算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

模板方法模式(Template Method):在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 Visitor模式也是Java模拟双分派机制的一种设计模式。

行为模式不仅描述对象和类的模式,还描述它们之间的通信模式。

模板方法使用继承改变算法的一部分,策略模式使用委托改变整个算法。

中介者模式与观察者模式通常是相互竞争的。在一个GUI设计的系统中,每一个控件的UI事件都可以理解为是对观察者模式的应用,当多个UI控件间通信时则可以借助于中介者模式协调。

在命令模式中,Command是作为一个中间者的身份,请求和响应并不是直接相互调用,而是通过Command建立联系。观察者和被观察者其实是直接相互关联调用的,并且一个观察者可以同时关联多个观察者。在观察者模式中,接口是为了处理被观察者的变化而设计的,耦合性相比命令模式也更高一些。

责任链模式按照顺序将请求动态传递给一系列的潜在接收者,直至其中一名接收者对请求进行处理或者所有的接收者都不接收请求。

命令模式在发送者和请求者之间通过命令对象建立单向连接。

中介者模式清除了发送者和请求者之间的直接连接,强制它们通过一个中介对象进行间接沟通。

观察者允许接收者动态地订阅或取消接收请求。

结束语

在武术或者其它竞技运动都有相关套路或者品势,这些套路或者品势就是为了锻炼身体素质,练习技术动作。同样的,设计模式就是问题的解决方案,是可以被重复使用的技术手段,学习了23种设计模式,就相当于学习了23种不同的武术套路或者品势。

面向对象的三大特性:封装、继承和多态,学习设计模式可以很好的理解巩固这三大特性。设计模式绝对是面向对象设计方法中重要的一环,因为设计模式有太多地方展示了诸如对象、继承和多态的基本技术。

在所整理的设计模式相关文章中,特别是一些专业术语的定义与使用,一般都是参考自如下书籍:

《设计模式-可复用的面向对象设计的基础》 GOF

《Head First设计模式》

《Java设计模式》 刘伟

《Java与设计模式》 朱天华

代码示例除了参考上述书籍中之外,也参考了网上的许多其它有关设计模式的博客,也有些是根据自己对模式的理解设计而来。

近些年有许多关于设计模式的讨论与质疑,这里有两篇比较有深度的讨论,有兴趣的可以阅读了解。

20年前GoF提出的设计模式,对这个时代是否还有指导意义?

如何正确地使用设计模式?

评论

您确定要删除吗?删除之后不可恢复