JS 的行为设计模式:策略、观察者与命令模式

JS 的行为设计模式:策略、观察者与命令模式

在软件开发中,设计模式是解决特定问题的通用解决方案。行为设计模式专注于对象之间的通信和职责分配。本文将介绍三种常用的行为设计模式:策略模式、观察者模式和命令模式,以及它们的主要组成部分、工作原理、优缺点和应用场景。

策略模式

策略模式允许在运行时选择算法或行为,从而使得算法的变化独立于使用算法的客户。它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。

主要组成部分

  1. 策略接口(Strategy):定义所有支持的算法或策略的统一接口。
  2. 具体策略(Concrete Strategy):实现策略接口,封装具体的算法或行为。
  3. 上下文(Context):持有策略对象的引用,并通过该策略对象调用具体的算法。

优点

  • 灵活性:可以在运行时选择不同的策略。
  • 可扩展性:可以轻松添加新的策略。
  • 单一职责:每个策略类只负责实现一种算法。

缺点

  • 策略数量增加可能导致类的数量增加。
  • 客户端需要了解不同策略的具体实现。

应用场景

  • 需要使用多种算法的场景。
  • 避免使用大量的条件语句。
  • 动态选择算法。

示例

javascript 复制代码
class Strategy {
    execute(a, b) {
        throw new Error("This method should be overridden!");
    }
}

class AddStrategy extends Strategy {
    execute(a, b) {
        return a + b;
    }
}

class SubtractStrategy extends Strategy {
    execute(a, b) {
        return a - b;
    }
}

class Context {
    constructor(strategy) {
        this.strategy = strategy;
    }

    setStrategy(strategy) {
        this.strategy = strategy;
    }

    executeStrategy(a, b) {
        return this.strategy.execute(a, b);
    }
}

const context = new Context(new AddStrategy());
console.log(context.executeStrategy(5, 3)); // 输出: 8

context.setStrategy(new SubtractStrategy());
console.log(context.executeStrategy(5, 3)); // 输出: 2

观察者模式

观察者模式定义了对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都能够自动收到通知并更新。

主要组成部分

  1. 主题(Subject):维护观察者的列表,并在状态变化时通知所有注册的观察者。
  2. 观察者(Observer):定义更新接口,以便在主题状态变化时接收通知。
  3. 具体主题(Concrete Subject):实现主题接口,维护状态并在状态变化时通知观察者。
  4. 具体观察者(Concrete Observer):实现观察者接口,定义对主题状态变化的具体响应。

优点

  • 松耦合:主题和观察者之间的关系是松散的。
  • 动态关系:可以在运行时添加或移除观察者。
  • 自动更新:观察者能够自动接收通知。

缺点

  • 通知开销:如果观察者数量较多,状态变化时的通知开销可能较大。
  • 顺序问题:观察者的通知顺序可能影响程序的行为。

应用场景

  • 事件处理系统。
  • 数据绑定。
  • 消息推送系统。
  • 股票市场监控。
  • 社交媒体通知。
  • 游戏开发。
  • 日志系统。
  • 天气监测系统。

示例

javascript 复制代码
class Subject {
    constructor() {
        this.observers = [];
    }

    registerObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }

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

class Observer {
    update(subject) {
        throw new Error("This method should be overridden!");
    }
}

class Display implements Observer {
    update(subject) {
        console.log(`Temperature updated: ${subject.getTemperature()}°C`);
    }
}

class WeatherStation extends Subject {
    constructor() {
        super();
        this.temperature = 0;
    }

    setTemperature(temp) {
        this.temperature = temp;
        this.notifyObservers(); // 通知所有观察者
    }

    getTemperature() {
        return this.temperature;
    }
}

const weatherStation = new WeatherStation();
const display = new Display();

weatherStation.registerObserver(display);
weatherStation.setTemperature(25); // 输出: Temperature updated: 25°C

命令模式

命令模式将请求封装为对象,允许使用不同的请求、队列请求或日志请求,以及支持可撤销操作。

主要组成部分

  1. 命令接口(Command):定义统一的接口,通常包含一个 execute 方法。
  2. 具体命令(Concrete Command):实现命令接口,封装具体的操作和接收者。
  3. 接收者(Receiver):包含执行请求的具体方法。
  4. 调用者(Invoker):持有命令对象并在适当的时候调用命令的 execute 方法。
  5. 客户端(Client):创建具体命令对象并设置接收者。

优点

  • 解耦:请求的发送者与接收者之间的解耦。
  • 可扩展性:可以轻松添加新的命令。
  • 支持撤销/重做:可以通过保存命令的历史记录来实现撤销和重做功能。

缺点

  • 命令类数量增加:每个具体命令都需要一个类。
  • 复杂性:对于简单的请求,使用命令模式可能显得过于复杂。

应用场景

  • 图形用户界面(GUI)。
  • 撤销/重做功能。
  • 任务调度。
  • 日志记录。
  • 远程控制。
  • 宏命令。
  • 游戏开发。
  • 网络请求。

示例

javascript 复制代码
class Command {
    execute() {
        throw new Error("This method should be overridden!");
    }
}

class LightOnCommand extends Command {
    constructor(light) {
        super();
        this.light = light;
    }

    execute() {
        this.light.turnOn();
    }
}

class LightOffCommand extends Command {
    constructor(light) {
        super();
        this.light = light;
    }

    execute() {
        this.light.turnOff();
    }
}

class Light {
    turnOn() {
        console.log("The light is on.");
    }

    turnOff() {
        console.log("The light is off.");
    }
}

class RemoteControl {
    constructor() {
        this.command = null;
    }

    setCommand(command) {
        this.command = command;
    }

    pressButton() {
        if (this.command) {
            this.command.execute();
        }
    }
}

const light = new Light();
const lightOn = new LightOnCommand(light);
const lightOff = new LightOffCommand(light);
const remote = new RemoteControl();

remote.setCommand(lightOn);
remote.pressButton(); // 输出: The light is on.

remote.setCommand(lightOff);
remote.pressButton(); // 输出: The light is off.

通过这些设计模式,开发者可以构建更加灵活、可扩展和可维护的软件系统。每种模式都有其特定的应用场景和优缺点,选择合适的模式可以有效地解决特定的设计问题。

-- 欢迎点赞、关注、转发、收藏【我码玄黄】,各大平台同名。

相关推荐
暗黑起源喵4 分钟前
设计模式-工厂设计模式
java·开发语言·设计模式
王哲晓11 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
理想不理想v16 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云26 分钟前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
aPurpleBerry1 小时前
JS常用数组方法 reduce filter find forEach
javascript
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x2 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
我血条子呢3 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
半开半落3 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt