# 设计模式——外观设计模式

上面的创建型设计模式,专注于创建对象。而结构性设计模式则专注于结构设计,通俗点来说就是对象与对象之间的结构设计,也就是如何将类或者对象进行更好的组织,以方便使用。

# 外观设计模式定义:

为一组复杂的子接口提供一个更高级的统一接口,以便更方便的去实现子接口的功能。看定义总是感觉很复杂,我们根据一些场景来具体分析:

HTML代码
 <div id="btn1">按钮1</div>
 <div id="btn2">按钮2</div>
js代码
    let oBtn1= document.getElementById('btn1');
    let oBtn2= document.getElementById('btn2');


    //按钮1
    function btn1Fn(){
      console.log('这里是按钮1的内容')
    }
    //DOM事件的兼容性处理
    if( document.addEventListener ){
      oBtn1.addEventListener("click" , btn1Fn, false);
    }else if(document.attachEvent){
      oBtn1.attachEvent("onclick" , btn1Fn);
    }else{
      oBtn1.onclick = btn1Fn;
    }


    //按钮2
    function btn2Fn(){
      console.log('这里是按钮2的内容')
    }
    //DOM事件的兼容性处理
    if( document.addEventListener ){
      oBtn1.addEventListener("click" , btn2Fn, false);
    }else if(document.attachEvent){
      oBtn1.attachEvent("onclick" , btn2Fn);
    }else{
      oBtn1.onclick = btn2Fn;
    }

上面代码中由两个按钮,每个按钮有对应的点击事件。但是我们知道如果直接使用onclickDOM0级点击事件,那么就可能出现后续的事件覆盖前面的。因此建议使用DOM2级点击事件,但是addEventListener存在兼容性问题,在IE中存在不兼容。因此我们需要对每次事件做兼容性处理。从上面的代码中,我们可以看出,我们对按钮1和按钮2都做了兼容性处理。事实上,这些兼容性处理都是相同的,如果每一次都去写复杂的重复的兼容性代码,是没有意义的。因此,我们通常会将兼容性处理封装起来,作为一个统一的接口,在需要的时候,直接调用这个接口,而不是再去重复写这个复杂的兼容代码,这种将复杂的代码封装起来,其实就是外观设计模式. 我们看使用外观设计模式实现的代码:

let oBtn1= document.getElementById('btn1');
let oBtn2= document.getElementById('btn2');

//按钮1
function btn1Fn(){
  console.log('这里是按钮1的内容')
}
//按钮2
function btn2Fn(){
  console.log('这里是按钮2的内容')
}

function bindEvent(element,type,fn) {
  if(document.addEventListener){
    element.addEventListener(type,fn,false)
  }else if(document.attachEvent){
    element.attachEvent('on'+type,fn)
  }else{
    element["on"+type] = fn;
  }
}
bindEvent(oBtn1,'click',btn1Fn)
bindEvent(oBtn2,'click',btn2Fn)

从上面的代码中,我们可以看到使用了bindEvent来封装兼容性处理,然后oBtn1oBtn2触发点击事件都是直接调用这个封装函数。其实这就是外观模式的一次典型应用。所有的API的兼容性封装其实都是外观模式的应用。外观模式其实就是把一些复杂的操作隐藏起来,然后我们从更高级别直接调用。我们再看我们在开发中经常使用到的一个例子:

var  person = {
  init:function(){
  //  这里是初始化代码
  },
  getAge:function(){
  //  这里是获取元素的方法

  },
  getName:function(){
  //  这里是获取样式的代码
  },
  getJob:function(){
  //这里是获取个人工作的代码
  }
}
var name = person.getName();

上面的代码是一个对象person,里面封装了与个人信息相关的age,name,job等方法,然后在需要获取这些信息时,我们使用person.xx来调用。其实这就是外观模式的另外一种应用。在开发中,我们经常会使用命名空间,将一些相关的信息都封装到这个对象中,这种将各类操作饥饿和在一起,对外提供统一的接口就是外观模式的典型应用。

# 外观设计模式总结:

外观设计模式时结构性设计模式,我们之前说过结构型设计模式是用于组织代码结构的。而外观设计模式就是把所有的子类饥饿和在一起,对外提供统一的接口这样的一种组织形式。 典型的使用就是各种兼容性API的封装和命名空间的使用。