设计模式的总结及观察者模式和订阅者模式区别?

设计模式

设计模式是一种在特定情境下解决问题的标准化方法。他描述了一个问题及该问题的解决方案,并且提供了一种重用这一解决方案的方式。设计模式就是一种解决在某个特定情境下问题的指导思想。

设计模式的类别:

  • 创建型模式:关注对象的创建方式。
  • 结构型模式:关注于如何组合类或对象形成更大的结构。
  • 行为型模式:关注于对象间的职责分配和通信。

1.创建型模式(对象)

1.1 单例模式

  • 定义:确保一个类只有一个实例,并提供一个全局访问点。

  • 应用场景:配置管理、日志记录、浏览器窗口对象等。

  • 示例代码

    const singleton = (function(){
      let instance
      function createInstance(){
        return {
            counter : 0, 
            incrementCounter: function(){
               this.counter++
           }
        }
      }
    
      return {
        getInstance: function(){
          if(!instance){
            instance = createInstance()
          }
          return instance
        }
      }
    })()
    const instance = singleton.getInstance()
    instance.incrementCounter()
    instance.incrementCounter()
    instance.incrementCounter()
    console.log(instance.counter); // 3
    

1.2 工厂模式

  • 定义:定义一个创建产品对象的接口,让子类决定实例化哪一个类。创建单一类型的对象。

  • 应用场景:组件创建、模块加载等。

  • 示例代码:

    class ProductA{
      constructor(color, size){
        this.color = color
        this.size = size
      }
      printProduct(){
        console.log(`这个产品的颜色是${this.color},大小是${this.size}`);
      }
    }
    class ProductB{
      constructor(color, size){
        this.color = color
        this.size = size
      }
      printProduct(){
        console.log(`这个产品的颜色是${this.color},大小是${this.size}`);
      }
    
    }
    
    function createProduct(type){
      switch(type){
        case "A" : return new ProductA('pink','medium')
        case "B" : return new ProductB('black', 'big')
        default:
          throw new Error('Invalid product type')
      }
    }
    const product = createProduct('A')
    product.printProduct(); // 这个产品的颜色是pink,大小是mediu 
    

1.3 抽象工厂模式

  • 定义:提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。创建一系列相关的对象产品。

  • 应用场景:多主题样式管理、UI组件库等。

  • 示例代码

    class AbatractFactory{
      createButton(){}
      createInput(){}
    }
    class ModernButton{
      constructor(color, size){
        this.color = color
        this.size = size
      }
      printProduct(){
        console.log(`这个产品的颜色是${this.color},大小是${this.size}`);
      }
    }
    class ModernInput{
      constructor(color, size){
        this.color = color
        this.size = size
      }
      printProduct(){
        console.log(`这个产品的颜色是${this.color},大小是${this.size}`);
      }
    }
    
    
    class ModernFactory extends AbatractFactory{
      createButton(){
        return new ModernButton('blue','small')
      }
      createInput(){
        return new ModernInput()
      }
    }
    
    const modelFactory = new ModernFactory()
    const createButton = modelFactory.createButton()
    createButton.printProduct(); // 这个产品的颜色是blue,大小是small
    

2.结构型模式:(组合类或对象)

2.1 适配器模式

  • 定义:允许一个类接口与另一个不兼容的类接口协同工作。

  • 应用场景:第三方库集成、跨框架组件复用等。

  • 示例代码

    class ThitdPartyComponent{
      constructor(name){
        this.name = name
      }
      specificRequest(){
        return '第三方库'
      }
    }
    
    class Adapter extends ThitdPartyComponent{
      constructor(name){
        super(name)
      }
      request(){
        return `Adapter: (translated) ${this.specificRequest()}`
      }
    }
    
    const adapter = new Adapter('继承name')
    console.log(adapter.name);
    console.log(adapter.request());
    

2.2 装饰器模式

  • 定义:动态地给一个对象添加一些额外的职责。

  • 应用场景:权限控制、日志记录等。

  • 示例代码

    /* 
    2.2 装饰器模式
    定义:动态地给一个对象添加一些额外的职责。
    应用场景:权限控制、日志记录等。
    */
    
    function Component(){
      // console.log(this);
      this.operation = function(){
        console.log('Concrete component');
      }
    }
    
    function Decorator(component){
      this.component = component
    }
    
    // Decorator的原型指向 Object.create(Component.prototype)这个对象,并且这个对象继承Component.prototype
    // 让 Decorator 的原型继承自 Component.prototype 
    Decorator.prototype = Object.create(Component.prototype)
    // console.log(Decorator);
    // Decorator原型上添加 operation 方法
    Decorator.prototype.changeOperation = function(){
      // 调用继承来自Component 对象身上的operation方法
      console.log(this);
      this.component.operation()
      console.log('Decorator');
    }
    const component = new Component()
    const decorator = new Decorator(component)
    component.operation() // Concrete component
    // decorator.operation() // 报错
    decorator.changeOperation()
    

