桥接模式是指将抽象和实现放在两个不同的类层次中,使它们可以独立地变化。它属于结构型设计模式的一种。桥接模式主要用于解决双维度扩展问题。
应用场景:
1、如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
模拟场景
假设现在有这样一个剧院,每周五晚上剧院都会表演悲剧节目,而每周日晚上则会表演喜剧节目。剧院所表演的节目由剧团演员自行排练,可以表演现在已有的经典曲目也可以自己排练新的节目。
由于收益良好,所以剧院决定在周五和周日以外再增加其他的专场。假设在每周三新增一场历史剧,剧团便会根据历史主题排练新的节目。在这个过程当中,如果把专场的演出主题和具体表演的节目看做是继承关系,那么这两者便是一种双维度扩展问题。如果每个新节目都创建一个类并且去继承节目类型的话他们之间就会产生复杂度为O(m*n)的逻辑关系。如果后边的节目类型和节目越来越多,维护起来必然十分头疼。 最好的方式是在他们之间建一个桥梁,互相之间的扩展和维护不会产生直接影响。
// 表演节目
class DoPerform {
constructor() {
if (new.target == DoPerform) {
throw new Error("can't be instantiated.");
}
}
showTragedy() {
console.log('The performance of ' + this.showName + '.');
console.log('Be performed by: ' + this.actors.join(','));
}
}
// 哈姆雷特
class Hamlet extends DoPerform {
constructor() {
super();
this.showName = "Hamlet";
this.actors = ['mike', 'sara', 'jone'];
}
}
// 奥赛罗
class Othello extends DoPerform {
constructor() {
super();
this.showName = "othello";
this.actors = ['betty', 'anna', 'tina'];
}
}
// 节目类型
class ShowType {
constructor(type) {
if (new.target == ShowType) {
throw new Error("can't be instantiated.");
}
this.showType = type;
}
show() {
if (this.showType == "Tragedy") {
this.program.showTragedy();
}
}
}
// 悲剧
class Tragedy extends ShowType {
constructor(program){
super('Tragedy');
this.program = program;
console.log("Today is Friday, we got a tragedy show -- ");
}
}
let hamlet = new Tragedy(new Hamlet());
hamlet.show();
程序执行结果:
示例代码的核心思想就是把节目类型和具体节目之间的继承关系分开,也就是把抽象和实现剥离开。通过这样的设计可以提升扩展能力,不过在实际开发中需要用到桥接模式的场景并不常见,并且对于设计和理解难度都有一定的要求。