设计模式就是一套写代码的方式,通过这种方式写的代码更容易维护和复用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

创建型设计模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活

属于这一类的一些模式是:工厂模式(Factory),抽象工厂模式 (Abstract),原型模式 (Prototype),单例模式 (Singleton)以及 建造者模式(Builder)。

结构设计模式
结构模式关注于对象组成和通常识别的方式实现不同对象之间的关系。该模式有助于在系统的某一部分发生改变的时候,整个系统结构不需要改变。
在该分类下的模式有:装饰模式,外观模式,享元模式,适配器模式和代理模式。

行为设计模式
行为模式关注改善或精简在系统中不同对象间通信

行为模式包括:迭代模式,中介者模式,观察者模式和访问者模式。

1.1工厂模式

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,不是使用 new 运算符直接实例化对象,且是通过使用一个共同的接口来指向新创建的对象。隐藏了创建实例的复杂度,只需要提供一个接口,简单清晰。
1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
vue中的动态组件,component,通过给is方法传递不同的组件名,使得插入不同的组件。

class Man {
   constructor(name){
      this.name = name;
      this.sex = 'man'
  }
  alertName() {
      alert(this.name)
  }
}

class Woman{
   constructor(name){
      this.name = name;
      this.sex = 'woman'
  }
  alertName() {
      alert(this.name)
  }
}

class Factory{
   static create(name, sex) {
      if(sex === 'man') {
          return new Man(sex);
      }
      else {
          return new Woman(sex);
      }
   }
}

Factory.create('yck').alertName()

1.2 单例模式
保证一个类仅有一个实例,无论调用多少次实例只创建一次,保证全局只有一个对象可以访问,并提供一个访问它的全局访问点。设置弹窗,设置管理员之类的。
vuex采用的就是单例模式,全局维护了一个对象,在这个全局对象中,所有属性都是响应式的,任意属性进行了改变,都会造成使用到该属性的组件进行更新。并且只能通过 commit 的方式改变状态,实现了单向数据流模式。
假设要设置一个管理员,多次调用也仅设置一次,我们可以使用闭包缓存一个内部变量来实现这个单例。

function SetManager(name) {
   this.name = name
}
SetManger.prototype.getManagerName = function() {console.log(this.name)};
function Singelton() {
    let manager= null;
    return function(name) {
       if(!manager) manager = new SetManager(name);
        return manager;
    }
}
SingletonSetManager('a').getName(); // a
SingletonSetManager('b').getName(); // a
SingletonSetManager('c').getName(); // a

2.1适配器模式
是解决两个软件实体间的接口不兼容的问题,对不兼容的部分进行适配
不需要改变已有的接口,通过包装一层的方式实现两个接口的正常协作。

// 渲染数据,格式限制为数组了
function renderData(data) {
    data.forEach(function(item) {
        console.log(item);
    });
}

// 对非数组的进行转换适配
function arrayAdapter(data) {
    if (typeof data !== 'object') {
        return [];
    }

    if (Object.prototype.toString.call(data) === '[object Array]') {
        return data;
    }

    var temp = [];

    for (var item in data) {
        if (data.hasOwnProperty(item)) {
            temp.push(data[item]);
        }
    }

    return temp;
}
var data = {
    0: 'A',
    1: 'B',
    2: 'C'
};
renderData(arrayAdapter(data)); // A B C

2.2装饰器模式(Decorator Pattern)
动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。能够在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责。

function Person() {}
Person.prototype.skill = function(){
    console.log('跑步')
}

function MusicDecorator(person) {
    this.person = person;
}
MusicDecorator.prototype.skil = function() {
    this.person.skill();
    console.log('唱歌')
}

const person = new Person();
const person1 = new MusicDecorator(person);
person.skill(); //跑步
person1.skill(); //跑步 唱歌

2.3代理模式(Proxy Pattern)
实现了访问主体的限制行为,控制对对象的访问,不让外部直接访问到对象。
为一个对象提供一个代用品或占位符,以便控制对它的访问
比如字符屏蔽、暂时缓存、函数节流防抖。

2.4外观模式
为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使子系统更加容易使用。比如兼容性封装。

var addMyEvent = function( el,ev,fn ){

   if( el.addEventListener ){
            el.addEventListener( ev,fn, false );
      }else if(el.attachEvent){
            el.attachEvent( "on" + ev, fn );
      } else{
           el["on" + ev] = fn;
    }

};

3.1观察者模式(发布-订阅模式)
通过一对一或者一对多的依赖,当对象发生改变时,订阅方会收到通知。在js中常用回调函数的形式。比如事件触发就是使用了这种模式。

3.2迭代器模式
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
JS中数组的map forEach 已经内置了迭代器。