JavaScript设计模式之观察者模式实例详解

JavaScript设计模式之观察者模式实例详解

概述

观察者模式是一种行为型设计模式,它定义对象之间的一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都将得到通知并自动更新。观察者模式能够使我们建立松散耦合关系,从而提高系统的灵活性和可维护性。

实现

在JavaScript中,观察者模式的实现主要依靠两个对象:被观察的对象和观察者对象。被观察的对象负责维护一个观察者列表,而观察者对象则通过订阅这个列表中的被观察的对象,从而接收这个对象的状态更新通知。

下面是一个简单的实现示例:

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

  registerObserver(observer) {
    if (!this.observers.includes(observer)) {
      this.observers.push(observer);
    }
  }

  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
      this.observers.splice(index, 1);
    }
  }

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

class Observer {
  constructor(subject, name) {
    this.subject = subject;
    this.name = name;
  }

  update() {
    console.log(`${this.name} received a notification.`);
  }

  subscribe() {
    this.subject.registerObserver(this);
  }

  unsubscribe() {
    this.subject.removeObserver(this);
  }
}

在上面的代码中,Subject类代表被观察的对象,Observer类代表观察者对象。Subject类中定义了observers数组属性,表示观察者列表,以及registerObserverremoveObservernotifyObservers方法,分别用于添加观察者、移除观察者和通知所有观察者。

Observer类中定义了subject属性,表示观察的对象,以及name属性,表示观察者的名字。update方法表示观察者接收到更新通知后的回调函数。subscribeunsubscribe方法分别用于在被观察的对象中添加和移除当前观察者。

下面是一个使用示例:

const subject = new Subject();

const observer1 = new Observer(subject, 'Observer 1');
const observer2 = new Observer(subject, 'Observer 2');

observer1.subscribe();
observer2.subscribe();

subject.notifyObservers();

observer1.unsubscribe();

subject.notifyObservers();

在上面的代码中,首先创建了一个Subject对象,然后创建了两个Observer对象。接着,分别对两个观察者对象调用subscribe方法,将它们添加到被观察的对象中。然后,调用Subject对象的notifyObservers方法,通知所有观察者。最后,移除一个观察者后再次调用notifyObservers方法。

示例说明

快递追踪实例

一个典型的应用场景是快递追踪。假设有一个快递公司管理系统,其中有一个快递追踪模块,用户可以订阅自己的快递进度。当快递状态发生变化时,订阅者将收到通知。

class Express {
  constructor() {
    this.observers = [];
    this.state = 'pending';
  }

  registerObserver(observer) {
    if (!this.observers.includes(observer)) {
      this.observers.push(observer);
    }
  }

  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
      this.observers.splice(index, 1);
    }
  }

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

  setState(state) {
    this.state = state;
    this.notifyObservers();
  }
}

class User {
  constructor(name) {
    this.name = name;
  }

  update(express) {
    console.log(`${this.name} received a notification: ${express.state}`);
  }

  subscribe(express) {
    this.express = express;
    this.express.registerObserver(this);
  }

  unsubscribe() {
    this.express.removeObserver(this);
  }
}

const express = new Express();

const user1 = new User('User 1');
user1.subscribe(express);

const user2 = new User('User 2');
user2.subscribe(express);

express.setState('shipping');

user1.unsubscribe();

express.setState('delivered');

在上面的代码中,Express类代表快递追踪状态,User类代表订阅者。Express类中新增了setState方法,用于设置快递状态并通知所有订阅者。User类中的update方法接收到快递状态更新通知后,将状态显示为指定的提示信息。subscribeunsubscribe方法分别用于添加和移除当前订阅者。

Web 音乐播放器实例

另一个应用场景是 Web 音乐播放器。假设有一个用户目录页面,其中有一个音乐播放器组件,用户点击页面中的音乐时,在播放器中展示该音乐。

class MediaPlayer {
  play() {}

  pause() {}

  seek() {}

  stop() {}
}

class MusicPlayer extends MediaPlayer {
  constructor() {
    super();
    this.observers = [];
    this.currentMusic = null;
    this.isPlaying = false;
  }

  registerObserver(observer) {
    if (!this.observers.includes(observer)) {
      this.observers.push(observer);
    }
  }

  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
      this.observers.splice(index, 1);
    }
  }

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

  play(music) {
    if (this.isPlaying) {
      this.stop();
    }

    console.log(`Now playing ${music.name} by ${music.artist}.`);

    this.currentMusic = music;
    this.isPlaying = true;
    this.notifyObservers();
  }

  pause() {
    console.log(`Paused ${this.currentMusic.name}.`);
    this.isPlaying = false;
    this.notifyObservers();
  }

  seek(time) {
    console.log(`Seeked to ${time} seconds.`);
    this.notifyObservers();
  }

  stop() {
    console.log(`Stopped ${this.currentMusic.name}.`);
    this.currentMusic = null;
    this.isPlaying = false;
    this.notifyObservers();
  }
}

class MusicList {
  constructor(musics) {
    this.musics = musics;
  }

  render() {
    const container = document.querySelector('#music-list');

    this.musics.forEach(music => {
      const button = document.createElement('button');
      button.innerText = music.name;
      button.addEventListener('click', () => this.playMusic(music));
      container.appendChild(button);
    });
  }

  playMusic(music) {
    this.musicPlayer.play(music);
  }
}

class MusicInfo {
  constructor() {
    this.container = document.querySelector('#music-info');
  }

