设计模式
- 设计模式代码地址https://gitee.com/BeliveLove/source-code/tree/master/src/main/java/com/example/demo/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/
行为型设计模式
模板方法模式
- 模板方法模式定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤
- 模板方法模式:
- 抽象类(AbstractRole):算法骨架,有一个模板方法和多个其余方法组成
- 模板方法(TemplateMethod):算法骨架,按照某种顺序执行方法
- 抽象方法(method4):抽象类申明,由具体类实现
- 具体方法(method1,method2):抽象类实现,子类继承或重写
- 钩子方法(method3):抽象类实现,包含了模板执行的逻辑方法,可以由子类重写
- 实现类(ConCreateRole,ConCreateRole2):重写具体方法或者钩子方法,属于模板方法最高逻辑的一部份组成
- 模板方法模式的优点、缺点
- 优点
- 封装了不变的部分,拓展了可变部分
- 在抽象类中提取了公共代码,便于复用
- 通过子类覆写主要逻辑,符合开闭原则
- 缺点
- 每一种实现,都需要一个子类,增加了类的数目,使系统变得复杂
- 模板方法主要通过继承实现,如果在父类添加了方法,则所由子类都需要修改
策略模式
- 策略模式定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户
- 策略模式
- 抽象策略(AbstractStrategy):定义了具体策略的规范接口,是环境角色访问的对象
- 具体策略(ConCreateStrategyNotNull,ConCreateStrategyNotList):实现了抽象策略,是具体算法的实现
- 环境(StragyContext):持有抽象策略的引用,最终给客户用
- 策略模式的优点、缺点
- 优点
- 实现与使用分离(在具体策略实现,环境中调用)
- 是一个可替换的、可重用的算法族
- 缺点
- 客户需要了解具体策略
- 增加了策略类,是系统类变多,更复杂
命令模式
- 命令模式定义:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开. 这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理.
- 命令模式:
- 抽象命令(Command):声明执行命令的抽象接口,拥有执行命令的抽象接口
- 具体命令(ConCreateShutdown,ConCreateStartUp,ConCreateSelect):实现了抽象接口,并且创建了对应的实现者Receiver,通过调用实现者来完成业务操作
- 实现者(ReceiverStartUp,ReceiverShutdown,ReceiverSelect):是实现业务的真正执行者
- 调用者(Invoker):请求的发送者,内部拥有命令抽象接口引用,通过具体命令访问实现者,不直接访问实现者(与策略模式的区别在这)
- 命令模式的优点
- 优点
- 引入中间访问层访问具体实现,进一步降低了耦合
- 拓展良好,基于命令接口的增加以及删除命令,不影响其余类,符合开闭原则
- 缺点
- 会导致具体命令以及实现过多,增加系统复杂性
责任链模式
- 责任链模式定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止.
- 责任链模式:
- 抽象处理者(AbstractHandler)角色:定义一个处理请求的接口,包含抽象处理方法.
- 具体处理者(ConcreteHandlerLogin,ConCreateHandlerLimit,ConCreateHandleWriteLog)角色:实现抽象处理者的处理方法.
- 组装类(HandlerGroup):将多个具体处理者用List或者Array装起来,并且提供同一调用
- 责任链模式的优点、缺点
- 优点
- 关注工作流程的处理,对于流程的拓展性很高,能够轻松的添加流程或者删除流程以及更改流程执行顺序
- 责任分担,每一个具体处理者只处理自己的部分
- 对于流程的拓展符合开闭原则,只需要添加具体实现,然后添加组合类中去
- 缺点
- 对于每一个请求,不一定能够处理,即便传到末尾也无法处理
- 如果职责链较长,可能导致性能影响
- 多个具体实现类,增加了系统复杂性
状态模式
- 状态模式的定义:对有状态的对象,把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为.
- 状态模式
- 环境类(StateContext):客户访问的接口,持有当前状态,能够实现具体状态的切换
- 抽象状态类(State):定义了接口规范,包含特定状态的行为规范,是环境类的引用对象
- 具体状态类(FailState,RunningState,RunableState):实现了抽象状态的接口,能够持有环境类,并根据环境刷新状态
- 状态模式的优点、缺点
- 优点
- 不同的具体状态职责清晰,符合单一原则
- 状态转化现显示化,减少了对象间的引用
- 缺点
- 增加了系统复杂性
- 对开闭原则不是很好,如果需要动态切换状态,则需要修改源码
- 状态模式和策略模式的区别
- 策略模式对于不同算法的封装,替换使用;状态模式则是对于一个对象的不同行为的维护
- 状态模式中每个具体状态持有每个环境的引用,而策略模式没用
- 策略模式的状态修改,由Client显示修改;而状态模式的修改由Context隐式完成
观察者模式
- 观察者模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.
- 观察者模式
- 抽象主题类(AbstractSubject):定义了具体抽象类所需要实现的基本操作,如add、delete观察者,通知观察者
- 具体主题类(ConCreateSubject,ConCreateSubjectPerson):实现了抽象主题类的方法,如果有需要可以自我实现将任何操作延迟到子类.内部维护了一个集合存储观察者对象
- 抽象观察者(AbstractObserver):定义了当具体观察者收到具体主题所的通知时刷新自身的方法
- 具体主题类(ConCreateObserverGovernment,ConCreateObserverMarket):实现了抽象观察者刷新自身的方法,是具体主题类被注册的对象
- 观察者模式的优点、缺点
- 优点
- 高层模块定义的规则与低层实现无关,符合依赖倒置原则
- 具体抽象的实现可以将通知操作延迟到子类,对于不同的场景可以实现自定义通知,而无需修改源码,符合开闭原则
- 观察者与被观察者之间建立了一套属于自身的通知机制
- 缺点
- 有可能产生循环引用
- 观察者对象较多时,通知可能花费更多的时间
中介者模式
- 中介者模式定义:定义一个中介对象来封装一系列对象之间的交互(对象之间的交互存在网状结构),使原有对象之间的耦合松散,且可以独立地改变它们之间的交互.
- 中介者模式:
- 抽象中介者(AbstractMediator):定义了中介者所需要的基本方法,包括具体同事的注册、消息的转发机制
- 具体中介者(ConCreateMediator):实现了抽象抽象中介者,内部维护List对象用于存储具体同事对象
- 抽象同事(AbstractColleague):定义了具体同事所需要实现的基本方法,保存了中介者对象
- 具体同事(ConCreateColleague,ConCreateColleagueB):抽象同事的实现,当同事同事需要交互时,通过中介者实现
- 中介者模式的优点、缺点
- 优点
- 符合迪米特法则
- 相互需要通信的对象之间耦合降低
- 将不同对象之间的多对多的关系转化为了与中介者相关的一对一的关联
- 缺点
- 当同事十分多的时候,中介者将十分臃肿
- 是系统变得复杂
- 中介者跟观察者的区别
- 观察者着重于多个对象依赖于一个对象时,当'一'发生改变时,告诉所有的'多'
- 中介者侧重在于,多个对象之间需要互相通信,引入中介者统一管理
- 观察者不需要知道与谁通信,只是把所有订阅的对象都发布通知
- 中介者需要知道与谁通信,并且消息的发布是一对一
迭代器模式
(PS:这个模式抄的,因为懒得写!)
- 迭代器模式定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示.
- 迭代器模式
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口.
- 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例.
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法.
- 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置.
- 迭代器模式优点、缺点
- 优点
- 数据的表示与数据的获取分离
- 对于数据的操作方式修改容易,只需要实现接口即可
- 简化了数据表示类,数据操作通过统一接口转化为迭代器处理
- 缺点
- 增加系统复杂性
访问者模式
- 访问者模式定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式.
- 访问者模式:
- 抽象访问者(Visitor):定义了需要访问的具体元素的接口,为每一个具体访问的元素定义一个visit,入参便是具体访问元素
- 具体访问者(ConCreateVisitorA,ConCreateVisitorB):实现了抽象访问者接口,确定了访问具体元素时需要执行的操作
- 抽象元素者(Element):声明一个包含接受操作accept()的接口,被接受的访问者对象作为 accept() 方法的参数
- 具体元素者(ConCreateElementA,ConCreateElementB):实现了抽象元素者,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作.
- 对象结构者(ObjectStructure):是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法
- 访问者模式的优点、缺点:
- 优点
- 拓展性好,可以在不修改源对象的情况下,对元素添加新的功能
- 符合单一职责原则,无论是访问者还是元素,每一个访问者、元素的功能都很单一
- 缺点
- 新增新的元素十分困难,通过抽象访问者定义了元素的访问,在添加新的元素修改十分困难
- 增加了系统的复杂性
- 双重委派导致了代码的难于理解
- 访问者模式的双重委派
- 第一层委派
- ObjectStructure#accept(Visitor visitor)中通过运行时element的具体实现决定不同的具体元素
- 第二层委派
- 具体元素类中ConCreateElement*#accept(Visitor visitor)中通过不同的visitor决定不同的访问者访问具体元素的操作
备忘录模式
- 备忘录模式定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态.
- 备忘录模式
- 发起人(Originator):记录了对象当前的状态信息,提供创建、恢复备忘录的功能
- 备忘录(Memento):存储了发起人内部真正的信息
- 管理者(Caretaker):对备忘录进行管理,能够保存、获取备忘录,但是不能修改备忘录、获取备忘录的信息
- 备忘录模式的优点、缺点
- 优点
- 内部提供了一种对象的恢复机制,能够较为方便的恢复到历史中某状态
- 对历史记录的恢复实现了安全控制,除了自己谁也不能访问
- 缺点
- 保存历史记录将消耗很大的内存
- 增加了系统的复杂性
解释器模式
- 解释器模式定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子.
- 解释器模式:
- 抽象表达式(AbstractExpression):定义了解释器的接口,对解释器做出了规范
- 终结符表达式(TerminalExpression):实现了抽象表达式,每一条终结字符规则都对应一个终结表达式
- 非终结符表达式(NonterminalExpression):实现了抽象表达式,每一条非终结规则对应一个非终结表达式
- 环境(ContextExpression):对外访问的接口,分装了一系列解释器的规则
- 解释器的优点、缺点
- 优点
- 拓展容易,每一条规则都通过接口实现
- 缺点
- 如果规则过多,会导致类的数目增多,代码极度膨胀