『面试的底气』—— 设计模式之桥接模式

1,228 阅读3分钟

定义

将抽像部分与它的实现部分分离,使它们都可以独立地变化。

理解

抽像与它的实现分离,这并不是说,让抽像类与其派生类分离,这样的分离没有任何意义。实现指的是抽像类和它的派生类用来实现自己的对象。

学习桥接模式关键是要理解抽象部分与实现部分的分离。

用一个例子来说明,比如画一个红色的圆和黄色的三角形。有两种做法,

  • 先画好圆,调好红色的颜料直接上色,然后继续画好三角形,调好黄色的颜料直接上色。

  • 先调好红色的颜料和黄色的颜料,然后再画圆和三角形,分别进行上色。

那哪一种做法好,肯定是第二种好了,如果用第一种做法,红色的颜料就和圆的图形耦合在一起了。

用代码来描述一下:

class colorshape {
  redCircle() {
    console.log('red circle')
  }
  yellowTriangle() {
    console.log('yellow triangle')//三角形
  }
}
let cs = new colorshape();
cs.redCircle()
cs.yellowTriangle()

我们把颜色当作抽像类,把图形当作颜色抽像类派生出来的具体类,其中圆和三角形就是具体类实现的。

class Color {
  constructor(name) {
    this.name = name
  }
}
class Shape {
  constructor(name, color) {
    this.name = name
    this.color = color
  }
  draw() {
    console.log(`${this.color.name} ${this.name}`)
  }
}
let red = new Color('red')
let yellow = new Color('yello')
let circle = new Shape('circle', red)
circle.draw()
let triangle = new Shape('triangle', yellow)
triangle.draw()

应用

创建一个对象桥接addMethod,实现为对象拓展方法的功能。

抽像层

Object.prototype.addMethod = function (name, fn) {
  this[name] = fn;
}

实现层

function Coordinate(x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
}

var box = new Coordinate(20, 10, 10);

为对象拓展方法(桥接方法)

box.addMethod("init", function () {
  console.log("初始化X轴坐标" + this.x + " , y轴坐标为:" + this.y + " , z轴坐标为:" + this.z);
});
box.addMethod("getCoordinateY", function () {
  console.log("y轴坐标为"+this.y);
});

输出

box.init();// 初始化x轴坐标20,y轴坐标为10,z轴坐标为10。
box.getCoordinateY();// y轴坐标为10

在JavaScript中的应用

在JavaScript中没有抽像类的概念,其实可以这么理解桥接模式在在JavaScript中的应用场景。

不同的对象A和B有相同的行为和特征,将这部分行为和特征单独出来,形成一个新的对象C,在构建对象(A,B)时传入对象C,对象(A,B)的行为函数中调用对象C对应的行为函数。

举一个例子,例如对话框和消息提示两种形式的弹窗都有显示和隐藏的功能。我们就可以把创建对话框和消息提示当作一个具体实现部分,把显示和隐藏的功能当作一个抽像部分。然后将两者分离开来,独立实现,最后桥接起来。

class Toast {
  constructor(node, animation) {
    this.node = node;
    this.animation = animation
  }
  show() {
    this.animation.show(this.node)
  }
  hide() {
    this.animation.hide(this.node)
  }
}

class Message {
  constructor(node, animation) {
    this.node = node;
    this.animation = animation
  }
  show() {
    this.animation.show(this.node)
  }
  hide() {
    this.animation.hide(this.node)
  }
}

class Animation {
  constructor() {
  }
  hide(node) {
    console.log(node, ' hide')
  }
  show(node) {
    console.log(node, ' show')
  }
}

let animation = new Animation()
let toast = new Toast('div', animation)
toast.show(); //div  show
let message = new Message('div', animation)
message.hide() //div  hide

优点和缺点

  • 桥接模式优点:

    把抽象与实现隔离开,有助于独立地管理程序的各组成部分。

  • 桥接模式缺点:

    每使用一个桥接元素都要增加一次函数调用,这对应用程序的性能会有一些负面影响。提高了系统的复杂程度。如果一个桥接函数被用于连接两个函数,而其中某个函数根本不会在桥接函数之外被调用,那么此时这个桥接函数就不是非要不可的。