设计模式系列之行为性模式

84 阅读3分钟

欢迎访问我的博客

介绍

对在不同的对象之间划分责任和算法的抽象化,行为型模式不仅仅关注类和对象的结构,而且重点关注他们之间的相互作用,通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互

模板方法模式

定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个 算法的结构即可重定义该算法的某些特定步骤

这个主要用在基类,比如你可以把公共的方法写进一个基类,这样就不需要重复实现功能了

abstract class AbstractClass {
    constructor() { }
    // 模板方法
    public template(): void {
        this.operation1();
        this.hookMethod() && this.operation2();
        this.operation3();
    }
    protected operation1(): void {
        console.log('使用了方法operation1');
    }
    protected operation2(): void {
        console.log('使用了方法operation2');
    }
    protected operation3(): void {
        console.log('使用了方法operation3');
    }
    // 钩子方法
    protected hookMethod(): boolean {
        return true;
    }
}

class ConcreteClassA extends AbstractClass {
    protected operation2(): void {
        console.log('对该方法operation2进行了修改再使用');
    }

    protected operation3(): void {
        console.log('对该方法operation3进行了修改再使用');
    }
}

class ConcreteClassB extends AbstractClass {
    // 覆盖钩子方法
    protected hookMethod(): boolean {
        return false;
    }
}

function main() {
    const class1: AbstractClass = new ConcreteClassA();
    const class2: AbstractClass = new ConcreteClassB();

    class1.template();
    class2.template();
}

main();

命令模式

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求 排或者记录请求日志,可以提供命令的撤销和恢复功能

interface Command {
    execute(): void;
    undo(): void;
}

// 开启命令
class ConcreteCommandOn implements Command {
    private receiver: Receiver;
    constructor(receiver: Receiver) {
        this.receiver = receiver;
    }

    // 执行命令的方法
    public execute(): void {
        this.receiver.actionOn();
    }

    // 撤销命令的方法
    public undo(): void {
        this.receiver.actionOff();
    }
}

// 关闭命令
class ConcreteCommandOff implements Command {
    private receiver: Receiver;
    constructor(receiver: Receiver) {
        this.receiver = receiver;
    }

    // 执行命令的方法
    public execute(): void {
        this.receiver.actionOff();
    }

    // 撤销命令的方法
    public undo(): void {
        this.receiver.actionOn();
    }
}

// 空命令(省去判空操作)
class NoCommand implements Command {
    public execute(): void { }
    public undo(): void { }
}

class Receiver {
    public actionOn(): void {
        console.log('我是命令接收者,开启了某动作');
    }
    public actionOff(): void {
        console.log('我是命令接收者,关闭了某动作');
    }
}

class Invoker {
    private onCommands: Array<Command>;
    private offCommands: Array<Command>;
    private undoCommand: Command;
    private slotNum: number = 7;
    constructor() {
        this.undoCommand = new NoCommand();
        this.onCommands = [];
        this.offCommands = [];

        for (let i = 0; i < this.slotNum; i++) {
            this.onCommands[i] = new NoCommand();
            this.offCommands[i] = new NoCommand();
        }
    }

    public setCommand(index: number, onCommand: Command, offCommand: Command): void {
        this.onCommands[index] = onCommand;
        this.offCommands[index] = offCommand;
    }

    // 开启
    public on(index: number): void {
        this.onCommands[index].execute();// 调用相应方法
        //记录这次操作,用于撤销
        this.undoCommand = this.onCommands[index];
    }

    // 关闭
    public off(index: number): void {
        this.offCommands[index].execute();
        this.undoCommand = this.offCommands[index];
    }

    // 撤销
    public undo(): void {
        this.undoCommand.undo();
    }
}

function main() {
    // 创建接收者
    const receiver: Receiver = new Receiver();

    // 创建命令
    const commandOn: Command = new ConcreteCommandOn(receiver);
    const commandOff: Command = new ConcreteCommandOff(receiver);

    // 创建调用者
    const invoker: Invoker = new Invoker();
    invoker.setCommand(0, commandOn, commandOff);

    invoker.on(0);
    invoker.off(0);
    invoker.undo();
}

main();

策略模式

定义一组算法,将每个算法都封装起来,并且使他们之间可以互换

这个主要用在写测试类的时候,比如有8种排序算法,每次只需要改变当前的策略,即可实现相应的测试检查

