JavaScript - 桥接模式

201 阅读3分钟

介绍

桥接模式:是用于把实现过程和通用代码分离,让通用代码抽象化,使得两种具体的实现变得多样化。

举一个例子,在 DOM 树中,我们需要在点击 span,button,div 标签时更改它们的颜色:

// 点击 span 标签更改颜色
document.getElementById("span").click = function() {
    this.style.color = "red"
}

// 点击 button 标签更改颜色
document.getElementById("button").click = function() {
    this.style.color = "green"
}

// 点击 div 标签更改颜色
document.getElementById("div").click = function() {
    this.style.color = "yellow"
}

可以看出上面的代码中有一部分是复用的代码,我们可以把这部分代码单独抽离出来,让代码更见简洁化。

function changeColor( dom,color ){
    dom.style.color = color
}

在更改过程中,直接调用 changeColor 方法:

document.getElementById("span").click = function() {
    changeColor( this,'red' )
}

document.getElementById("button").click = function() {
    changeColor( this,'green' )
}

document.getElementById("p").click = function() {
    changeColor( this,'yellow' )
}

具体实现时,我们在点击事件的匿名函数中调用 changeColor 方法,而这个匿名函数就是 ,它接通了实现过程和抽象化。同时这样的实现过程就可以叫做 桥接模式

具体实现

有时候在多维的变化中桥接模式更加实用,比如可以提取多个底层功能模块,比如提取运动,着色,说话模块,球类可以具有运动和着色模块,人类可以具有运动和说话模块,这样可以实现模块的快速组装,不仅仅是实现与抽象部分相分离了,而是更进一步功能与抽象相分离,进而 提升逼格 灵活的创建对象。

/** 运动模块,它将抽象一个物体如何运动
 * 
 * @param { number } x 
 * @param { number } y 
 */
function Speed( x,y ) {
    this.x = x
    this.y = y

    this.run = function() {
        console.log( `运动起来  x=>${this.x} y=>${ this.y }` );
    }
}

/** 着色模块,抽象一个物体的颜色
 * 
 * @param {string} cl 
 */
function Color( cl ) {
    this.color = cl

    this.draw = function() {
        console.log( `绘制颜色 ${this.color}` )
    }
}

/** 说话模块,它抽象出说出的什么话
 * 
 * @param {any} context 
 */
function Speak( context ) {
    this.context = context

    this.say = function() {
        console.log( `他说出了 ${this.context}` );
    }
}

在上面的代码中,我们对运动,着色,说话的三个模块进行了抽象分离。

function Ball( x,y,color ) {
    this.speed = new Speed( x,y )
    this.color = new Color( color )

    this._init = function() {
        this.speed.run()
        this.color.draw()
    }
}

const ball = new Ball( 10,34,'red' )
ball._init()
// 运动起来  x=>10 y=>34
// 绘制颜色 red


function Man( x,y,context ) {
    this.speed = new Speed( x,y )
    this.speak = new Speak( context )

    this._init = function() {
        this.speed.run()
        this.speak.say()
    }
}

const man = new Man( 90,45,"Hello World!" )
man._init()
// 运动起来  x=>90 y=>45
// 他说出了 Hello World!

总结

学习桥接模式关键是要理解抽象部分与实现部分的分离,使得二者可以独立的变化,而不必拘泥于形式。适用场景的多变就非常适合使用这种模式来实现。使用桥接模式最重要的是要找出系统中不同的变化维度。

优点:

  • 分离了抽象和实现部分,将实现层(DOM 元素事件触发并执行具体修改逻辑)和抽象层( 元素外观、尺寸部分的修改函数)解耦,有利于分层

  • 提高了可扩展性,多个维度的部件自由组合,避免了类继承带来的强耦合关系,也减少了部件类的数量

  • 使用者不用关心细节的实现,可以方便快捷地进行使用

缺点:

  • 桥接模式要求两个部件没有耦合关系,否则无法独立地变化,因此要求正确的对系统变化的维度进行识别,使用范围存在局限性

  • 桥接模式的引入增加了系统复杂度

  • 大量的类将导致开发成本的增加,同时在性能方面可能也会有所减少。