javascript设计模式-行为型模式

观察者模式、发布/订阅模式、迭代器模式、职责链模式、委托模式、策略模式、中介者模式、模版方法模式、命令模式、备忘录模式、状态模式、访问者模式、解释器模式

1. 观察者模式
  • 它定义了对象间的一种一对多的依赖关系,只要当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题
let observer_ids=0;
let observed_ids=0;
//观察者类
class Observer {
   constructor() {
      this.id = observer_ids++;
   }
   //观测到变化后的处理
   update(ob){
      console.log("观察者" + this.id + `-检测到被观察者${ob.id}变化`);
   }
}
//被观察者列
class Observed {
   constructor() {
      this.observers = [];
      this.id=observed_ids++;
   }
   //添加观察者
   addObserver(observer) {
      this.observers.push(observer);
   }
   //删除观察者
   removeObserver(observer) {
      this.observers = this.observers.filter(o => {
         return o.id != observer.id;
      });
   }
   //通知所有的观察者
   notify(ob) {
      this.observers.forEach(observer => {
         observer.update(ob);
      });
   }
}

let mObserved=new Observed();
let mObserver1=new Observer();
let mObserver2=new Observer();

mObserved.addObserver(mObserver1);
mObserved.addObserver(mObserver2);

mObserved.notify();
2. 发布订阅模式
  • 定义一个主体和众多个体,主体为消息中心,里面有各种各样的消息,众多的个体可以订阅不同的消息,当未来中心发布某条消息时,订阅过他的个体就会得到通知。
class eventBus {
  constructor() {
    this.events = new Map()
  }
  subscribe(eventname,fn) {
    let fns = this.events.get(eventname)
    if(!fns){
      fns = []
      fns.push(fn)
      this.events.set(eventname,fns)
    }else {
      fns.push(fn)
    }
  }
  publish(...args) {
    let eventname = args.shift()
    let fns = this.events.get(eventname)
    for(let i = -1; fns[++i];){
      fns[i](args)
    }
  }
}
var eventBus1 = new eventBus()
eventBus1.subscribe(3000,function(data) {
  console.log(data)
})
eventBus1.publish(3000,'发布了一个3000的房子')
3. 迭代器模式
  • 不暴露对象内部结构的同时,可以顺序的访问聚合对象内部的元素
  • 一个迭代器的实现,通常需要实现以下接口
  • next() 查找并返回下一个元素
  • hasNext() 判断迭代是否结束, 返回布尔值
     	class Iterator {
            constructor(container) {
                this.list = container.list
                this.index = 0

            }
            next() {
                if(this.hasNext()) {
                    return this.list[this.index++]
                }
            }
            hasNext() {
                if(this.index >= this.list.length) {
                    return false
                }
                return true
            }

        }
        class Container {
            constructor(list) {
                this.list = list
            }
            // 生成遍历器
            getIterator() {
                return new Iterator(this)
            }
        }

        let container = new Container([1,2,3,4,5,6])
        let iterator = container.getIterator()

        while(iterator.hasNext()) {
            console.log(iterator.next());
        }
4.链模式
  • 链模式是实现链式调用的主要方法,通过在自身方法中返回自身的方法,在一个对象连续多次调用自身方法是可以简化写法。
var obj = {
	a:function(){
		console.log('aaa')
		return this
	}
	b:function(){
		console.log('bbb')
		return this
	}
}
console.log(a.b().c())
5.委托模式
  • 当多个对象需要处理同一请求时,可以将这些请求交由另一个对象同一处理。
<ul>
<li>aaaaaaaaaaaaa<li>
ul>
window.onload = function(){
	var oUl = document.querySelector('ul')
	oUl.onclick=function(e){
		var e = e || window.event
		target = e.target || e.srcElement
		if(target.nodeName.toLowerCase() === 'li'){
			console.log(target.innerHTML)
		}
	}
	var oLi = document.createElement('li')y
	oLi.innerHtml = 'eeee'
	oul.appendchild(oLi)
}
6.策略模式
  • 将算法封装到类里,在使用时,客户端自行选择需要的算法,像STL里封装的sort,find等。
  • 改善前
let calculateBonus = function (level,salary) {
    if(level === 'S')
    {
        return salary*4;
    }
    if(level === 'A')
    {
        return salary*3;
    }
    if(level === 'B')
    {
        return salary*2;
    }
}
calculateBonus('S',10000) //输出40000
calculateBonus('B',10000) //输出20000
  • 改善后:
let strategies = {
    "S" :function(salary) {
        return salary*4
    },
    "A" :function(salary) {
        return salary*3
    },
    "B" :function(salary) {
        return salary*2
    },
    "C" :function(salary) {
        return salary*1
    },
}
// 引用
let calculateBonus = function (level,salary) {
    return strategies[level](salary);
}
calculateBonus('S',20000)//输出80000
7. 中介者模式
  • 与代理模式不同,代理模式是一对一结构中,代替某方与另一方沟通的模式;而中介者模式是一种一对多结构中,作为一个单独的结构,将这种一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
class Olympiad {
  constructor () {
    this.players = []
  }
  join (player) {
    this.players.push(player)
  }
  exit (player) {
    this.players.splice(this.players.findIndex(item=>item.name === player.name), 1)
  }
  getResult () {
    console.log('参赛所有方', this.players)
    this.players.forEach(item => {
      console.log(item.name, item.state)
    })
  }
}

class player {
  constructor (name) {
    this.name = name
    this.state = 'ready'
  }
  lose () {
    this.state = 'lose'
  }
  win () {
    this.state = 'win'
  }
}

const rabbit = new player('兔子')
const bear = new player('北极熊')
const chicken = new player('高卢鸡')
const eagle = new player('白头鹰')
const johnBull = new player('约翰牛')

const olympiad = new Olympiad ()
olympiad.join(rabbit)
olympiad.join(bear)
olympiad.join(chicken)
olympiad.join(eagle)
olympiad.join(johnBull)
olympiad.exit(chicken)

rabbit.win()
bear.win()
eagle.lose()
johnBull.lose()

olympiad.getResult()
8. 模板方法模式
  • 模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
var Beverage = function(){};
Beverage.prototype.boilWater = function(){
    console.log( '把水煮沸' );
};
Beverage.prototype.brew = function(){
    throw new Error( '子类必须重写brew方法' );
};
Beverage.prototype.pourInCup = function(){
    throw new Error( '子类必须重写pourInCup方法' );
};
Beverage.prototype.addCondiments = function(){
    throw new Error( '子类必须重写addCondiments方法' );
};
Beverage.prototype.customerWantsCondiments = function(){
    return true; // 默认需要调料
};
Beverage.prototype.init = function(){
    this.boilWater();
    this.brew();
    this.pourInCup();
    if ( this.customerWantsCondiments() ){ // 如果挂钩返回true,则需要调料
        this.addCondiments();
    }
};
var CoffeeWithHook = function(){};
CoffeeWithHook.prototype = new Beverage();
CoffeeWithHook.prototype.brew = function(){
    console.log( '用沸水冲泡咖啡' );
};
CoffeeWithHook.prototype.pourInCup = function(){
    console.log( '把咖啡倒进杯子' );
};
CoffeeWithHook.prototype.addCondiments = function(){
    console.log( '加糖和牛奶' );
};
CoffeeWithHook.prototype.customerWantsCondiments = function(){
    return window.confirm( '请问需要调料吗?' );
};
var coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.init();
9. 命令模式
  • 命令模式由三种角色构成:
  • 发布者 invoker(发出命令,调用命令对象,不知道如何执行与谁执行);
  • 接收者 receiver (提供对应接口处理请求,不知道谁发起请求);
  • 命令对象 command(接收命令,调用接收者对应接口处理发布者的请求)。
class Receiver {  // 接收者类
  execute() {
    console.log('接收者执行请求');
  }
}

class Command {   // 命令对象类
  constructor(receiver) {
    this.receiver = receiver;
  }
  execute () {    // 调用接收者对应接口执行
    console.log('命令对象->接收者->对应接口执行');
    this.receiver.execute();
  }
}

class Invoker {   // 发布者类
  constructor(command) {
    this.command = command;
  }
  invoke() {      // 发布请求,调用命令对象
    console.log('发布者发布请求');
    this.command.execute();
  }
}

const warehouse = new Receiver();       // 仓库
const order = new Command(warehouse);   // 订单
const client = new Invoker(order);      // 客户
client.invoke();

/*
输出:
  发布者发布请求
  命令对象->接收者->对应接口执行
  接收者执行请求
*/
10. 备忘录模式
  • 备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。