2.3 组合模式

  • 定义:将对象组合成树形结构以表示“部分-整体”的层次结构。

  • 应用场景:文件系统、UI组件树等。

  • 示例代码:

    class Component {
      constructor(name) {
        this.name = name
      }
      add(component) { }
      remove(component) { }
      display(level) { }
    }
    
    class Leaf extends Component {
      display(level) {
        console.log(`Leaf的display`, level);
        console.log(`${" ".repeat(level * 2)} Leaf:${this.name}`);
      }
    }
    
    class Composite extends Component {
      constructor(name) {
        super(name)
        this.children = []
      }
    
      add(component) {
        this.children.push(component)
      }
      remove(component) {
        const index = this.children.indexOf(component)
        if (index > -1) {
          this.children.splice(index, 1)
        }
      }
    
      display(level) {
        console.log("Composite的display", level);
        // " ".repeat(level * 2),缩进空格
        console.log(`${" ".repeat(level * 2)} Composite: ${this.name}`);
        this.children.forEach(child => child.display(level + 1))
      }
    }
    
    const root = new Composite('root')
    const branch1 = new Composite('branch1') // 生成一级分支: branch1
    const branch2 = new Composite('branch2') // 生成二级分支: branch2
    root.add(branch1)
    root.add(branch2)
    
    branch1.add(new Leaf('leaf1'))
    branch1.add(new Leaf('leaf2'))
    branch2.add(new Leaf('leaf3'))
    branch2.add(new Leaf('leaf4'))
    console.log(JSON.stringify(root));
    root.display(0)
    
    // 生成的树结构为:
    // const rootNode = {
    //   "name": "root",
    //   "children": [
    //     { "name": "branch1", "children": [{ "name": "leaf1" }, { "name": "leaf2" }] },
    //     { "name": "branch2", "children": [{ "name": "leaf3" }, { "name": "leaf4" }] }]
    // }
    

3.行为型模式(对象间的职责分配和通信)

3.1 观察者模式

  • 定义:定义对象间的一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

  • 应用场景:事件处理、状态监测等。

  • 示例代码:

    class Subject{
      constructor(){
        this.observers = [] // 存储每一个订阅者observer,使用对象的依赖
      }
    
      addObserver(observer){
        this.observers.push(observer)
      }
    
      removeObserver(observer){
        const index = this.observers.indexOf(observer)
        if(index > -1){
          this.observers.splice(index, 1)
        }
      }
    
      notify(data){
        this.observers.forEach(observer => observer.update(data))
      }
    }
    
    class Observer{
      update(data){
        console.log(`Observer recived: ${data}`);
      }
    }
    
    const subject = new Subject()
    const observer1 = new Observer()
    const observer2 = new Observer()
    subject.addObserver(observer1)
    subject.addObserver(observer2)
    
    subject.notify('hello, observers!') // 打印两边: Observer recived: hello, observers!
    

3.2 策略模式

  • 定义:定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。

  • 应用场景:支付方式选择、排序算法等。

  • 示例代码:

    class Strategy{
      // 执行函数
      execute(data){
        throw new Error('Method not implemented')
      }
    }
    
    class ConcreteStrategyA extends Strategy{
      execute(data){
        return `Sorting with strategy A: ${data.sort().join(',')}`
      }
    }
    class ConcreteStrategyB extends Strategy{
      execute(data){
        return `Sorting with strategy B: ${data.reverse().join(',')}`
      }
    }
    
    class Context{
      constructor(strategy){
        this.strategy = strategy
      }
    
      setStrategy(strategy){
        this.strategy = strategy
      }
    
      executeStratety(data){
        return this.strategy.execute(data)
      }
    }
    // 实例化context,使用策略一
    const context = new Context(new ConcreteStrategyA())
    console.log(context.executeStratety([3,5,6,1,8]));
    
    // 使用另外一种策略
    context.setStrategy(new ConcreteStrategyB())
    console.log(context.executeStratety([3,5,6,1,8]));
    

