# 设计模式——桥接模式

桥梁的作用主要就是连接岸的两边。在开发中,桥接模式的作用也是用于连接,只不过它连接的是抽象部分和实现部分。这么说可能很抽象,我们用具体的例子来展示。桥接模式在javascript中应用最广泛的就是事件监听。

 <div id="box1">box1</div>

 var oBox1 = document.getElementById('box1');
 bindEvent(oBox1,'click',getBeerById)
  function getBeerById(){
      var id = this.id;
      asyncRequest('GET','beer.uri?id='+id,function(resp) {
        console.log(resp.responseText);
      })
  }

如上面代码所示,我们定义了一个div,给idbox1div绑定了点击事件,事件函数为getBeerById。其中bindEvend点击事件为抽象类,getBeerById为具体实现类。我们可以发现这个就实现类,也就是getBeerById函数,只能作为事件触发函数,因为它里面的this.id依赖于点击事件即抽象类。我们没办法对getBeerById进行单元测试。现在假设我们又新增了一个div,它根据类名传递参数,代码如下所示:

  <div class="box2">box1</div>

  var oBox2 = document.getElementsByClassName('box2')[0];
  bindEvent(oBox2,'click',getBeerByClassName)
  function getBeerByClassName(){
    var className = this.className;
    asyncRequest('GET','beer.uri?id='+className,function(resp) {
      console.log(resp.responseText);
    })
  }

上面这个事件处理函数getBeerByClassName,不再是根据id请求数据了,而是根据className请求数据。他们之间仅仅是传递参数的区别,根据代码复用和抽象的原则,我们可能会将代码公告部分抽离出来:

   function getBeerId(id){
     asyncRequest('GET','beer.uri?id='+id,function(resp) {
        console.log(resp.responseText);
      })
   }

将代码公共部分抽离出来后,虽然提高了代码的服用。但是带来了新的问题,由于之前的具体实现是作为事件处理函数,它依赖于抽象类即点击事件。抽象后的代码没办法作为事件处理函数了(因为之前通过this获取id和className,现在是将其作为参数进行封装了),因此为了保证原来的功能,我们需要对代码及性能修改,使用新的事件处理函数。

    //抽象类
    bindEvent(oBox1,'click',getBeerByIdBridge)
    //桥接函数
    function getBeerByIdBridge(e){
      getBeerById(this.id)
    }
    //具体类
    function getBeerById(id){
      asyncRequest('GET','beer.uri?id='+id,function(resp) {
        console.log(resp.responseText)
      })
    }

通过上面的代码,我们可以知道,定义了一个函数getBeerByIdBridge来作为事件处理函数。但是这个函数并没有实现具体的功能。具体功能的实现在getBeerById中,也就是说这个函数其实只是点击事件和具体功能之间连接的桥梁。这就是桥接模式,这个函数就是桥接函数。通过上面的代码,我们可以知道桥接模式就是抽象类和具体类之间抽离开来,使得他们能够各自独自变化,而不是互相依赖。
桥接模式的另一个应用:用于连接多个类。
桥接模式不仅能够用来连接抽象和具体实现,而且还能够用于连接多个类,这些多各类实现各部分功能,通过桥接模式实现完整的功能。看具体的代码如下:

//A类
 class A {
    constructor(name,age){
      this.name = name;
      this.age = age;
    }
    showName(){
      console.log(this.name)
    }
  }
  //B类
  class B {
    constructor(job,sex){
      this.job = job;
      this.sex = sex;
    }
    showJob(){
      console.log(this.job)
    }
  }
  //桥接类
  class Bridge{
    constructor(){
      this.w = new A('刘亦菲',30);
      this.h = new B('actor','女')
    }
  }
  let bridge = new Bridge();
  console.log(bridge)
  bridge.w.showName()

如上面代码所示,通过桥接类将类A和类B连接起来了,A类用于记录姓名和年龄,B类用于记录职业和性别,桥接类用于这些功能的所有的实现,相当于记录一个人的完整信息。这样的话我们进行开发时,可以分别对A类和B类进行单独开发,各部分实现各自的功能,最后再通过桥接类实现完整功能。

# 桥接模式的总结:

桥接模式用于将抽象与其是实现隔离开来,以便二者独立变化。这种模式对于事件驱动的编程非常方便。另外桥接模式还可以用于将多个类连接起来,用于实现一个完整功能。