定义
将对象组合成树型结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
类型
结构类模式
类图
代码实现
1 | public abstract class Component { |
优点
- 高层模块调用简单
- 节点自由增加
缺点
树叶和树枝使用时直接使用了实现类,在面向接口编程上是很不恰当的,与依赖倒置原则冲突。
## 使用场景
- 维护和展示部分——整体关系的场景,比如树形菜单,文件和文件夹管理
- 从一个整体中能够独立出部分模块或功能的场景
将对象组合成树型结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
结构类模式
1 | public abstract class Component { |
树叶和树枝使用时直接使用了实现类,在面向接口编程上是很不恰当的,与依赖倒置原则冲突。
## 使用场景
将抽象和实现解耦,使得两者可以独立的变化
结构类模式
1 | public interface Implementor { |
为其他对象提供一种代理以控制对这个对象的访问
结构类模式
1 | public interface Subject { |
讲一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够一起工作
结构类模式
1 | public interface Target { |
在详细设计阶段不用考虑,而是解决正在复议的项目的问题
当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了其类。
创建类模式
State——抽象状态角色
接口抽象类,负责对象状态定义,并且封装环境角色以实现状态转换。
ConcreteState——具体状态角色
每一个具体状态必须完成两个职责: 本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态
Context——环境角色
定义客户端需要的接口,并且负责具体状态的切换。
1 | public abstract class State { |
结构清晰
避免许多switch…case
遵循设计原则
很好地体现了开闭原则和单一职责原则
子类会太多,可以解决,比如在数据库中建立一个状态表,然后根据状态执行相应的操作。
给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。
行为类模式
1 | class Context {} |
解释器是一个简单的语法分析工具,它最显著的优点就是扩展性,修改语法规则只需要修改相应的非终结符就可以了,若扩展语法,只需要增加非终结符类就可以了。
解释器模式会引起类的膨胀,每个语法都需要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来非常多的麻烦。同时,由于采用递归调用方法,每个非终结符表达式只关心与自己相关的表达式,每个表达式需要知道最终的结果,必须通过递归方式,无论是面向对象的语言还是面向过程的语言,递归都是一个不推荐的方式。由于使用了大量的循环和递归,效率是一个不容忽视的问题。特别是用于解释一个解析复杂、冗长的语法时,效率是难以忍受的。
在以下情况下可以使用解释器模式:
解释器模式真的是一个比较少用的模式,因为对它的维护实在是太麻烦了,想象一下,一坨一坨的非终结符解释器,假如不是事先对文法的规则了如指掌,或者是文法特别简单,则很难读懂它的逻辑。解释器模式在实际的系统开发中使用的很少,因为他会引起效率、性能以及维护等问题。
提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。
行为类模式
1 | interface Iterator { |
对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合。
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。
行为类模式
1 | interface IStrategy { |
做面向对象设计的,对策略模式一定很熟悉,因为它实质上就是面向对象中的继承和多态,在看完策略模式的通用代码后,我想,即使之前从来没有听说过策略模式,在开发过程中也一定使用过它吧?至少在在以下两种情况下,大家可以考虑使用策略模式,
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
行为类模式
## 责任连模式的结构
1 | class Level { |
责任链模式与if…else…相比,他的耦合性要低一些,因为它把条件判定都分散到了各个处理类中,并且这些处理类的优先处理顺序可以随意设定
在找到正确的处理类之前,所有的判定条件都要被执行一遍,当责任链比较长时,性能问题比较严重。
就像开始的例子那样,假如使用if…else…语句来组织一个责任链时感到力不从心,代码看上去很糟糕时,就可以使用责任链模式来进行重构。
责任链模式其实就是一个灵活版的if…else…语句,它就是将这些判定条件的语句放到了各个处理类中,这样做的优点是比较灵活了,但同样也带来了风险,比如设置处理类前后关系时,一定要特别仔细,搞对处理类前后逻辑的条件判断关系,并且注意不要在链中出现循环引用的问题。
责任连模式常常会和模板方法一起使用
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
行为类模式
1 | class Invoker { |
首先,命令模式的封装性很好:每个命令都被封装起来,对于客户端来说,需要什么功能就去调用相应的命令,而无需知道命令具体是怎么执行的。比如有一组文件操作的命令:新建文件、复制文件、删除文件。如果把这三个操作都封装成一个命令类,客户端只需要知道有这三个命令类即可,至于命令类中封装好的逻辑,客户端则无需知道。
其次,命令模式的扩展性很好,在命令模式中,在接收者类中一般会对操作进行最基本的封装,命令类则通过对这些基本的操作进行二次封装,当增加新命令的时候,对命令类的编写一般不是从零开始的,有大量的接收者类可供调用,也有大量的命令类可供调用,代码的复用性很好。比如,文件的操作中,我们需要增加一个剪切文件的命令,则只需要把复制文件和删除文件这两个命令组合一下就行了,非常方便。
最后说一下命令模式的缺点,那就是命令如果很多,开发起来就要头疼了。特别是很多简单的命令,实现起来就几行代码的事,而使用命令模式的话,不用管命令多简单,都需要写一个命令类来封装。
对于大多数请求-响应模式的功能,比较适合使用命令模式,正如命令模式定义说的那样,命令模式对实现记录日志、撤销操作等功能比较方便。
对于一个场合到底用不用模式,这对所有的开发人员来说都是一个很纠结的问题。有时候,因为预见到需求上会发生的某些变化,为了系统的灵活性和可扩展性而使用了某种设计模式,但这个预见的需求偏偏没有,相反,没预见到的需求倒是来了不少,导致在修改代码的时候,使用的设计模式反而起了相反的作用,以至于整个项目组怨声载道。这样的例子,我相信每个程序设计者都遇到过。所以,基于敏捷开发的原则,我们在设计程序的时候,如果按照目前的需求,不使用某种模式也能很好地解决,那么我们就不要引入它,因为要引入一种设计模式并不困难,我们大可以在真正需要用到的时候再对系统进行一下,引入这个设计模式。
拿命令模式来说吧,我们开发中,请求-响应模式的功能非常常见,一般来说,我们会把对请求的响应操作封装到一个方法中,这个封装的方法可以称之为命令,但不是命令模式。到底要不要把这种设计上升到模式的高度就要另行考虑了,因为,如果使用命令模式,就要引入调用者、接收者两个角色,原本放在一处的逻辑分散到了三个类中,设计时,必须考虑这样的代价是否值得。
感觉 Redux
有借鉴命令模式的思想
Nothing to say
Front-End Development Engineer