  update(musicPlayer) {
    const music = musicPlayer.currentMusic;
    const isPlaying = musicPlayer.isPlaying;

    if (isPlaying) {
      this.container.innerText = `正在播放 ${music.name} - ${music.artist} [${music.duration}]`;
    } else {
      this.container.innerText = '当前未播放任何音乐';
    }
  }
}

const musics = [
  {
    name: 'Song 1',
    artist: 'Artist 1',
    duration: '3:23',
  },
  {
    name: 'Song 2',
    artist: 'Artist 2',
    duration: '4:12',
  },
  {
    name: 'Song 3',
    artist: 'Artist 3',
    duration: '2:51',
  },
];

const musicPlayer = new MusicPlayer();
const musicList = new MusicList(musics);
musicList.musicPlayer = musicPlayer;
musicList.render();

const musicInfo = new MusicInfo();
musicPlayer.registerObserver(musicInfo);

在上面的代码中,MusicPlayer类代表音乐播放器,MusicList类代表音乐列表,MusicInfo类代表音乐信息展示组件。MusicPlayer类中除了实现playpauseseekstop等基本方法外,还定义了registerObserverremoveObservernotifyObservers方法,用于实现观察者模式。MusicList类中的render方法根据音乐列表渲染出一个按钮列表,并通过playMusic方法调用MusicPlayer对象的play方法。MusicInfo类中的update方法接收到音乐状态更新通知后,将状态显示在 HTML 元素上。

最后,在页面加载完成后,实例化音乐播放器对象、音乐列表对象和音乐信息展示组件对象,并将音乐信息展示组件对象订阅到音乐播放器对象中。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript设计模式之观察者模式实例详解 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • 使用nodejs实现JSON文件自动转Excel的工具(推荐)

    使用Node.js实现JSON文件自动转Excel的工具是一件非常实用的任务。下面是详细的攻略: 1. 准备工作:安装相关工具 在开始处理工具的制作之前,要先安装相关的工具: Node.js:在开始使用Node.js之前,需要先安装Node.js(https://nodejs.org/en/)。Node.js是一个JavaScript的运行环境,可以在服务器…

    node js 2023年6月8日
    00
  • node.js http模块概念详解

    可以的,以下是关于“node.js http模块概念详解”的攻略: 什么是Node.js的http模块? Node.js提供了一个核心模块http,用于创建Web服务器和处理HTTP请求和响应。 如何使用http模块创建服务器? 要使用http模块创建Web服务器,需要执行以下步骤: 首先,需要引入http模块。 const http = require(‘…

    node js 2023年6月8日
    00
  • express框架+bootstrap美化ejs模板实例分析

    下面我将为你详细讲解“express框架+bootstrap美化ejs模板实例分析”的完整攻略。 一、概述 Express框架是Node.js项目开发的常用框架之一,它提供了一个简单、灵活的Web应用程序开发框架,可以帮助你快速搭建自己的Web应用。Bootstrap是一套优秀的前端框架,它包括了HTML、CSS以及JavaScript工具,可以非常方便地用…

    node js 2023年6月8日
    00
  • 基于NodeJS的前后端分离的思考与实践(一)全栈式开发

    首先,我们需要明确什么是前后端分离。前后端分离指的是将前端和后端的代码分离开来,前端和后端通过API进行交互,实现数据交互和页面渲染。这种模式的优点是使前后端分别负责自己的领域,提高了代码的可维护性和可扩展性。 接下来,我们讲解一下如何基于NodeJS进行前后端分离开发。 一、选择前端框架 首先,我们需要选择前端框架。目前比较流行的前端框架有React、An…

    node js 2023年6月8日
    00
  • 利用node.js开发cli的完整步骤

    利用node.js开发CLI,一般分为以下几个步骤: 步骤一:创建项目 首先,我们需要创建一个新的npm项目,可以通过命令行执行以下代码: mkdir my-cli cd my-cli npm init 其中,npm init命令会引导你创建一个新的package.json文件,其中包含项目的名称、版本等信息。在这个过程中,你可以自定义项目的名称、版本等信息…

    node js 2023年6月8日
    00
  • nodeJs爬虫获取数据简单实现代码

    下面是关于“nodeJs爬虫获取数据简单实现代码”的完整攻略。 1. 前言 在讲解具体实现方法之前,我们需要了解一下什么是爬虫及其应用场景。 1.1 什么是爬虫 爬虫是指按照一定的规则自动从互联网上抓取信息的程序,也称网络爬虫、网络机器人。其工作模式基本上类似于人工去浏览网页,寻找信息,但爬虫可以在很短时间内处理大量信息。 1.2 爬虫的应用场景 在互联网上…

    node js 2023年6月8日
    00
  • egg.js的基本使用和调用数据库的方法示例

    下面为你详细讲解egg.js的基本使用和调用数据库的方法示例: 1. egg.js的基本使用 1.1 egg.js简介 Egg.js是阿里出品的一款Node.js框架,它基于Koa.js,致力于企业级应用开发。 Egg.js具有插件化机制,通过插件的方式为开发者提供了一系列开箱即用的基础设施。同时,Egg.js具有比Koa.js更高的扩展性、更完善的文档和更…

    node js 2023年6月8日
    00
  • Node.js使用对话框ngDialog的示例代码

    Node.js是一个基于Chrome浏览器V8引擎的JavaScript后端运行环境,它具有事件驱动、非阻塞I/O的特点,适用于高并发、实时应用。而ngDialog是一款基于AngularJS实现的弹窗插件,它提供了简单易用、高度定制的UI界面解决方案,方便应用程序开发。 本文将详细讲解如何在Node.js中使用ngDialog的示例代码,过程中包含两个示例…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部