桥接模式也称为桥梁模式,是结构型设计模式之一。现实生活中桥梁大家肯定知道,是连接河岸两侧的重要枢纽,至于桥接模式跟它很类似。
桥接模式的定义
将抽象部分与实现部分分离,使它们都可以独立地进行变化。
桥接模式的使用场景
1.如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
2.设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
3.一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
4.虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
桥接模式的UML类图
角色介绍:
Abstraction:抽象部分
该类保持一个对实现部分对象的引用,抽象部分中的方法需要调用实现部分的对象来实现,该类一般为抽象类。
RefinedAbstraction:优化的抽象部分
抽象部分的具体实现,该类一般是对抽象部分的方法进行完善和扩展。
Implementor:实现部分
可以为接口或抽象类,其方法不一定要与抽象部分中的保持一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分这些操作的业务方法。
ConcreteImplementorA/ConcreteImplementorB:实现部分的具体实现
完善实现部分中方法定义的具体逻辑
Client:客户端,客户端程序
源码实现
拿显示生活中的咖啡例子来说,店里有小杯原味咖啡,中杯原味咖啡,小杯加糖咖啡,中杯加糖咖啡。好,首先咱们定义一个Coffee的抽象类
// 抽象的Coffee类
public abstract class Coffee {
protected CoffeeAdditives impl;
public Coffee(CoffeeAdditives impl) {
this.impl = impl;
}
// 咖啡具体是什么样的由子类决定;
public abstract void makeCoffee();
}
// 大杯咖啡的实现
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
System.out.println("大杯的" + impl + "咖啡");
}
}
// 小杯咖啡的实现
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
System.out.println("小杯的" + impl + "咖啡");
}
}
// 抽象类,定义加糖和不加糖,具体也由子类去实现
public abstract class CoffeeAdditives {
// 具体要往咖啡里添加什么也是由子类实现
public abstract String addSomething();
}
// 原味咖啡
public class Ordinary extends CoffeeAdditives {
@Override
public String addSomething() {
return "原味";
}
}
// 加糖咖啡
public class Sugar extends CoffeeAdditives {
@Override
public String addSomething() {
return "加糖";
}
}
// 测试类
public class Main {
public static void main(String[] args){
// 原味
Ordinary implOrdinary = new Ordinary();
// 加糖
Sugar implSugar = new Sugar();
//大杯咖啡 ,原味
LargeCoffee largeCoffeeOrdinary = new LargeCoffee(implOrdinary);
largeCoffeeOrdinary.makeCoffee();
// 小杯咖啡,原味
SmallCoffee smallCoffeeOrdinary = new SmallCoffee(implOrdinary);
smallCoffeeOrdinary.makeCoffee();
//大杯咖啡,加糖
LargeCoffee largeCoffeeSugar = new LargeCoffee(implSugar);
largeCoffeeSugar.makeCoffee();
// 小杯咖啡,加糖
SmallCoffee smallCoffeeSugar = new SmallCoffee(implSugar);
smallCoffeeSugar.makeCoffee();
}
}
测试结果就不展示了,那么好,现在想增加一个中杯,实现代码如下
public class MiddleCoffee extends Coffee {
public MiddleCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
System.out.println("中杯的" + impl + "咖啡");
}
}
// 测试类
public class Main {
public static void main(String[] args){
// 原味
Ordinary implOrdinary = new Ordinary();
// 加糖
Sugar implSugar = new Sugar();
... // 代码省略
// 中杯咖啡,原味
MiddleCoffee middleCoffeeOrdinary = new MiddleCoffee(implOrdinary);
middleCoffeeOrdinary.makeCoffee();
// 中杯咖啡,加糖
MiddleCoffee middleCoffeeSugar = new MiddleCoffee(implSugar);
middleCoffeeSugar.makeCoffee();
}
}
桥接模式的总结
Bridge模式是一个非常有用的模式,也非常复杂,它很好的符合了开放-封闭原则和优先使用对象,而不是继承这两个面向对象原则。分离抽象与实现,灵活的扩展以及对客户来说透明的实现都是它毋庸置疑的优点。它的缺点就是不容易设计,对开发者来说要有一定的经验要求。
桥接模式与装饰的区别:
装饰模式:
这两个模式在一定程度上都是为了减少子类的数目,避免出现复杂的继承关系。但是它们解决的方法却各有不同,装饰模式把子类中比基类中多出来的部分放到单独的类里面,以适应新功能增加的需要,当我们把描述新功能的类封装到基类的对象里面时,就得到了所需要的子类对象,这些描述新功能的类通过组合可以实现很多的功能组合
桥接模式:
桥接模式则把原来的基类的实现化细节抽象出来,在构造到一个实现化的结构中,然后再把原来的基类改造成一个抽象化的等级结构,这样就可以实现系统在多个维度上的独立变化 。