interface Strategy {
    // 策略模式运算法则
    doSomething(): void;
}

class ConcreteStrategy1 implements Strategy {
    public doSomething(): void {
        console.log('使用的策略1');
    }
}

class ConcreteStrategy2 implements Strategy {
    public doSomething(): void {
        console.log('使用的策略2');
    }
}

class ContextofStrategy {
    private _strategy: Strategy;
    constructor(strategy: Strategy) {
        this._strategy = strategy;
    }

    set strategy(strategy: Strategy) {
        this._strategy = strategy;
    }

    //封装后的策略方法
    doOperation(): void {
        this._strategy.doSomething();
    }
}

function main() {
    const strategy1: Strategy = new ConcreteStrategy1();
    const strategy2: Strategy = new ConcreteStrategy2();
    const context: ContextofStrategy = new ContextofStrategy(strategy1);
    context.doOperation();
    context.strategy = strategy2;
    context.doOperation();
}

main();

观察者模式

这个也是一个比较流行的模式,比如跟事件类有关的类。通过某一个事件,触发对该事件订阅的模型发生数据变化。

比如在一个游戏框架中,键盘和鼠标事件的触发,会使得全局订阅者集合中相对应的事件的订阅者触发自己的行为事件

又比如在mvvm模型中,Object.defineProperty中通过set方法调用的时候,会触发所有订阅这的更新

interface Observer {
    update(): void;
}

// 观察者模式
interface AbstractSubject {
    // 注册订阅者
    registerObserver(observer: Observer): void;
    remove(observer: Observer): void;
    // 通知订阅者,让每个订阅者调用自己的update方法
    notifyObservers(): void;
}

class ConcreteSubject implements AbstractSubject {
    private observers: Array<Observer>;

    constructor() {
        this.observers = [];
    }

    public registerObserver(observer: Observer): void {
        this.observers.push(observer);
    };

    public remove(observer: Observer): void {
        const observerIndex = this.observers.findIndex(value => {
            return value == observer;
        })

        observerIndex >= 0 && this.observers.splice(observerIndex, 1);
    };

    public notifyObservers(): void {
        this.observers.forEach(observer => observer.update())
    };
}

class ConcreteObserver1 implements Observer {
    public update(): void {
        console.log('已经执行更新操作1,值为');
    }
}
class ConcreteObserver2 implements Observer {
    public update(): void {
        console.log('已经执行更新操作2,值为');
    }
}

// 发布订阅模式
interface Publish {
    registerObserver(eventType: string, subscribe: Subscribe): void;
    remove(eventType: string, subscribe?: Subscribe): void;
    notifyObservers(eventType: string): void;
}

interface SubscribesObject {
    [key: string]: Array<Subscribe>
}

class ConcretePublish implements Publish {
    private subscribes: SubscribesObject;

    constructor() {
        this.subscribes = {};
    }

    registerObserver(eventType: string, subscribe: Subscribe): void {
        if (!this.subscribes[eventType]) {
            this.subscribes[eventType] = [];
        }

        this.subscribes[eventType].push(subscribe);
    }

    remove(eventType: string, subscribe?: Subscribe): void {
        const subscribeArray = this.subscribes[eventType];
        if (subscribeArray) {
            if (!subscribe) {
                delete this.subscribes[eventType];
            } else {
                for (let i = 0; i < subscribeArray.length; i++) {
                    if (subscribe === subscribeArray[i]) {
                        subscribeArray.splice(i, 1);
                    }
                }
            }
        }
    }

    notifyObservers(eventType: string, ...args: any[]): void {
        const subscribes = this.subscribes[eventType];
        if (subscribes) {
            subscribes.forEach(subscribe => subscribe.update(...args))
        }
    }
}

interface Subscribe {
    update(...value: any[]): void;
}

class ConcreteSubscribe1 implements Subscribe {
    public update(...value: any[]): void {
        console.log('已经执行更新操作1,值为', ...value);
    }
}
class ConcreteSubscribe2 implements Subscribe {
    public update(...value: any[]): void {
        console.log('已经执行更新操作2,值为', ...value);
    }
}

function main() {
    const publish = new ConcretePublish();
    const subscribe1 = new ConcreteSubscribe1();
    const subscribe2 = new ConcreteSubscribe2();

    publish.registerObserver('1', subscribe1);
    publish.registerObserver('2', subscribe2);

    publish.notifyObservers('2', '22222');
}

main();