前端要知道的设计模式

2019-06-14  本文已影响0人  chasing_dream

发布订阅模式:

这种设计模式可以大大降低程序没款之间的耦合度,便于更加的灵活的扩展和维护。

// 一个播放器类
class Player {

  constructor() {
    // 初始化观察者列表
    this.watchers = {}

    // 模拟2秒后发布一个'play'事件
    setTimeout(() => {
      this._publish('play', true)
    }, 2000)

    // 模拟4秒后发布一个'pause'事件
    setTimeout(() => {
      this._publish('pause', true)
    }, 4000)
  }

  // 发布事件
  _publish(event, data) {
    if (this.watchers[event] && this.watchers[event].length) {
      this.watchers[event].forEach(callback => callback.bind(this)(data))
    }
  }

  // 订阅事件
  subscribe(event, callback) {
    this.watchers[event] = this.watchers[event] || []
    this.watchers[event].push(callback)
  }

  // 退订事件
  unsubscribe(event = null, callback = null) {
    // 如果传入指定事件函数,则仅退订此事件函数
    if (callback&&event) {
      if (this.watchers[event] && this.watchers[event].length) {
        this.watchers[event].splice(this.watchers[event].findIndex(cb => Object.is(cb, callback)), 1)
      }

    // 如果仅传入事件名称,则退订此事件对应的所有的事件函数
    } else if (event) {
      this.watchers[event] = []

    // 如果未传入任何参数,则退订所有事件
    } else {
      this.watchers = {}
    }
  }
}

// 实例化播放器
const player = new Player()
console.log(player)

// 播放事件回调函数1
const onPlayerPlay1 = function(data) {
  console.log('1: Player is play, the `this` context is current player', this, data)
}

// 播放事件回调函数2
const onPlayerPlay2 = data => {
  console.log('2: Player is play', data)
}

// 暂停事件回调函数
const onPlayerPause = data => {
  console.log('Player is pause', data)
}

// 加载事件回调函数
const onPlayerLoaded = data => {
  console.log('Player is loaded', data)
}

// 可订阅多个不同事件
player.subscribe('play', onPlayerPlay1)
player.subscribe('play', onPlayerPlay2)
player.subscribe('pause', onPlayerPause)
player.subscribe('loaded', onPlayerLoaded)

// 可以退订指定订阅事件
player.unsubscribe('play', onPlayerPlay2)
// 退订指定事件名称下的所有订阅事件
player.unsubscribe('play')
// 退订所有订阅事件
player.unsubscribe()

// 可以在外部手动发出事件(真实生产场景中,发布特性一般为类内部私有方法)
player._publish('loaded', true)

思路:订阅=》添加到watchers(订阅列表)=》执行发布_publish

工厂模式

把相同的操作放在一个对外开放的接口里

代理模式

ES6中的Proxy对象 http://es6.ruanyifeng.com/#docs/proxy
const target = {}
const handler = {
    get(target, property) {
        if (property in target) {
            return target[property]
        } else {
            throw new ReferenceError("Property \"" + property + "\" does not exist.")
        }
    }
}
const p = new Proxy(target, {})
p.a = 3  // 被转发到代理的操作
console.log(p.c) //

单例模式/单体模式

//static 如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
http://es6.ruanyifeng.com/#docs/class
// 类数实例:
class Singleton {
  constructor(name) {
    this.name = name
    this.instance = null   // 
  }
  getName() {
    alert(this.name)
  }
  static getInstance(name) {
    if (!this.instance) {
      this.instance = new Singleton(name)
    }
    return this.instance
  }
}
const ins = new Singleton('hhhh')
const instanceA = Singleton.getInstance('seven1')
const instanceB = Singleton.getInstance('seven2')

中介者模式

先来理解这么一个问题,假如我们前端开发接的需求是需求方给我们需求,可能一个前端开发会和多个需求方打交道,所以会保持多个需求方的联系,那么在程序里面就意味着保持多个对象的引用,当程序的规模越大,对象会越来越多,他们之间的关系会越来越复杂,那现在假如现在有一个中介者(假如就是我们的主管)来对接多个需求方的需求,那么需求方只需要把所有的需求给我们主管就可以,主管会依次看我们的工作量来给我们分配任务,这样的话,我们前端开发就不需要和多个业务方联系,我们只需要和我们主管(也就是中介)联系即可,这样的好处就弱化了对象之间的耦合。

