js里的职责链模式

职责链模式

职责链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

该模式类似于调用原型方法一样:在该对象没有该方法时向上一个原型上寻找方法;该模式这是该方法无法处理这个请求时,用下一个方法处理该请求,这样形成一个链,每个方法都有可能被调用。

这里用一个表单验证做例子:

btn.addEventListener("click", function (event) {
    if (input.value.length == 0) {
        console.log("这里要输入东西");
    } else {
        if (Number.isNaN(+input.value)) {
            console.log("这里是数字");
            if (input.value.length < 3) {
                console.log("这里要三个以上数字");
            }
        }
    }
});

可以看到代码可读性很差,如果用职责链模式来重构:

function checkEmpty() {
    if (input.value.length == 0) {
        console.log("这里要输入东西");
    }
    return "next";
}
function checkNumber() {
    if (Number.isNaN(+input.value)) {
        console.log("这里是数字");
    }
    return "next";
}
function checkLength() {
    if (input.value.length < 3) {
        console.log("这里要三个以上数字");
    }
    return "next";
}

class Chain {
    constructor(fn) {
        this.checkRule = fn;
        this.nextRule = null;
    }
    addRule(nextRule) {
        this.nextRule = nextRule;
    }
    check() {
        this.checkRule() == "next" ? this.nextRule.check() : null;
    }
}

const isEmpty = new Chain(checkEmpty);
const isNumber = new Chain(checkNumber);
const isLength = new Chain(checkLength);

const check = new Chain(() => "next");
check.addRule(isEmpty);
isEmpty.addRule(isNumber);
isNumber.addRule(isLength);
isLength.addRule({ check: () => "end" });

btn.addEventListener("click", () => {
    check.check();
});

现在代码可读性变强了,但是很明显变得相当庞大,并且每个链上的函数都得返回一个相同的“next”,这里用装饰模式稍微修改一下代码,做成链式调用:

function checkEmpty() {
    if (input.value.length == 0) {
        console.log("这里要输入东西");
    }
}
function checkNumber() {
    if (Number.isNaN(+input.value)) {
        console.log("这里是数字");
    }
}
function checkLength() {
    if (input.value.length < 3) {
        console.log("这里要三个以上数字");
    }
}

class Chain {
    constructor(fn) {
        this.checkRule = fn ?? (() => "next");
        this.nextRule = null;
    }
    addRule(nextRule) {
        this.nextRule = new Chain(() => (nextRule(), "next"));
        return this.nextRule;
    }
    end() {
        this.nextRule = { check: () => "end" };
    }
    check() {
        this.checkRule() == "next" ? this.nextRule.check() : null;
    }
}

const checks = new Chain();
checks.addRule(checkEmpty).addRule(checkNumber).addRule(checkLength).end();

这样,代码的可读性更好,并且如果要在规则之间添加新规则,也只需要在调用链里新增而已:

function checkSum() {
    const result = Array.prototype.reduce.call(
        input.value,
        (result, now) => {
            return (result += +now);
        },
        0
    );
    if (result !== 10) {
        console.log("和必须为10");
    }
}

const checks = new Chain();
checks.addRule(checkEmpty).addRule(checkNumber).addRule(checkSum).addRule(checkLength).end();

热门相关:无量真仙   第一神算:纨绔大小姐   薄先生,情不由己   大神你人设崩了   横行霸道