JS设计模式之单例模式、组合模式、观察者模式、策略模式

关于JS中的设计模式与单例模式的介绍,在上一篇博客中做了介绍,详情见:JS设计模式及单例模式


好,下面我将结合一些实例,说一下我对组合模式以及观察者模式的了解:

1、组合模式:

  • 组合模式在对象间形成树形结构;
  • 组合模式中基本对象和组合对象被一致对待;
  • 无须关心对象有多少层, 调用时只需在根部进行调用;
  • 将多个对象的功能,组装起来,实现批量执行

想象我们现在手上有个万能遥控器, 当我们回家, 按一下开关, 下列事情将被执行:

  • 到家了,开门
  • 开电脑
  • 开音乐
// 先准备一些需要批量执行的功能
class GoHome{
    init(){
        console.log("到家了,开门");
    }
}
class OpenComputer{
    init(){
        console.log("开电脑");
    }
}
class OpenMusic{
    init(){
        console.log("开音乐");
    }
}

// 组合器,用来组合功能
class Comb{
    constructor(){
        // 准备容器,用来防止将来组合起来的功能
        this.skills = [];
    }
    // 用来组合的功能,接收要组合的对象
    add(task){
        // 向容器中填入,将来准备批量使用的对象
        this.skills.push(task);
    }
    // 用来批量执行的功能
    action(){
        // 拿到容器中所有的对象,才能批量执行
        this.skills.forEach( val => {
            val.init();
        } );
    }
}

// 创建一个组合器
var c = new Comb();

// 提前将,将来要批量操作的对象,组合起来
c.add( new GoHome() );
c.add( new OpenComputer() );
c.add( new OpenMusic() );

// 等待何时的时机,执行组合器的启动功能
c.action();
    // 在内部,会自动执行所有已经组合起来的对象的功能

由此,我们可以总结一下组合模式的特点

1.批量执行
2.启动一个方法,会遍历多个方法,同时执行,有点类似于递归的感觉
3.组合模式略微耗性能,但是执行方便
 目前只是一个基础组合。
 高级组合:
1.组合成树状结构,每个对象下,还会有自己的子对象
2.如果执行了父对象的某个方法,所有的子对象会跟随执行
3.组合模式一般建议使用在动态的html结构上,因为组合模式的结构和html的结构,出奇的一致
4.基本对象和组合对象被一致对待, 所以要保证基本对象(叶对象)和组合对象具有一致方法

2、观察者模式:

  • 观察者模式也叫也叫Observer模式、订阅/发布模式,也是由GoF提出的23种软件设计模式的一种
  • 观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态,或者说执行对应对象的方法(主题数据改变,通知其他相关个体,做出相应的数据更新)。
  • 这种设计模式可以大大降低程序模块之间的耦合度,便于更加灵活的扩展和维护。
  • 观察的角度,发现对应的状况,处理问题。
  • 观察者模式包含两种角色:
    观察者(订阅者):会随时更新自身的信息或状态(订阅者可以随时加入或离开);
    被观察者(发布者):接收到发布者发布的信息,从而做出对应的改变或执行。
  • 很方便的实现简单的广播通信,实现一对多的对应关系。
  • 核心思想:观察者只要订阅了被观察者的事件,那么当被观察者的状态改变时,被观察者会主动去通知观察者,而无需关心观察者得到事件后要去做什么,实际程序中可能是执行订阅者的回调函数。
  • Javascript中实现一个例子:
// 我们向某dom文档订阅了点击事件,当点击发生时,他会执行我们传入的callback
element.addEventListener("click", callback, false)
element.addEventListener("click", callback, false)
  • 简单的例子:
// 模拟事件监听式处理事件的过程
// 需要一个观察者(班主任),创建一个事件容器(小本本),并准备on等方法(如何操作小本本)...
function Observer(){
this.msg = {};
}
// 向小本本中添加事件,消息
Observer.prototype.on = function(type, cb){
// 判断小本本中,有没有当前传进来的这个类型
// 如何没有,走else
if(this.msg[type]){
    // 如果有,直接给第一次设置的这个数组,添加个新数据
    this.msg[type].push(cb);
}else{
    // 给他设置一个对应的属性,同时,属性值需要提前写成数组
    this.msg[type] = [cb];
}
}
Observer.prototype.emit = function(type){
// 首先判断小本本中是不是已经记录
if(this.msg[type]){
    var event = {
        type:type
    }
    // 如果已经记录了信息,那么就去执行这个消息对应的所有的处理函数
    this.msg[type].forEach(val=>{
        val.call(this,event);
    })
}
}
Observer.prototype.off = function(type, cb){
// 首先判断小本本中是不是已经记录
if(this.msg[type]){
    // 准备保存符合传参的处理函数的索引
    var i = 0;
    // 遍历,判断,当前类型对应的每一个处理函数,依次作比较
    var onoff = this.msg[type].some((val, idx)=>{
        i = idx;
        return val === cb;
    })
    // 判断是否获取到重复的函数
    if(onoff){
        // 如果有,那么就在当前的消息处理函数的队列中,删除这个函数
        this.msg[type].splice(i, 1);
    }
}
}

// 首先创建一个观察者对象
var ob = new Observer();
// 准备两个处理函数
function a(){
console.log("找来谈话");
console.log(this);
}
function b(){
console.log("叫来家长");
}

// 随便绑定一个消息,给了两个处理函数
ob.on("早恋",a);
ob.on("早恋",b);

// 模拟事件的执行
ob.emit("早恋");

// 删除一个处理函数
ob.off("早恋", b);

// 模拟事件的执行
ob.emit("早恋");

var obj = {
    data: {
    list: []
      },
 }
 // defineProperty 可以观察 obj对象 的list 属性的使用
  Object.defineProperty(obj, 'list', {
       get() {
          console.log('获取了list 属性');
          console.log(this.data['list']);
          return this.data['list'];
      },
   		set(val) {
                console.log('值被更改了')this.data['list'] = val;
        }
   })
// 获取了list属性,那么get 方法就会被调用
console.log(obj.list);
// 设置了list属性set 方法就会被调用
obj.list = ['a', 'b'];

注意:观察者模式中,需要执行的内容存储在消息盒子中;on方法 , 添加要执行的操作;emit , 发布执行操作;off , 删除执行的操作。

3、策略模式:

策略模式的定义:定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。也就是:给出多个计划,当将来发生某种状态时,执行对应的计划。

  • 策略模式的目的就是将算法的使用算法的实现分离开来。
  • 一个基于策略模式的程序至少由两部分组成。
    第一个部分是一组策略类(可变),策略类封装了具体的算法,并负责具体的计算过程。
    第二个部分是环境类Context(不变),Context接受客户的请求,随后将请求委托给某一个策略类。要做到这一点,说明Context中要维持对某个策略对象的引用。
  • 简单的例子:
/*策略类*/
var test = {
    "A": function (money) {
        return money + 6;
    },
    "B": function (money) {
        return money + 4;
    },
    "C": function (money) {
        return money + 2;
    }
};
/*环境类*/
var calculateBouns = function (level, money) {
    return test[level](money);
};
console.log(calculateBouns('A', 6)); // 12
console.log(calculateBouns('B', 6)); // 10
console.log(calculateBouns('C', 6)); // 8

策略模式的优点:

  • 策略模式是封装了一个充满各种算法的对象,这些算法可以供各种对象使用,可以供给给任何条件判断。
  • 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句,即策略模式可以有效避免很多if条件语句。
  • 策略模式符合开放——封闭原则,使代码更容易理解和扩展。
  • 策略模式中的代码可以复用。

你可能感兴趣的:(JavaScript,设计模式)