编程 三种常用的行为设计模式:策略模式、观察者模式和命令模式

2024-11-19 05:17:20 +0800 CST views 609

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

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

策略模式

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

主要组成部分

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

优点

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

缺点

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

应用场景

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

示例

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

观察者模式

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

主要组成部分

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

优点

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

缺点

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

应用场景

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

示例

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 extends 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

命令模式

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

主要组成部分

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

优点

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

缺点

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

应用场景

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

示例

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.

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

复制全文 生成海报 软件开发 设计模式 编程 JavaScript 算法

推荐文章

Linux 网站访问日志分析脚本
2024-11-18 19:58:45 +0800 CST
Vue中如何使用API发送异步请求?
2024-11-19 10:04:27 +0800 CST
Web浏览器的定时器问题思考
2024-11-18 22:19:55 +0800 CST
Go 协程上下文切换的代价
2024-11-19 09:32:28 +0800 CST
js函数常见的写法以及调用方法
2024-11-19 08:55:17 +0800 CST
如何在 Vue 3 中使用 TypeScript?
2024-11-18 22:30:18 +0800 CST
Vue3的虚拟DOM是如何提高性能的?
2024-11-18 22:12:20 +0800 CST
pip安装到指定目录上
2024-11-17 16:17:25 +0800 CST
PHP openssl 生成公私钥匙
2024-11-17 05:00:37 +0800 CST
Go语言中实现RSA加密与解密
2024-11-18 01:49:30 +0800 CST
利用图片实现网站的加载速度
2024-11-18 12:29:31 +0800 CST
go发送邮件代码
2024-11-18 18:30:31 +0800 CST
一键配置本地yum源
2024-11-18 14:45:15 +0800 CST
CSS Grid 和 Flexbox 的主要区别
2024-11-18 23:09:50 +0800 CST
前端代码规范 - Commit 提交规范
2024-11-18 10:18:08 +0800 CST
实用MySQL函数
2024-11-19 03:00:12 +0800 CST
联系我们
2024-11-19 02:17:12 +0800 CST
一个简单的html卡片元素代码
2024-11-18 18:14:27 +0800 CST
liunx宝塔php7.3安装mongodb扩展
2024-11-17 11:56:14 +0800 CST
16.6k+ 开源精准 IP 地址库
2024-11-17 23:14:40 +0800 CST
20个超实用的CSS动画库
2024-11-18 07:23:12 +0800 CST
微信内弹出提示外部浏览器打开
2024-11-18 19:26:44 +0800 CST
php获取当前域名
2024-11-18 00:12:48 +0800 CST
使用Rust进行跨平台GUI开发
2024-11-18 20:51:20 +0800 CST
程序员茄子在线接单