gdutwyg / blog

使用issues记录笔记
0 stars 1 forks source link

js 几种常用的设计模式 #77

Open gdutwyg opened 5 years ago

gdutwyg commented 5 years ago

单体模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。

class Fn {
    constructor(name) {
        this.name = name
    }
    getName() {
         return this.name;
    }
}
// 代理实现单例模式
var ProxyMode = (function() {
    var instance = null;
    return function(name) {
        if(!instance) {
            instance = new Fn(name);
        }
        return instance;
    }
})();
// 测试单体模式的实例
var a = new ProxyMode("aaa");
var b = new ProxyMode("bbb");
// 因为单体模式是只实例化一次,所以下面的实例是相等的
console.log(a === b);    //true
console.log(a.getName());    //aaa
console.log(b.getName());    //aaa

工厂模式

常见的实例化对象模式,工厂模式就相当于将 new 操作单独封装,只对外提供相应接口

    // 定义产品
    class Product {
        constructor (name) {
            this.name = name;
        }
        init () {}
    }
   // 定义工厂
    class Factory {
        create (name) {
            return new Product(name);
        }
    }
    const factory = new Factory();
    const p = factory.create('bbb'); // 通过工厂对象创建出来的产品

适配器模式

用来解决两个接口不兼容问题,由一个对象来包装不兼容的对象,比如参数转换,允许直接访问

    class Adapter {
        specificRequest () {
            return '德国标准插头';
        }
    }
    // 适配器对象,对原来不兼容对象进行包装处理
    class Target {
        constructor () {
            this.adapter = new Adapter(); // 实例化Adapter
        }
        request () {
            const info = this.adapter.specificRequest();
            console.log(`${info} - 转换器 - 中国标准插头`)
        }
    }
    const target = new Target();
    console.log(target.request()); // 德国标准插头 - 转换器 - 中国标准插头

装饰器模式

不改变对象自身的基础上,动态的给某个对象添加新方法,同时又不影响旧方法

class Circle {
    draw() {
        console.log('画一个圆形');
    }
}

class Decorator {
    constructor(circle) {
        this.circle = circle;
    }
    draw() {
        this.circle.draw();
        this.setRedBorder(circle);
    }
    setRedBorder(circle) {
        console.log('画一个红色边框');
    }
}

let circle = new Circle();
let decorator = new Decorator(circle); // 把circle实例传入
//画一个圆形  
// 画一个红色边框
decorator.draw(); 

该例中,我们写了一个Decorator装饰器类,它重写了实例对象的draw方法,给其方法新增了一个setRedBorder(),因此最后为其输出结果进行了装饰。

代理模式

为其他对象提供一种代理,便以控制对这个对象的访问,不能直接访问目标对象

// 为这个target设置一个代理
class Target {
   constructor () {

   }
  test () {
    console.log('test')
  }
}
class ProxyObj {
  constructor () {
      this.target = new Target()
  }
  test () {
    this.target.test()
  }
}
let  proxy = new ProxyObj()
proxy.test()

中介者模式

通过一个中介者对象,其他所有的相关对象都通过该中介者对象来通信,而不是相互引用,当其中的一个对象发生改变时,只需要通知中介者对象即可。通过中介者模式可以解除对象与对象之间的紧耦合关系。

例如:现实生活中,航线上的飞机只需要和机场的塔台通信就能确定航线和飞行状态,而不需要和所有飞机通信。同时塔台作为中介者,知道每架飞机的飞行状态,所以可以安排所有飞机的起降和航线安排。

中介者模式适用的场景:例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等等,都会触发change事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。

var colorSelect = document.getElementById('colorSelect');
var memorySelect = document.getElementById('memorySelect');
var numSelect = document.getElementById('numSelect');
//中介者
var mediator = (function() {
    return {
        changed: function(obj) {
            switch(obj){
                case colorSelect:
                    //TODO
                    break;
                case memorySelect:
                    //TODO
                    break;
                case numSelect:
                    //TODO
                    break;
            }
        }
    }
})();
colorSelect.onchange = function() {
    mediator.changed(this);
};
memorySelect.onchange = function() {
    mediator.changed(this);
};
numSelect.onchange = function() {
    mediator.changed(this);
};

观察者模式

观察者模式,也叫订阅-发布模式, 该模式定义了一种1对N的关系(注意:不一定是一对多,所以更准确地描述应该是1对N),使观察者们同时监听某一个对象相应的状态变换,一旦变化则通知到所有观察者,从而触发观察者相应的事件。因此,观察者模式中的角色有两类:观察者(发布者)和被观察者(订阅者)

// 创建一个主题,保存状态,状态变化之后触发所有观察者对象
/*
每一个观察者(Observer)都有一个update 方法,并且观察者的状态就是等待被触发;
每一个主题(subject)都可以通过attach方法接纳N个观察者所观察,即观察者们存储在主题的observers数组里,;
主题有初始化状态(init)、获取状态(getState)和设置状态(setState)三个通用型方法;
当主题的状态发生变化时,通过特定的notifyAllObervers方法通知所有观察者。
*/
class Subject {
    constructor() {
        this.state = 0;
        this.observers = []
    }

    getState() {
        return this.state
    }

    setState(state) {
       this.state = state;
       this.notifyAllObservers()
    }

    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }

    attach(observer) {
       this.observers.push(observer)
    }
}

// 观察者
class Observer {
    constructor(name , subject) {
       this.name = name;
       this.subject = subject;
       this.subject.attach(this);
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`)
    }
}
const s = new Subject()
var a = new Observer('a',s)
var b = new Observer('b',s)
var c = new Observer('c',s)
s.setState(1) 
/*
 a update, state: 1
 b update, state: 1
 c update, state: 1
*/

策略模式

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

/*策略类*/
var levelOBJ = {
    "A": function(money) {
        return money * 4;
    },
    "B" : function(money) {
        return money * 3;
    },
    "C" : function(money) {
        return money * 2;
    } 
};
/*环境类*/
var calculateBouns =function(level,money) {
    return levelOBJ[level](money);
};
console.log(calculateBouns('A',10000)); // 40000

外观模式

外观模式即让多个方法一起被调用

例如。 stopPropagation() 和 preventDefault() 兼容性一起调用。

var myEvent = {
    stop: function(e) {
        if (typeof e.preventDefault() === "function") {
            e.preventDefault();
        }
        if (typeof e.stopPropagation() === "function") {
            e.stopPropagation();
        }
        //for IE
        if (typeof e.returnValue === "boolean") {
            e.returnValue = false;
        }
        if (typeof e.cancelBubble === "boolean") {
            e.cancelBubble = true;
        }
    }
}
myEvent.stop()
gdutwyg commented 5 years ago

参考

JavaScript设计模式总结 JavaScript设计模式 js设计模式 javascript-design-patterns