行为模式

责任链

使多个对象都有机会处理请求,避免发送者与接受者之间的耦合

屏幕截图 2021-05-27 093547

public interface Filter {

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
}
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //...
    }
}

在GOF的书中描述的责任链每个节点都有一个后继节点,前驱节点可根据特定的逻辑来将请求传递到后继节点来进行处理,代表着一种责任的转移。

另外一种责任链的变体模式:

  1. 引入一个责任链实体,即责任链节点编排器:
public class Chain {
    void process(){
        for(var chainNode : chain) {
            if (!chainNode.process()) {
                break;
            }
        }
    }
}
  1. 责任链节点可通过传回一个布尔值或者抛出异常来终止整个流程。

这种方式的问题在于无法实现类似于Web Filter的对Response的过滤处理。上述的Filter可以在后继Filter处理完毕后回来处理后继Filter处理过的Response,而通过引入一个第三方编排校色的方式则无法实现。

命令

将请求封装为对象

该模式解耦了调用请求的对象与知道如何处理该请求的对象

202164142850 202164145026

interface Command {
    void execute();
}
class ConcreteCommand1 implements Command {
    Reveiver reveiver;
    void execute() {
        reveiver.action(); // do something
    }
}
class ConcreteCommand2 implements Command {...}

class Invoker {
    void invoke(){
        Command command;
        command.execute();
    }
}

在该模式的实现中,一个很重要的一点是可以考虑在Invoker记录该命令的操作历史,定义另外一个接口unexecute 来实现对命令撤销。

解释器

定义一个文法,定义一个解释器,解释器解释执行做一些操作

classDiagram
    Context <.. AbstractExpression
    class AbstractExpression {
        +interpret(Context ctx)
    }
    class TerminalExpression {
        +interpret(Context ctx)
    }
    class NoneTerminalExpression {
        +interpret(Context ctx)
    }
    AbstractExpression <|-- TerminalExpression
    AbstractExpression <|-- NoneTerminalExpression
    Client ..> Context
    Client ..> AbstractExpression

迭代器

提供一种顺序访问对象中的各个元素,并不暴露内部表示

classDiagram
    class Container {
        +getIterator()
    }
    class Iterator {
        +next()
        +hasNext()
    }
    Container <|-- ConcreteContainer
    Iterator <|-- ConcreteIterator
    ConcreteContainer --> ConcreteIterator: 拥有
interface Iterator{
    hasNext();
    next();
}
class ArrayListItr implements Iterator{...}

中介者

用一个中介对象封装一系列对象之间的交互

classDiagram
    Mediator <-- Colleague
    Mediator <|-- ConcreteMediator
    Colleague <|-- ConcreteColleague
    ConcreteMediator --> ConcreteColleague

备忘录

不破坏封装性的情况下,保存一个对象的内部状态

classDiagram
    class Originator {
        +State
        +SetMemento(m: Memento)
        +CreateMemento()
    }
    class Memento {
        +State
    }
    class CareTaker {
        -Memento: Memento
    }
    Originator ..> Memento
    CareTaker o--> Memento

观察者

定义对象间一对多的依赖关系,依赖它的对象都会得到通知并自动更新

classDiagram
    class Subject {
        +add(ob Observer)
        +del(ob Observer)
        +notify()
    }
    class Observer {
        +update()
    }
    Subject --> Observer
    Subject <|-- ConcreteSubject
    Observer <|-- ConcreteObserver
abstract class Subject{
    add(Observer ob);
    del(Observer ob);
    notify();
}
interface Observer{
    update();
}
class ConcreteSubject{
    notify(){
        obServerlist.forEachNotify();
    }
}
class ConcreteObserver implements Observer{
    ...
}

状态

允许一个对象在其内部状态改变时改变它的行为

屏幕截图 2020-08-06 134707

class LoginContext{
    private UserState state;
    login(){
        state.login()
    }
}
interface UserState{
    login();
}
class UserNormalState{
    login(){
        if (loginFailCount == 5){
            context.state = new UserBannedState();
        }
        print "login success";
    }
}
class UserBannedState{
    login(){
        print "you are banned";
    }
}

策略模式

封装一系列算法,以使它们可以互相替换

202153110326

interface Strategy{
    void execute(..);
}

class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    void execute(){
        strategy.execute(..);
    }
}

class StrategyA implements Strategy{
    // 具体实现
}
// 使用
Context context = new Context(new StrategyA());
context.execute();

策略模式要求客户代码必须了解不同策略模式的差异,也就是客户必须针对具体实现进行编码。

另外一个要考虑的是不同策略所需要的参数不同,虽然可以一股脑将全部参数传递给具体策略,但为了降低性能开销,某些策略并不需要用到那么多参数,此时可以传递一个Context的引用给具体策略,让具体策略按需索取,但这种方式则对Context接口的粒度做了过细的要求。

组合模式 + 策略模式

可以通过组合多个策略得到一个新的策略:

class CompositeStrategy implements Strategy{
    void execute(){
        StrategyA...
        StrategyB...
    }
}

模板方法

在父类当中定以算法骨架,将一些步骤延迟到子类当中实现

实现一些操作时,整体步骤很固定,但是呢。就是其中一小部分容易变,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现

classDiagram
    class AbstractClass {
        +process1()
        +process2()
        +templateMethod()
    }
    class ConcreteClass1 {
        +process1()
        +process2()
    }
    class ConcreteClass2 {
        +process1()
        +process2()
    }
    AbstractClass <|-- ConcreteClass1
    AbstractClass <|-- ConcreteClass2
    Client --> AbstractClass
abstract class BaseAlgorithm{
    void process(){
        process1();
        process2();
    }
    abstract void process1();
    abstract void process2();
}
class ConcreteAlgorithm extends BaseAlgorithm{
    // 实现方法
}
// 使用
BaseAlgorithm algorithm = new ConcreteAlgorithm();
algorithm.process();

访问者

表示一个作用于对象结构中的各元素的操作

识图避免新功能的引入造成接口的修改

屏幕截图 2021-06-15 161411

class Visitor {
    visit(ElementA);
    visit(ElementB);
}
class VisitorA extends Visitor {
    visit(ElementA){...}
    visit(ElementB){...}
}
class VisitorB extends Visitor {
    visit(ElementA){...}
    visit(ElementB){...}
}
class Element{
    accept(Vistor);
}
class ElementA extends Element {
    accept(Vistor) {
        Visitor.visit(this)
    }
}
...

访问者设计模式提出的根本原因是为了在不修改类的前提下 增加类的行为。

在这里,当需要增加新的行为时,就将新增一个具体的Vistor 然后传递给响应的Element。

该模式适合在对象数据结构稳定,不会变更且经常需要定义新操作的场景下使用。