责任链模式
以公司的审批流程来说,一般审批流程需要经历多个节点,只有当层层审批通过后才算成功,审批请求就通过这条层层审批的链路传递,这条链就叫做责任链。
责任链模式避免了请求发送者和接收者之间耦合,让多个对象都可能接受请求,将这些对象连接成一条链,并且沿着这条链传递,直到有对象处理到它为止。
责任链模式通常包含两个角色:
- 抽象处理者
- 具体处理者
抽象处理者通常定义了一个处理请求的接口,共给具体处理者处理。同时抽象处理者也定义了一个自身类型的对象作为Next下一个节点的引用。
abstract class Handler {
//维持对下家的引用
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor=successor;
}
public abstract void handleRequest(String request);
}
具体处理者只需要继承抽象处理者即可,重写抽象处理者的处理方法。如果当前处理者处理不了该请求,就转发给下一个链路。
class ConcreteHandler extends Handler {
public void handleRequest(String request) {
if (请求满足条件) {
//处理请求
}
else {
//this.successor就是下一个链路的引用
this.successor.handleRequest(request); //转发请求
}
}
}
优点:
- 避免了打量了if else的逻辑判断
- 在对象分派职责时候,可以对链进行随意的动态改变,不需要更改内部代码,符合开闭原则
缺点:
- 请求不一定能够保证绝对被处理,可能走到了责任链的末尾依旧得不到处理
- 责任链过长,可能导致请求无法及时处理,系统性能收到影响
- 责任链建链不当可能造成循环调用,导致死循环
命令模式
命令模式的核心是将指令信息封装成一个对象,并将此对象作为参数发送给接收方去执行,达到使命令的请求与执行方解耦,双方只通过传递各种命令对象来完成任务。
我们知道,C 语言支持函数指针,我们可以把函数当作变量传递来传递去。但是,在大部分编程语言中,函数没法儿作为参数传递给其他函数,也没法儿赋值给变量。借助命令模式,我们可以将函数 封装成对象。具体来说就是,设计一个包含这个函数的类,实例化一个对象传来传去,这样就可以实现把函数像对象一样使用。
命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。
命令模式一般包括4个角色:
- 抽象命令类
- 具体命令类
- 调用者
- 接收者
抽象命令类
abstract class Command {
public abstract void execute();
}
调用者(发起命令)可以通过构造注入或者set注入的方式,将具体的命令类注入到自身,调用其中的execute方法
class Invoker {
private Command command;
//构造注入
public Invoker(Command command) {
this.command = command;
}
//设值注入
public void setCommand(Command command) {
this.command = command;
}
//业务方法,用于调用命令类的execute()方法
public void call() {
command.execute();
}
}
具体命令类继承抽象命令类,并充给execute方法,关联请求接收者,在execute中执行接收者的请求相应方法
class ConcreteCommand extends Command {
private Receiver receiver; //维持一个对请求接收者对象的引用
public void execute() {
receiver.action(); //调用请求接收者的业务处理方法action()
}
}
请求接收者具体实现对请求的业务处理
class Receiver {
public void action() {
//具体操作
}
}
例如餐饮出餐流程:
Command作为抽象方法(出餐抽象)
服务员作为Invoker调用者角色,命令出餐
厨师作为接受者,真正执行命令的对象 Receiver
OrderCommand 作为具体命令类,持有一个接收者引用,调用recevier的执行操作
优点:
- 命令魔偶是可以降低接收者和请求者之间的耦合读,相同的请求者可以对应不用的接收者,相同的接受这样也可以共给不同的请求者使用
- 新命令易于添加
缺点:
- 系统可能出现过多具体命令类, 导致系统复杂
解释器模式
解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。
TODO
这个模式初步有点理解不了,埋坑以后填
迭代器模式
迭代器模式是把遍历数据的行为从容器中抽取出来,封装到迭代器对象中,由迭代器来提供遍历数据的行为,这将简化聚合对象的设计,更加符合单一职责原则。像java提供的iterator接口一样。
迭代器模式主要包括4个部分:
- 抽象集合
- 具体集合
- 抽象迭代器
- 具体迭代器
抽象集合主要存储和管理元素对象,定义存储、添加、删除集合元素的功能,并且声明了一个iterator()方法用于创建迭代器对象。
public interface Aggregate<E> {
Iterator<E> iterator();
}
具体集合主要实现抽象集合类,返回一个具体迭代器实例
public class ConcreteAggregate<E> implements Aggregate<E>{
private List<E> aggregateList;
public ConcreteAggregate(List<E> aggregateList) {
this.aggregateList = aggregateList;
}
@Override
public Iterator<E> iterator() {
return new ConcreteIterator<E>(this.aggregateList);
}
}
抽象迭代器:主要是访问和遍历聚合元素的接口,包含hasNext(), next(), currentItem()等
public interface Iterator<E> {
// 重置游标
void reset();
// 判断集合中是否有下一个元素
boolean hasNext();
// 游标后移
E next();
// 返回当前游标指定的元素
E currentItem();
}
具体迭代器:实现抽象迭代器中的方法
public class ConcreteIterator<E> implements Iterator<E>{
private int cursor; // 游标
private List<E> arrayList; // 容器
public ConcreteIterator(List<E> arrayList) {
this.cursor = 0;
this.arrayList = arrayList;
}
@Override
public void reset() {
this.cursor = 0;
}
@Override
public boolean hasNext() {
return this.cursor != this.arrayList.size();
}
@Override
public E next() {
return arrayList.get(this.cursor++);
}
@Override
public E currentItem() {
if(this.cursor >= this.arrayList.size()){
throw new NoSuchElementException();
}
return arrayList.get(this.cursor);
}
}
中介者模式
一个系统中对象之间存在多对多的相关关系,如果我们可以将对象之间的关系从各个对象中分离出来,并集中封装在一个中介者对象,并由中介者集中协调,这样对象之间多对多的复杂关系就转化为简单的一对多关系了。可以看出中介者是一种解耦合的模式。
中介者一般包含4个角色:
- 抽象中介者Mediator 它定义一个接口,该接口用于与各同事对象之间进行通信。
- 具体中介者ConcreteMediator 它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。
- 抽象同事类Colleague 它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
- 具体同事类ConcreteColleague 它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
abstract class Mediator {
protected ArrayList<Colleague> colleagues; //用于存储同事对象
//注册方法,用于增加同事对象
public void register(Colleague colleague) {
colleagues.add(colleague);
}
//声明抽象的业务方法
public abstract void operation();
}
class ConcreteMediator extends Mediator {
//实现业务方法,封装同事之间的调用
public void operation() {
......
((Colleague)(colleagues.get(0))).method1(); //通过中介者调用同事类的方法
......
}
}
abstract class Colleague {
protected Mediator mediator; //维持一个抽象中介者的引用
public Colleague(Mediator mediator) {
this.mediator=mediator;
}
public abstract void method1(); //声明自身方法,处理自己的行为
//定义依赖方法,与中介者进行通信
public void method2() {
mediator.operation();
}
}
class ConcreteColleague extends Colleague {
public ConcreteColleague(Mediator mediator) {
super(mediator);
}
//实现自身方法
public void method1() {
......
}
}
备忘录模式
备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式。
备忘录模式主要包括三个部分
- 原发器(Originator)角色:状态需要被记录的元对象类,记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
- 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
- 负责人(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
public class Originator {
private String state;
public Originator(){}
// 创建一个备忘录对象
public Memento createMemento() {
return new Memento(this);
}
// 根据备忘录对象恢复原发器状态
public void restoreMemento(Memento m) {
state = m.state;
}
public void setState(String state) {
this.state=state;
}
public String getState() {
return this.state;
}
}
对于备忘录类来说,通常提供了和原发器相对应的属性,用来存储原发器的状态
//备忘录类,默认可见性,包内可见
class Memento {
private String state;
public Memento(Originator o) {
state = o.getState();
}
public void setState(String state) {
this.state=state;
}
public String getState() {
return this.state;
}
}
负责人用来保存备忘录对象,并提供getMemento方法返回一个备忘录对象,原发器可以使用这个备忘录对象回到某个历史状态。
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento=memento;
}
}
观察者模式
状态模式
状态模式就是用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中(用类来表示状态),使得对象状态可以灵活变化。
状态模式包含3个角色:
- Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
- State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
- ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
环境类维持一个对抽象状态类的引用,通过setState()方法可以向环境类注入不同的状态对象,再在环境类的业务方法中调用状态对象的方法
class Context {
private State state; //维持一个对抽象状态对象的引用
private int value; //其他属性值,该属性值的变化可能会导致对象状态发生变化
//设置状态对象
public void setState(State state) {
this.state = state;
}
public void request() {
//其他代码
state.handle(); //调用状态对象的业务方法
//其他代码
}
}
abstract class State {
//声明抽象业务方法,不同的具体状态类可以不同的实现
public abstract void handle();
}
class ConcreteState extends State {
public void handle() {
//方法具体实现代码
}
}
策略模式
在软件开发的过程中,实现某一功能可能有许多途径,每一条途径对应一种算法,此时我们可以使用一种设计模式来灵活的选择解决途径,这种设计模式就叫策略模式
策略模式主要包括三个部分
-
Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
-
Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
-
ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
abstract class AbstractStrategy {
public abstract void algorithm(); //声明抽象算法
}
class ConcreteStrategyA extends AbstractStrategy {
//算法的具体实现
public void algorithm() {
//算法A
}
}
class Context {
private AbstractStrategy strategy; //维持一个对抽象策略类的引用
public void setStrategy(AbstractStrategy strategy) {
this.strategy= strategy;
}
//调用策略类中的算法
public void algorithm() {
strategy.algorithm();
}
}
模板方法模式
在操作中定义算法的框架,将一些步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。
主要包括两个部分:
- 抽象父类:定义一个算法所包含的所有步骤,并提供一些通用的方法逻辑。
- 具体子类:继承自抽象父类,根据需要重写父类提供的算法步骤中的某些步骤。
public abstract class AbstractClassTemplate {
public void step1(String key) {
System.out.println("模板----->执行步骤1");
if (step2(key)) {
step3();
} else {
step4();
}
step5();
}
private void step5() {
System.out.println("模板----->执行步骤5");
}
private boolean step2(String key) {
System.out.println("模板----->执行步骤2");
if ("x".equals(key)) {
return true;
} else {
return false;
}
}
public abstract void step3();
public abstract void step4();
public void run(String key){
step1(key);
}
}
public class ConcreteClassA extends AbstractClassTemplate{
@Override
public void step3() {
System.out.println("在子类A中------->执行步骤3");
}
@Override
public void step4() {
System.out.println("在子类A中------->执行步骤4");
}
}
当多个类有相同的方法并且逻辑可以共用时,就可以抽象出一个模板方法出来,其实就是一种继承的体现
访问者模式
访问者模式包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。例如处方单中的各种药品信息就是被访问的元素,而划价人员和药房工作人员就是访问者。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。
主要有以下几个角色;
●Vistor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。
●ConcreteVisitor(具体访问者):具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素。
●Element(抽象元素):抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。
●ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。
abstract class Visitor
{
public abstract void visit(ConcreteElementA elementA);
public abstract void visit(ConcreteElementB elementB);
public void visit(ConcreteElementC elementC)
{
//元素ConcreteElementC操作代码
}
}
class ConcreteVisitor extends Visitor
{
public void visit(ConcreteElementA elementA)
{
//元素ConcreteElementA操作代码
}
public void visit(ConcreteElementB elementB)
{
//元素ConcreteElementB操作代码
}
}
interface Element
{
public void accept(Visitor visitor);
}
class ConcreteElementA implements Element
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
public void operationA()
{
//业务方法
}
}