3.3命令模式

  • 定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

  • 应用场景:UI按钮操作、命令行工具等。

  • 示例代码

    class Command{
      constructor(receiver){
        this.receiver = receiver
      }
      // 执行办法,子类继承说明具体的办法
      execute(){}
    }
    // 具体的命令
    class ConcreteCommand extends Command{
      execute(){
        this.receiver.action()
      }
    }
    
    // 接收方
    class Receiver{
      // 行为操作
      action(){
        console.log(`Receiver: Action executed`);
      }
    }
    // 用具体命令对象,触发命令执行的对象
    class Invoker{
      constructor(){
        this.commands = []
      }
    
      takeCommand(command){
        this.commands.push(command)
      }
    
      placeCommands(){
        this.commands.forEach(command => command.execute())
      }
    }
    const invoker = new Invoker()
    const receiver1 = new Receiver()
    const receiver2 = new Receiver()
    
    const concreteCommand1 = new ConcreteCommand(receiver1)
    const concreteCommand2  = new ConcreteCommand(receiver2)
    invoker.takeCommand(concreteCommand1)
    invoker.takeCommand(concreteCommand2)
    invoker.placeCommands() // Receiver: Action executed
    

4.实战案例

4.1 案例1:单例模式(确保一个类只有一个实例,并提供一个全局访问点)

背景:实现一个全局的配置管理器。
实现:使用闭包和构造函数相结合的方式创建单例。
应用场景:前端项目中的配置管理、全局事件监听等。
// 闭包封装私有变量和构造函数
function createConfigManager(){
    let instance = null
    let configs = {}

    // 构造函数
   function configManager(){
        if(instance){
            return instance
        }
        instance = this // 实例为当前this指向
   }

   configManager.prototype = {
        // 添加配置项
        setConfig: function(key, value){
            configs[key] = value
        },
        // 获取配置项
        getConfig: function(key){
            return configs[key]
        },
        // 删除配置项
        removeConfig:  function(key){
            delete configs[key]
        }
   }
   return function getInstance(){
    return new configManager()
   }
}
  
const getConfigManager = createConfigManager();  

// 使用示例: 返回一个实例
const manager1 = getConfigManager();  
manager1.setConfig('apiUrl', 'https://api.example.com');  
console.log(manager1.getConfig('apiUrl')); // 输出: https://api.example.com  

const manager2 = getConfigManager();  
console.log(manager1 === manager2); // 输出: true,说明是单例  
manager2.setConfig('theme', 'dark');  
console.log(manager1.getConfig('theme')); // 输出: dark,因为它们是同一个实例  

// 清理或删除配置项  
manager1.removeConfig('apiUrl');  
console.log(manager1.getConfig('apiUrl')); // 输出: undefined,因为该配置项已被删除

4.2 案例2:观察者模式:(定义对象间的一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。)

背景:实现一个简单的事件监听器。
实现:使用数组存储观察者,并在事件触发时遍历执行。
应用场景:DOM事件绑定、自定义事件发布订阅等。
// 创建观察者的类, 每一个观察者都有数据更新的回调函数
class Observer{
    constructor(updateCallback){
        this.update = updateCallback
    }
}

// 一个类,实现当该对象内数据变化,会通知所有用到这个对象的订阅者,进行数据更新
class Subject{
    constructor(){
        this.data = null
        this.obervers = []
    }
    // 订阅事件
    subscribe(observer){
        this.obervers.push(observer)
    }
    // 取消事件
    cancel(oberver){
        const index = this.obervers.indexOf(oberver)
        if(index > -1){
            this.obervers.splice(index, 1)
        }
    }
    // 通知所有订阅者数据已变化 
    notify(newData){
        this.data = newData
        this.obervers.forEach(observer => {
            observer.update(newData)
        })
    }
    // 设置数据并通知所有订阅者 
    setData(newData){
        // 通知每个订阅者
        this.notify(newData)
    }
}

// 实例化数据对象
const subject = new Subject()
const observer1 = new Observer((newData) => {
    // 可以对新数据进行处理
    console.log(`Observer 1 received new data: ${newData}`);
})
const observer2 = new Observer((newData) => {
    // 可以对新数据进行处理
    console.log(`observer 2 received new data: ${newData}`);
})

subject.subscribe(observer1)
subject.subscribe(observer2)
subject.setData('Initial data') // Observer 1 received new data: Initial data observer 2 received new data: Initial data

// 取消订阅者2
subject.cancel(observer2)
subject.setData('set newData') // Observer 1 received new data: set newData

观察者模式和发布订阅模式?

观察者模式

目标者和观察者对象相互依赖,观察者对某个对象的状态进行观察,当对象的状态发生变化的时候,通知所有依赖这个对象的观察者。目标提供维护观察者的提供一系列方法,观察者提供更新方法,观察者把自己注册到具体目标中去,当目标发生变化,调用观察者提供的方法进行更新。

