《JavaScript设计模式与开发实践》之常见设计模式

学习设计模式的过程,就是一个积累经验的过程,可能学完后里面的代码在具体工作中根本用不上,但它们可以在你遇到问题时提供一些灵感思路,帮助你更好的解决问题。

几种常用的设计模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

应用场景:当一些组件或方法我们只需要一个时,例如当我们点击登陆按钮时,会弹出登陆浮窗,而这个登陆浮窗是唯一的,无论点击多少次登陆按钮,这个浮窗都只会被创建一次,那么这个登陆浮窗就适合用单例模式创建。

实现:用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下次获取该类的实例时,直接返回之前创建的对象

var Singleton=function(){
     this.name=name;
     this.instance=null;
}
Singleton.getInstance=function(){
    if(!this.instance){//确保单例
      this.instance=new Singleton(name)
    }
    return this.instance;
}
策略模式:为实现同一功能,定义一系列的算法,把他们一个个封装到策略类内部方法里,根据需要调用策略类中的某一个进行计算

应用场景:以年终奖计算为例,年终奖是根据员工的工资基数和年底绩效来发的,比如:绩效为S的人年终奖有4倍工资,A有3倍,B有2倍
实现:

var strategies={//策略对象(类)
  "S":function(salary){//绩效等级及年终奖计算函数
        return salary*4;
  },
  "A":function(salary){
      return salary*3;
  },
  "B":function(salary){
      return salary*2;
  }
}
var calculateBonus=function(level,salary){
      return strategies[level](salary);
}
console.log(calculateBonus('S',20000)); //输出:80000
发布-订阅模式(又称观察者模式):它定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都将得到通知

应用场景:发布订阅模式广泛应用于异步编程(如响应式编程库Rxjs)
示例:

//发布者
class Subject {
    constructor() {
        this.observerCollection = [];
    }
    addObserver(observer) { // 添加观察者
        this.observerCollection.push(observer);
    }
    
    deleteObserver(observer) { // 移除观察者
        let index = this.observerCollection.indexOf(observer);
        if(index >= 0) this.observerCollection.splice(index, 1);
    }
    
    notifyObservers() { // 通知观察者
        this.observerCollection.forEach((observer)=>observer.notify());
    }
}
//观察者
class Observer {
    constructor(name) {
        this.name = name;
    }
    
    notify() {
        console.log(`${this.name} has been notified.`);
    }
}
//应用
let subject = new Subject(); // 创建发布对象

let observer1 = new Observer('semlinker'); // 创建观察者A - 'semlinker'
let observer2 = new Observer('lolo'); // 创建观察者B - 'lolo'

subject.addObserver(observer1); // 注册观察者A
subject.addObserver(observer2); // 注册观察者B
 
subject.notifyObservers(); // 通知观察者

subject.deleteObserver(observer1); // 移除观察者A
命令模式:

命令模式是最简单和优雅的模式之一,命令模式中的命令(command)指的是一个执行某些特定事情指令(或方法)
应用场景:有时候需要向某些对象发送请求,但不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求的发送者和接受者能够消除彼此的耦合关系
示例:

    var setCommand=function(func){//指令发送者
        func()
    }
    var MenuBar={//指令接受对象
        refresh:function(){
            console.log('刷新页面');
        }
    }
    var RefreshMenuBarCommand=function(receiver){
        return function(){
            receiver.refresh();
        }
    }
    var refreshMenuBarCommand=RefreshMenuBarCommand(MenuBar);
    setCommand(refreshMenuBarCommand);//发送指令
组合模式:用一系列叶对象构建一个大的组合对象,用户只要执行组合对象的方法,就能依次执行每个叶对象的方法

示例:

/*
*宏命令
*组合模式和命令模式联用产物
*/
    //三个叶对象
var closeDoorCommand={
    execute:function(){
        console.log('关门');
    }
}
var openPcCommand={
    execute:function(){
        console.log('开电脑');
    }
}
var loginQQCommand={
    execute:function(){
        console.log('登录qq');
    }
}
var MarcoCommand=function(){
    return {
        commandList:[],
        add:function(command){
            this.commandList.push(command);
        },
        execute:function(){
            this.commandList.forEach(function(command){
                command.execute();
            })
        }
    }
}
var marcoCommand=MarcoCommand();//组合对象
marcoCommand.add(closeDoorCommand);
marcoCommand.add(openPcCommand);
marcoCommand.add(loginQQCommand);

marcoCommand.execute();// 依次输出 开门   开电脑   登录qq

注意:
1、组合模式中的组合对象和叶对象不是父子关系,而是一种聚合关系(HAS-A)
2、对叶对象的操作必须具有一致性。如假设公司全体员工构成了一个组合对象,公司元旦要给全体员工发过节费1000元,这个场景可以用组合模式,但如果公司给今天过生日的员工发一封生日祝福邮件,组合模式就无用户之地了。

你可能感兴趣的:(《JavaScript设计模式与开发实践》之常见设计模式)