class Memento {
    constructor(content) {
        this.content = content;
    }
 
    getContent() {
        return this.content;
    }
}
 
// 备忘列表
class CarTaker {
    constructor() {
        this.list = [];
    }
 
    add(memento) {
        this.list.push(memento);
    }
 
    get(index) {
        return this.list[index];
    }
 
    getList() {
        return this.list
    }
}
 
// 编辑器
class Editor {
    constructor() {
        this.content = null;
    }
 
    setContent(content) {
        this.content = content;
    }
 
    getContent() {
        return this.content;
    }
 
    saveContentToMemento() {
        return new Memento(this.content);
    }
 
    getConentFromMemento(memento) {
        this.content = memento.getContent();
    }
}
 
// 测试代码
let editor = new Editor()
let careTaker = new CarTaker()
 
editor.setContent('111')
editor.setContent('222')
 
careTaker.add(editor.saveContentToMemento())  // 将当前222内容备份
editor.setContent('333')
careTaker.add(editor.saveContentToMemento())  // 将当前333内容备份
editor.setContent('444')
 
console.log(editor.getContent())
editor.getConentFromMemento(careTaker.get(1)) // 撤销
console.log(editor.getContent())
editor.getConentFromMemento(careTaker.get(0)) // 撤销
console.log(editor.getContent())
11. 状态模式
let HighState = {
  show() {
    console.log('绿色');
  },
}

let MiddleState = {
  show() {
    console.log('黄色');
  }
}

let LowState = {
  show() {
    console.log('红色');
  }
}
let Battery = {
  amount: 'heigh',
  state: HighState,
  // Bettery对象暴露的接口,用于设置对象的状态,并调用状态对象的接口,刷新对应状态的行为
  show() {
    this.setState();
    // 把显示的逻辑委托给状态对象
    this.state.show();
  },
  // 设置Bettery对象的状态,
  setState() {
    let amount = {
      'heigh': () => {
        this.state = HighState;
      },
      'middle': () => {
        this.state = MiddleState;
      },
      'low': () => {
        this.state = LowState;
      }
    }
    amount[this.amount]();
  }
}


Battery.show();
Battery.amount = 'middle';
Battery.show();
Battery.amount = 'low';
Battery.show();
12. 访问者模式
  • 将数据操作和数据结构进行分离
var Visitor = (function () {
  return {
    splice: function () {
      var args = Array.prototype.splice.call(arguments, 1);
      return Array.prototype.splice.apply(arguments[0], args);
    },
    push : function () {
      var len = arguments[0].length || 0;
      var args = this.splice(arguments, 1);
      arguments[0].length = len + arguments.length - 1;
      return Array.prototype.push.apply(arguments[0], args);
    },
    pop: function () {
      return Array.prototype.pop.apply(arguments[0]);
    }
  }
})();

var a = {};
Visitor.push(a, 1, 3, 4);
Visitor.push(a, 3, 4, 5);
Visitor.pop(a);
Visitor.splice(a, 1);
13. 解释器模式
  • 给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。
  • 正则表达式是解释器模式
class Context {
    constructor() {
      this._list = []; // 存放 终结符表达式
      this._sum = 0; // 存放 非终结符表达式(运算结果)
    }
  
    get sum() {
      return this._sum;
    }
    set sum(newValue) {
      this._sum = newValue;
    }
    add(expression) {
      this._list.push(expression);
    }
    get list() {
      return [...this._list];
    }
  }
  
  class PlusExpression {
    interpret(context) {
      if (!(context instanceof Context)) {
        throw new Error("TypeError");
      }
      context.sum = ++context.sum;
    }
  }
  class MinusExpression {
    interpret(context) {
      if (!(context instanceof Context)) {
        throw new Error("TypeError");
      }
      context.sum = --context.sum;
    }
  }
  
  /** 以下是测试代码 **/
  const context = new Context();
  
  // 依次添加: 加法 | 加法 | 减法 表达式
  context.add(new PlusExpression());
  context.add(new PlusExpression());
  context.add(new MinusExpression());
  
  // 依次执行: 加法 | 加法 | 减法 表达式
  context.list.forEach(expression => expression.interpret(context));
  console.log(context.sum);

你可能感兴趣的:(计算机基础知识,javascript,前端)