举个例子:

比如有个天气中心的具体目标A,监听天气变化,同时有个显示天气界面的观察者B,B就会把自己注册到A中,当A中触发了天气变化事件,就会调用B中的更新方法,然后界面就会进行更新。

在这里插入图片描述

  • 目标者对象【Suject】:拥有方法:【删除、添加、通知】Observer;
    • subs数组:存储所有的观察者;
    • addSub():添加观察者;
    • notify():当目标对象状态发生变化后调用所有观察者的update()方法。
  • 观察者对象【Observer】:拥有方法:接受Subject状态变更通知并进行对应的处理。
    • update():当数据对象发生变化时,具体要做的事情。
// 目标者(发布者)
class Subject {
    constructor () {
        // 记录所有的订阅者
        this.subs = []
    }
    // 添加订阅者
    addSub (sub) {
        if (sub && sub.update) {
            this.subs.push(sub)
        }
    }
    // 发布通知
    notify () {
        this.subs.forEach(sub => {
            sub.update()
        })
    }
}
// 观察者(订阅者)
class Watcher {
    update () {
        console.log('update')
    }
}

// 测试一下 
let dep = new Subject()
let watcher = new Watcher()
let watcher1 = new Watcher()
// 添加订阅
dep.addSub(watcher)
dep.addSub(watcher1)
// 开启通知
dep.notify()

发布订阅模式

基于一个事件中心,接受通知的对象是订阅者,需要先订阅某个事件,触发事件的对象是发布者,发布者通过触发事件,通知各个订阅者。发布者将消息发布到特定的消息队列或主题中,而订阅者可以订阅这些消息队列或主题以接收和处理消息。发布者和订阅者之间的通信是异步的,这意味着发布者发布消息后,订阅者可以在任何时候接收和处理消息。

举个例子:

订阅公众号。公众号(事件中心),订阅公众号的大家(订阅者),维护这个公众号的作者(发布者),当发布者发布新的文章后,订阅者能够通过公众号平台接收到消息。

在这里插入图片描述

class PubSub {
    constructor() {
        this.subscribers = {}
    }
    subscribe(type, fn) {
        if (!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
            this.subscribers[type] = [];
        }

        this.subscribers[type].push(fn);
    }
    unsubscribe(type, fn) {
        let listeners = this.subscribers[type];
        if (!listeners || !listeners.length) return;
        this.subscribers[type] = listeners.filter(v => v !== fn);
    }
    publish(type, ...args) {
        let listeners = this.subscribers[type];
        if (!listeners || !listeners.length) return;
        listeners.forEach(fn => fn(...args));
    }
}

let ob = new PubSub();
ob.subscribe('add', (val) => console.log(val));
ob.publish('add', '哈哈哈哈 触发了add事件');
ob.subscribe('logInfo', (msg) => console.log(msg));
ob.publish('logInfo', '消息很重要!');

观察者模式和发布订阅模式的区别

相同点:

  • 一对多的依赖关系:在这两种模式中,多个观察者/订阅者都依赖于一个单一的主体(发布者或被观察对象)。
  • 解耦:这两种模式都提供了一种将发送者和接收者解耦的方式。发送者不需要知道接收者的具体信息,接收者只需知道如何响应接收到的消息或通知。
  • 动态更新:都允许当主体变化时动态地通知所有依赖者,使它们能自动更新自己的状态或处理信息。

不同点:

  • 实现机制:
    • 观察者模式处理的消息,消息数据的生产方和消费方都要和消息对象本身紧密关联。观察者模式是基于数据对象本身的;
    • 发布订阅模式跟消息对象本身没有紧密的关系,而是通过一个调度中心传递消息。发布订阅模式是基于主题或者消息队列的
  • 耦合度:
    • 观察者模式中,被观察对象通常持有观察者的引用,因此耦合度相对较高
    • 发布/订阅模式通过使用消息队列或事件总线,减少了发布者和订阅者之间的直接依赖,因而耦合度较低
  • 应用场景:
    • 观察者模式多用于实现单一应用程序中的同步更新;例如,GUI应用程序中视图与数据模型的更新。
    • 发布/订阅模式适用于异步消息传递场景,如跨应用程序或跨服务的消息通信,尤其是在分布式系统中。
  • 异步处理:
    • 在观察者模式中,被观察者对观察者的更新通常是同步进行的,也就是说,当一个观察者被通知时,必须等待这个观察者处理完成后才能继续进行下去。
    • 发布/订阅模式中,发布者发布消息后不需要等待订阅者处理,订阅者可以异步接收并处理消息,这有利于提高系统的响应能力和吞吐量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值