function Hero(name) {
    this.name = name;
    this.enemy = null; 
}
Hero.prototype.win = function(){
    console.log(this.name + 'Won');
}
Hero.prototype.lose = function(){
    console.log(this.name + 'lose');
}
Hero.prototype.die = function(){
    this.lose();
    this.enemy.win();
}
// 初始化2个对象
var h1 = new Hero("朱元璋");
var h2 = new Hero("刘伯温");
// 给玩家设置敌人
h1.enemy = h2;
h2.enemy = h1;
// 朱元璋死了 也就输了
h1.die();  // 输出 朱元璋lose 刘伯温Won

模块模式

var Person = (function(){
    var name = "weixin";
    var age = 22;
    function getName(){
        return name;
    }
    function getAge(){
        return age;
    }
    return {
        getName: getName,
        getAge: getAge
    }
})();

console.log(age); // 报错:age未定义
console.log(name); // 报错:name未定义
console.log(Person.age); // undefined
console.log(Person.name); // undefined
//只能通过Person提供的接口访问相应的变量
console.log(Person.getName()); // weixin
console.log(Person.getAge()); // 22

构造函数模式

//es5写法
function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype = {
    constructor: Person;
    printName: function(){
        console.log(this.name);
    },
    printAge: function(){
        console.log(this.age);
    }
}

var person = new Person('xin', 22);
person.printName(); // xin
person.printAge(); // 22
//es6写法
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    printName() {
        console.log(this.name);
    }
    printAge() {
        console.log(this.age)
    }
}
var person = new Person('xin', 22);
person.printName(); // xin
person.printAge(); // 22

职责链模式

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。(大函数分割成一个个小函数,清晰,各司其职)

优点:代码清晰,可读性较好,拆分函数

//----------------------改造前---------------

var order = function( orderType, pay, stock ){
if ( orderType === 1 ){ // 500 元定金购买模式
    if ( pay === true ){ // 已支付定金
        console.log( '500 元定金预购, 得到 100 优惠券' );
    }else{ // 未支付定金,降级到普通购买模式
        if ( stock > 0 ){ // 用于普通购买的手机还有库存
            console.log( '普通购买, 无优惠券' );
            }else{
                console.log( '手机库存不足' );
                }
            }
        }
        else if ( orderType === 2 ){ // 200 元定金购买模式
            if ( pay === true ){
                console.log( '200 元定金预购, 得到 50 优惠券' );
            }else{
                if ( stock > 0 ){
                    console.log( '普通购买, 无优惠券' );
                }else{
                    console.log( '手机库存不足' );
                }
            }
        }       else if ( orderType === 3 ){
            if ( stock > 0 ){
                console.log( '普通购买, 无优惠券' );
            }else{
                console.log( '手机库存不足' );
            }
        }
    };
    order( 1 , true, 500); // 输出: 500 元定金预购, 得到 100 优惠券



//--------------------- 改造后----------------------------



// 500 元订单
var order500 = function( orderType, pay, stock ){
    if ( orderType === 1 && pay === true ){
        console.log( '500 元定金预购, 得到 100 优惠券' );
    }else{
        order200( orderType, pay, stock ); // 将请求传递给 200 元订单
    }
};
// 200 元订单
var order200 = function( orderType, pay, stock ){
    if ( orderType === 2 && pay === true ){
        console.log( '200 元定金预购, 得到 50 优惠券' );
    }else{
        orderNormal( orderType, pay, stock ); // 将请求传递给普通订单
    }
};
// 普通购买订单
var orderNormal = function( orderType, pay, stock ){
    if ( stock > 0 ){
        console.log( '普通购买, 无优惠券' );
    }else{
        console.log( '手机库存不足' );
    }
};
// 测试结果:
order500( 1 , true, 500); // 输出:500 元定金预购, 得到 100 优惠券
order500( 1, false, 500 ); // 输出:普通购买, 无优惠券
order500( 2, true, 500 ); // 输出:200 元定金预购, 得到 500 优惠券
order500( 3, false, 500 ); // 输出:普通购买, 无优惠券
order500( 3, false, 0 ); // 输出:手机库存不足

https://segmentfault.com/a/1190000010914032?utm_source=tag-newest
https://blog.csdn.net/song_mou_xia/article/details/80763833
深入理解

上一篇 下一篇

猜你喜欢

热点阅读