观察者模式、发布/订阅模式、迭代器模式、职责链模式、委托模式、策略模式、中介者模式、模版方法模式、命令模式、备忘录模式、状态模式、访问者模式、解释器模式
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);