桥接模式也称为桥梁模式,是结构型设计模式之一。在现实生活中你们都知道“桥梁”是链接河道两岸的主要交通枢纽,简而言之其做用就是链接河的两边,而咱们的桥接模式与现实中的状况很类似,也会承担这链接“两边”的做用,那么具体是哪两边呢?这里先不着急,咱们先来看看该模式的定义。java
将抽象部分与实现部分分离,使它们均可以独立地进行变化。程序员
从模式的定义中咱们大体能够了解到,这里“桥梁”的做用其实就是链接“抽象部分” 与“实现部分”,可是事实上,任何多维度变化类或者说多个树状类之间的耦合均可以使用桥接模式来实现解耦。
若是一个系统须要在构件的抽象化角色和具体化角色之间增长更多的灵活性,避免在两个层次之间创建静态的继承联系,能够经过桥接模式使它们在抽象层创建一个关联关系。web
角色介绍:设计模式
现实生活中有不少桥接模式应用的影子,好比开关与具体的电器,开关的类型有多种,而电器也是各式各样,这二者是独立变化的且又有耦合。还有程序员每天面对的显示屏,对于显示屏来讲它的尺寸与生产商之间也是一种二维关系,具体的尺寸与具体的厂商独立变化。而更贴近生活的例子就是咱们在喝咖啡时,你们知道去咖啡馆喝咖啡通常分为 4 种。大杯加糖、大杯不加糖、小杯加糖、小杯不加糖,对于一杯咖啡来讲这 4 种实质上就两种变化,一是大杯小杯,二是加糖不加糖,无论怎样,咱们先来定义一个咖啡类。ide
public abstract class Coffee {
protected CoffeeAdditives impl;
public Coffee(CoffeeAdditives impl){
this.impl = impl;
}
/** * 咖啡具体是什么样子有子类决定 */
public abstract void makeCoffee();
}
Coffee 类中保持了对 CoffeeAddITIves 的引用,以便调用具体的实现。一样地,咖啡还分大杯小杯,定义两个子类继承于 Coffee。svg
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
Log.d("Coffee", "大杯的" + impl + "咖啡");
}
}
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
Log.d("Coffee", "小杯的" + impl + "咖啡");
}
}
而对于加进咖啡中的糖,固然也能够选择不加,咱们也用以抽象类定义:优化
public abstract class CoffeeAdditives {
/** * 具体要往咖啡里添加什么也是有子类实现 * @return 具体添加的东西 */
public abstract String addSomething();
}
注意,这里的 CoffeeAdditives 其实就对应于上面咱们 UML 类图中的实现部分,而 Coffee 则对应于抽闲部分,其实模块定义中所谓的 “抽象” 与“实现”实质上对应的是两个独立变化的维度,所以,上面咱们也曾说过,任何多维度变化类或者说多个树状类之间的耦合均可以使用桥接模式来实现解耦。在本例中,咱们的 Coffee 类虽然是一个抽象类,但它并不是是所谓的“抽象部分”,而 CoffeeAdditives 类也并不是必定就是“实现部分”,二者各自为一维度,独立变化,仅此而已,所谓的 “抽象与实现分离”更偏向于咱们实际的开发,二者并不必定挂钩,这里其实就能够看到桥接模式的应用性其实很普遍,并不局限于程序设计。咱们再来看 CoffeeAdditives 对应的两个子类:加糖与不加糖:this
public class Sugar extends CoffeeAdditives {
@Override
public String addSomething() {
return "加糖";
}
}
public class Ordinary extends CoffeeAdditives {
@Override
public String addSomething() {
return "原味";
}
}
不加糖咱们以原味表示,最后来看客户类,将二者进行整合:spa
public class Client {
public static void main(){
//原味
CoffeeAdditives ordinary = new Ordinary();
//糖类
CoffeeAdditives sugar = new Sugar();
//大杯咖啡 原味
Coffee largeCoffeeOrdinary = new LargeCoffee(ordinary);
largeCoffeeOrdinary.makeCoffee();
//大杯咖啡 加糖
Coffee largeCoffeeSugar = new LargeCoffee(sugar);
largeCoffeeSugar.makeCoffee();
//小杯咖啡 原味
Coffee smallCoffeeOrdinary = new SmallCoffee(ordinary);
smallCoffeeOrdinary.makeCoffee();
//小杯咖啡 加糖
Coffee smallCoffeeSugar = new SmallCoffee(sugar);
smallCoffeeSugar.makeCoffee();
}
}
代码逻辑很简单,不难理解,这里输出结果就不给出了。若是此时咖啡庁为了知足更多人的习惯,推出中杯的咖啡怎么办?对于本例来讲,这种需求的变化其实就是 Coffee 来的变化,定义中杯类扩展 Coffee 类便可:设计
public class MiddleCoffee extends Coffee {
public MiddleCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
Log.d("Coffee", "中杯的" + impl + "咖啡");
}
}
对应的客户端作出相应的增长便可。
//小杯咖啡 原味
Coffee middleCoffeeOrdinary = new MiddleCoffee(ordinary);
middleCoffeeOrdinary.makeCoffee();
//小杯咖啡 加糖
Coffee middleCoffeeSugar = new MiddleCoffee(sugar);
middleCoffeeOrdinary.makeCoffee();
一样地,为了增长咖啡口味的种类,咱们也可让 CoffeeAdditives 类变化起来,增长更多的子类表示,诸如加奶、加蜂蜜、加盐等,具体的代码就不在给出了,相信你们已经很清楚。从本例中咱们能够看到,不论是 Coffee 变化了仍是 CoffeeAdditives 变化了,其相对于对方而言都是独立的没有什么过多的交集,二者之间惟一的联系就是 Coffee 中保持的对 CoffeeAdditives 的引用,此乃二者之纽带,这就是桥接模式。
桥接模式能够应用到开发中,可是它应用得并很少,一个很重要的缘由是对于抽象与实现分离的把握,是否是须要分离、如何分离?对于设计者来讲要有一个恰到好处的分寸。无论怎么说,桥接模式的优势咱们母庸置疑,分离抽象与实现、灵活的扩展以及对客户来讲透明的实现等。可是使用桥接模式也有一个明显的缺点,上面咱们也提到了,就是不容易设计,对开发者来讲要有必定的经验要求。所以,对桥接模式应用来讲,理解很简单,设计却不容易。