Zhengrenzhe

(°∀°)ノ 老打杂了

用户工具

站点工具


设计模式:模式:责任链模式

责任链模式(Chain-of-responsibility pattern)

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.

责任链模式,顾名思义,该模式中有一条“链”,就像链表一样。在一个系统中,可以有多个不同的逻辑来处理同一种对象。那么具体是由那种逻辑来处理,一般是根据对象上的某一表示标识,例如这样的代码:

enum State {
    START,
    PROCESSING,
    END
}

abstract class ItemCls {
    abstract state: State;
}

class Item extends ItemCls {
    constructor(public state: State) {
        super();
    }
}

function process(item: ItemCls) {
    if (item.state === State.START) {
        console.log('start logic');
        return;
    }

    if (item.state === State.PROCESSING) {
        console.log('processing logic');
        return;
    }

    if (item.state === State.END) {
        console.log('end logic');
        return;
    }
}

process(new Item(State.START));
process(new Item(State.PROCESSING));
process(new Item(State.END));

在process过程中,我们根据item的state属性判断使用哪种逻辑。上面的代码并没有使用责任链模式,对于这种简单的需求,单纯的使用条件判断就好,如果强行使用责任链,那就是过度设计了。

那么到底什么是责任链模式?责任链是一种对于一长串处理过程的抽象,就像下面这样:

如果满足logic A的条件,则logic A处理,否则交给下一个处理逻辑,如此不断执行,直到责任链结束,那么上面的代码使用责任链模式就可以这么改写:

enum State {
    START,
    PROCESSING,
    END
}

abstract class ItemCls {
    abstract state: State;
}

class Item extends ItemCls {
    constructor(public state: State) {
        super();
    }
}


abstract class Logic {
    private next: Logic = null;

    handle(item: ItemCls) {
        if (this.getHandleLevel() === item.state) {
            this.response(item);
        } else {
            this.next.handle(item);
        }
    }

    setNext(next: Logic) {
        this.next = next;
    }

    abstract getHandleLevel(): State;
    abstract response(item: ItemCls): void;
}

class LogicA extends Logic {
    getHandleLevel() {
        return State.START
    }

    response(item: ItemCls) {
        console.log('start logic');
    }
}

class LogicB extends Logic {
    getHandleLevel() {
        return State.PROCESSING
    }

    response(item: ItemCls) {
        console.log('process logic');
    }
}

class LogicC extends Logic {
    getHandleLevel() {
        return State.END
    }

    response(item: ItemCls) {
        console.log('end logic');
    }
}

const logicA = new LogicA();
const logicB = new LogicB();
const logicC = new LogicC();

logicA.setNext(logicB);
logicB.setNext(logicC);

logicA.handle(new Item(State.START));
logicA.handle(new Item(State.PROCESSING));
logicA.handle(new Item(State.END));

在上面的代码中,根据抽象类Logic创建了不同的实体类Logic,每个实体Logic只需要实现getHandleLevel与response方法即可。在代码最后,使用抽象类中的setNext方法设定该逻辑的下一条是什么。在最后执行中,从logicA的handle方法开始,如果满足logicA的条件,则logicA工作,否则进入logicB,如果还不满足,则进入最后的logicC。

这样的设计有什么好处?显然在这个例子中看不出来,但在一些复杂的逻辑,并且还涉及多个系统的处理逻辑,责任链模式就有其用武之地了,典型的就是注册逻辑。

下面是一个复杂的注册逻辑:

  1. 输入邮箱、密码注册
  2. 验证邮箱
  3. 输入手机号
  4. 验证手机号
  5. 绑定信用卡
  6. 注册成功

这一长串流程,显然不是一个函数加多个条件判断就能处理的了的,并且他还包含了多个异步系统之间的协同工作。而且用户在执行到某一步时中断了,重新注册时还要恢复到上次处理的逻辑。

在这个系统中,每一步都会产生一个不同的状态,那么使用责任链模式就可以清晰的定义和解耦上面的处理流程,使整个系统的可维护性增强,而且每段逻辑都是互不依赖的,每个责任只需要关心自己的一亩三分地。

但责任链模式也不是万能的,从代码的微观角度来说,责任链模式就是一个链表,那么一个逻辑很可能就得从头至尾遍历才能得到真正的结果,这有可能会导致性能问题。当然你也可以将链式结构改造成哈希表结构,那么整个系统就会从链向状态机转移。由于链条变长,调试也可能会变得麻烦。所以实际应用中,最好限制责任链的最大长度。

设计模式/模式/责任链模式.txt · 最后更改: 2020/03/05 14:00 由 zhengrenzhe