结构设计模式:通常处理实体之间的关系,使这些实体更容易协同工作.
行为设计模式:用于实体,并使其更容易,更灵活的对这些实体进行通信之间的通信和make.
结构模式微服务
结构型模式是为解决怎样组装现有的类,设计他们的交互方式,从而达到实现必定的功能的目的。
结构型模式包容了对不少问题的解决。例如:扩展性(外观、组成、代理、装饰)封装性(适配器,桥接)。
行为模式设计
行为型模式涉及到算法和对象间职责的分配。
行为模式描述了对象和类的模式,以及它们之间的通讯模式。
行为型模式刻划了在程序运行时难以跟踪的复杂的控制流可分为行为类模式和行为对象模式代理
一些行为对象模式描述了一组对等的对象怎样相互协做以完成其中任何一个对象都没法单独完成的任务。
**定义:**将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项
目的扩展和维护性。
**选用规则:**需要构建多个对象时,或者项目后续可能新增其他相似对象时,当这些对象的构建过程(步骤)相同且每个步骤其内容相似时,可以采用工厂模式创建多个同种类不同方向的对象。工厂与不同对象间设计为聚合关系。
通过更改工厂完成不同方向的对象扩展,用聚合替换继承。避免了新建类(继承类)的代码量。因为工厂生成的对象创建过程一致,抽出所有构建代码(构建步骤)为工厂类。
调用方对聚合了工厂对象的类输入新建的工厂对象,通过调用这个类的方法生成不同方向的对象。
通过把聚合了工厂对象的类的对象生成方法变为抽象,由不同方向大类去实现。但对象的公用加工步骤仍可以在聚合了工厂对象的类中存放。
通过把聚合了工厂对象的类变成一个接口,所有生成、加工方法均为抽象。
**定义:**原型模式(Prototype 模式)是指用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
即对象的深拷贝代替构造器新建对象,深拷贝方式:clone(),序列化,set方法
选用规则:当所需要Bean或普通对象需要填充的属性为动态变化时可采用。例子:Spring配置Bean的单例与原型互斥配置。
**定义:**建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出 来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它
们, 用户不需要知道内部的具体构建细节。
客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可
以创建不同的产品对象 。
每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具
体建造者, 用户使用不同的具体建造者即可得到不同的产品对象。
**选用规则:**建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使 用建造者模式,因此其使用范围受到一定的限制。当项目需要创建多个相似对象时,且需要详细区分每个对象的生成过程、加工过程时可采用建造者。当多个对象属于一类当差异较大时,且构造加工过程较少则可选用工厂设计模式。
建造者模式程序的UML:
定义:
适配器模式属于结构型模式
主要分为三类:类适配器模式、对象适配器模式、接口适配器模式
选用规则:将两个或多个不同大类的对象群通过两个或多个接口的公共实现类、或聚合依赖(引入对象)、或**组合依赖(引入不可移除的依赖如私有链表)**连接起来。当需要引入外部某一个类或一组类的很多方法时,通过适配器来链接与相互调用。当多个类或项目很多处需要用到某一工具类的一些方法的不同实现时,可以把该类改为接口,采用接口适配器的匿名内部类来各自实现与引用。
1.类适配器模式UML:因为是继承所以叫类适配器模式
3.接口适配器模式(缺省适配器):当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。适用于一个接口不想使用其所有的方法的情况。
适配器在源码中的案例的UML:
SpringMVC使用该适配器的好处:可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用Controller方法,需要调用的时候就得不断是使用if else来进行判断是哪一种子类然后执行。那么如果后面要扩展Controller, 就得修改原来的代码,这样违背了OCP原则。
1**.定义**:将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。 是一种结构型设计模式, Bridge 模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要 特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功 能扩展
2.选用规则:当项目框架中成品对象种类较多、且每种类仍包含种类较多时,采用单层或多层(继承)接口聚合的方法引用相关各自的方法。适配器适配的大多不算是接口,但桥接为接口引用。
3.理解与注意事项:实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统。
\2) 对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其它的部分由具体业务来完成。
\3) 桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本。
1.定义:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开
闭原则**(ocp**)。
2.选用规则:当项目中某个固定对象的相应方法或某一组对象(继承一个基类)的相应方法、或相应应用层方法需要根据业务需要不确定的改变时,可以采用装饰者模式套娃的动态生成新对象。由于他们共同继承基类,故可替代原对象来获得新的方法实现过程。而桥接模式主要针对两个接口的关系,装饰者模式则针对装饰组接口及被装饰者多个接口进行链接。
Component 主体:比如类似前面的 Drink
ConcreteComponent 和 Decorator
ConcreteComponent:具体的主体, 比如前面的各个单品咖啡
Decorator: 装饰者,比如各调料.
在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可以设计一个缓冲层, 将共有的部分提取出来,抽象层一个类。
1**.定义**:组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示“整体**-**部分”的层次关系。
\2) 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。 (组合代替继承表示阶层关系)
\3) 这种类型的设计模式属于结构型模式。
\4) 组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户以一致的方式处理个别对象以 及组合对象。
2.选用规则:当设计对象较复杂且有不同应用方向时,可以采用组合模式的树形结构构建对象,提供搞扩展性与外部封装性。
3.注意事项:
\1) 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
\2) 具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动.
\3) 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的
树形结构
\4) 需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式.
\5) 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式
\1) Component :这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行
为,用于访问和管理
Component 子部件, Component 可以是抽象类或者接口
\2) Leaf : 在组合中表示叶子节点,叶子节点没有子节点
\3) Composite :非叶子节点, 用于存储子部件, 在 Component接口中实现 子部件的相关操作,比如增加(add),
删除。
1.定义:
\1)外观模式(Facade),也叫“过程模式:外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了 一个高层接口,这个接口使得这一子系统更加容易使用
\2) 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无
需关心这个子系统的内部细节
2.选用规则:
封装其他聚合对象与方法即外观模式,可以抽离共同步骤。意义就是直接抽离不同对象形成新一层,减少对源代码的修改。如spring的service层
4.注意事项:
外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
\2) 外观模式对客户端与子系统的耦合关系 - 解耦,让子系统内部的模块更易维护和扩展
\3) 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
\4) 当系统需要进行分层设计时,可以考虑使用 Facade 模式
\5) 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个
Facade 类,来提供遗留系统的比较清晰简单的接口,让新系统与 Facade 类交互,提高复用性
\6) 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维
护为目的
1.定义:享元模式(Flyweight Pattern) 也叫蝇量模式: 运用共享技术有效地支持大量细粒度的对象 。
\2) 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象 中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
\3) 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对 象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
\4) 享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享 元模式是池技术的重要实现方式。
2.选用规则:与池技术相似,当某个对象或某组对象及其下方法需要被多处利用且调用非同一对象时,可以采用池技术创建抽象享元对象聚合一组改组对象的队列(长度可扩展),外部调用直接从池子获取。
3.UML图:
对类图的说明 :
\1) FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态(后面介绍) 的接口
或实现
\2) ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
\3) UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
\4) FlyWeightFactory 享元工厂类,用于构建一个池容器(集合), 同时提供从池中获取对象方法
4**.注意事项**:
\1) 在享元模式这样理解,“享”就表示共享,“元”表示对象
\2) 系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化时,我们就可以考虑选用享元
模式
\3) 用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,用 HashMap/HashTable 存储
\4) 享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率
\5) 享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部
状态的改变而改变,这是我们使用享元模式需要注意的地方.
\6) 使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制。
\7) 享元模式经典的应用场景是需要缓冲池的场景,比如 String 常量池、数据库连接池
1.定义:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是: 可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
\2) 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
\3) 代理模式有不同的形式, 主要有三种 静态代理、动态代理 (JDK 代理、接口代理)和 Cglib 代理 (可以在内存动态的创建对象,而不需要实现接口, 他是属于动态代理的范畴) 。
2.选用规则:在一次需求中,需要扩展一个类的功能且后续不再扩展时时采用。
静态代理:使用静态代理方式,就需要在代理对象 TeacherDAOProxy 中也实现 ITeacherDAO
\4) 调用的时候通过调用代理对象的方法来调用目标对象.
\5) 特别提醒:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展 。
缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类;一旦接口增加方法,目标对象与代理对象都要维护。
动态代理:代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
\2) 代理对象的生成,是利用 JDK 的 API,动态的在内存中构建代理对象。只需要使用 newProxyInstance 方法,但是该方法需要接收三个参数。
Cglib代理: 静态代理和 JDK 代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是 Cglib 代理 。
\2) Cglib代理也叫作子类代理**,**它是在内存中构建一个子类对象从而实现对目标对象功能扩展, 有些书也将Cglib代
理归属到动态代理。
\3) Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口.它广泛的被许多 AOP 的框架使用,例如 Spring AOP,实现方法拦截
\4) 在 AOP 编程中如何选择代理模式:
\1. 目标对象需要实现接口,用 JDK 代理
\2. 目标对象不需要实现接口,用 Cglib 代理
\5) Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类
1.定义:模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
\2) 简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
\3) 这种类型的设计模式属于行为型模式。
2.选用规则:当某个需求需要多个策略时,同时多个策略间可以有公用的算法,则可采用模板方法
4.注意细节:
基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
\2) 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
\3) 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
\4) 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
\5) 一般模板方法都加上 final 关键字, 防止子类重写模板方法.
\6) 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模式来处理
1.定义:\1) 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计 。
\2) 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
\3) 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。
2.选用规则:当不同业务需求需要调用不同子类的同一方法时可以使用,显而易见,非常适用于单向传递消息。
\1) Invoker 是调用者角色
\2) Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
\3) Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作
\4) ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现 execut
4.注意事项:
\1) 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的 execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
\2) 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
\3) 容易实现对请求的撤销和重做
\4) 命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
\5) 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
\6) 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发-反馈机制
1.定义:
\1) 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
\2) 主要将数据结构(男女)与数据操作(投票类型)分离,解决 数据结构和操作耦合性问题
\3) 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口 (采用双分派回调方法把一个client的传参在内部转变为两次传参)
\4) 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
2.选用规则:减少输入参数,把多个对象用接口抽象汇集,内部回调,适用对象稳定、但操做对象的方法或对象内部方法属性未来可能变化的情况。
\1) Visitor 是抽象访问者,为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作
\2) ConcreteVisitor :是一个具体的访问值 实现每个有 Visitor 声明的操作,是每个操作实现的部分.
\3) ObjectStructure 能枚举它的元素, 可以提供一个高层的接口,用来允许访问者访问元素
\4) Element 定义一个 accept 方法,接收一个访问者对象
\5) ConcreteElement 为具体元素,实现了 accept 方法。
4.注意事项:
优点 :
\1) 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
\2) 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
缺点 :
\1) 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节(回调),这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
\2) 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
\3) 因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.
1.定义:\1) 迭代器模式(Iterator Pattern)是常用的设计模式,属于行为型模式
\2) 如果我们的集合元素是用不同的方式实现的,有数组,还有 java 的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
\3) 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
2.选用规则:与组合模式目标一致,为了解决多层次对象的管理。组合模式采用树形结构避免继承,为一种结构性的设计模式。而迭代器模式是行为模式,主要解决不同层对象间的信息传递、不同层对象内部数据结构暴露等问题。
\1) Iterator : 迭代器接口,是系统提供,含义 hasNext, next, remove
\2) ConcreteIterator : 具体的迭代器类,管理迭代
\3) Aggregate :一个统一的聚合接口, 将客户端和具体聚合解耦
\4) ConcreteAggreage : 具体的聚合持有对象集合, 并提供一个方法,返回一个迭代器, 该迭代器可以正确遍历集合
\5) Client :客户端, 通过 Iterator 和 Aggregate 依赖子类.
案例UML:
系聚合到学院里,学院聚合到学校里。
4.注意事项:
优点 :
\1) 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
\2) 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
\3) 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
\4) 当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式。
缺点:
每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类
1.定义: 观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为Observer,Subject通知 Observer 变化,比如这里的奶站是 Subject,是 1 的一方。用户时 Observer,是多的一方。
2.选用规则:一对多的消息传递模式
Subject:登记注册、移除和通知
\1) registerObserver 注 册
\2) removeObserver 移 除
\3) notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,看具体需求定
Observer:接收输入
4.注意事项:
\1) 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。
\2) 这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类 WeatherData 不会修改代码, 遵守了 ocp 原则。
1.定义:
\1) 中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
\2) 中介者模式属于行为型模式,使代码易于维护
\3) 比如 MVC 模式,C(Controller 控制器)是 M(Model 模型)和 V(View 视图)的中介者,在前后端交互时起到了中间人的作用
**2.选用规则:**中介者模式适用提供多个独立对象间相互交互的复杂服务,把复杂逻辑处理放置到中介者中。
\1) Mediator 就是抽象中介者,定义了同事对象到中介者对象的接口
\2) Colleague 是抽象同事类
\3) ConcreteMediator 具体的中介者对象, 实现抽象方法, 他需要知道所有的具体的同事类,即以一个集合来管理HashMap,并接受某个同事对象消息,完成相应的任务
\4) ConcreteColleague 具体的同事类,会有很多, 每个同事只知道自己的行为, 而不了解其他同事类的行为(方法),但是他们都依赖中介者对象
4.注意事项:
\1) 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,进行解耦
\2) 减少类间依赖,降低了耦合,符合迪米特原则
\3) 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
\4) 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
1.定义:\1) 备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
\2) 可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作 。
\3) 备忘录模式属于行为型模式
2.选用规则:
\1) originator : 对象(需要保存状态的对象) 。
\2) Memento : 备忘录对象,负责保存好记录,即 Originator 内部状态 。
\3) Caretaker: 守护者对象,负责保存多个备忘录对象, 使用集合管理,提高效率 。
\4) 说明:如果希望保存多个 originator 对象的不同时间的状态,也可以,只需要要 HashMap
4.注意事项:
\1) 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态 。
\2) 实现了信息的封装,使得用户不需要关心状态的保存细节 。
\3) 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存, 这个需要注意 。
\4) 适用的应用场景:1、后悔药。 2、打游戏时的存档。 3、Windows 里的 ctri + z。 4、IE 中的后退。 4、数据库的事务管理。
\5) 为了节约内存,备忘录模式可以和原型模式配合使用。
1.定义:
\1) 在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器
\2) 解释器模式(Interpreter Pattern):是指给定一个语言**(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(**表达式)
\3) 应用场景-应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树-一些重复出现的问题可以用一种简单的语言来表达-一个简单语法需要解释的场景
\4) 这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等。
2.选用规则:
\1) Context: 是环境角色,含有解释器之外的全局信息.
\2) AbstractExpression: 抽象表达式, 声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享
\3) TerminalExpression: 为终结符表达式, 实现与文法中的终结符相关的解释操作
\4) NonTermialExpression: 为非终结符表达式,为文法中的非终结符实现解释操作.
\5) 说明: 输入 Context he TerminalExpression 信息通过 Client 输入即可
4.注意事项:
\1) 当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有良好的扩展性
\2) 应用场景:编译器、运算表达式计算、正则表达式、机器人等
\3) 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低.
1.定义:
\1) 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换 。
\2) 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类 。
**2.选用规则:**状态机,每种状态赋予不同的业务前后逻辑
\1) Context 类为环境角色, 用于维护 State 实例,这个实例定义当前状态
\2) State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为
\3) ConcreteState 具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为
4.注意事项:
\1) 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
\2) 方便维护。将容易产生问题的 if-else 语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多 if-else 语句,而且容易出错
\3) 符合“开闭原则”。容易增删状态
\4) 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度
\5) 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候, 可以考虑使用状态模式
1.定义:\1) 策略模式(Strategy Pattern)中,定义算法族(策略组),分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
\2) 这算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合/聚合,少用继承(客户通过组合方式使用策略)。
**2.选用规则:**提取逻辑中不同处需要不同的策略(算法)为一个接口,后续调用直接传入该结构子类,如comparable接口。
说明:从上图可以看到,客户 context 有成员变量 strategy 或者其他的策略接口,至于需要使用到哪个策略,我们可以在构造器中指定 。
4.注意事项:
\1) 策略模式的关键是:分析项目中变化部分与不变部分
\2) 策略模式的核心思想是:多用组合/聚合 少用继承;用行为类组合,而不是行为的继承。更有弹性
\3) 体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为) 即可,避免了使用多重转移语句(if…else if…else)
\4) 提供了可以替换继承关系的办法: 策略模式将算法封装在独立的 Strategy 类中使得你可以独立于其 Context改变它,使它易于切换、易于理解、易于扩展
\5) 需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞
1.定义:
\1) 职责链模式(Chain of Responsibility Pattern), 又叫 责任链模式,为请求创建了一个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。
\2) 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的 请求传给下一个接收者,依此类推。
\3) 这种类型的设计模式属于行为型模式
**2.选用规则:**当一个外部请求一定要处理完毕,且有很多不同情况的不同处理人(handler),则可以采用责任链模式。注意:每个处理器的下一任处理器设置一定要闭环。
3.UML:
\1) Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外 Handler
\2) ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链
\3) Request , 含义很多属性,表示一个请求
4.注意事项:
\1) 将请求和处理分开,实现解耦,提高系统的灵活性 。
\2) 简化了对象,使对象不需要知道链的结构 。
\3) 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在 Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识 地破坏系统性能。
\4) 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂 。
\5) 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web 中 Tomcat对 Encoding 的处理、拦截器。