1、介绍
桥接模式也称为桥梁模式,是结构型设计模式之一,在显示生活中大家都知道桥梁是链接河道两岸的主要交通枢纽,简而言之其作用就是链接河的两边,而我们的桥接模式与显示中的情况很相似,也是承担着链接两边的作用,在代码中,两边指的又是什么呢?
2、定义
将抽象部分与实现部分分离,使它们都可以独立的进行变化。
3、使用场景
从定义中桥梁主要作用是链接抽象部分与实现部分,但是事实上,任何多维度变化或者多个树状类之间的耦合都可以使用桥接模式来实现解耦,在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
4、桥接模式的UML类图
角色介绍
Implementor,实现部分的抽象接口,其方法不一定要与抽象部分中的代码保持一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分这些基本操作的业务方法。
public interface Implementor {
public void oprationImpl();
}
ConcreteImplementorA、ConcreteImplementorB:实现部分的具体实现
public class ConcreteImplementorA implements Implementor {
@Override
public void oprationImpl() {
//具体实现
}
}
public class ConcreteImplementorB implements Implementor {
@Override
public void oprationImpl() {
//具体实现
}
}
Abstraction:抽象部分的实现,该类保持一个是显现部分对象的引用,抽象部分中的方法需要调用实现部分的对象来实现,该类一般为抽象类
public abstract class Abstraction {
//声明一个私有成员变量引用 实现部分的对象
private Implementor implementor;
//通过构造方法引用 实现部分的对象
public Abstraction(Implementor implementor) {
super();
this.implementor = implementor;
}
//调用具体实现部分的方法
public void oprationImpl() {
implementor.oprationImpl();
}
}
RefinedAbstraction优化的抽象部分
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
public void refinedOpration() {
//对Abstraction中的方法进行扩展
}
}
这里就不写客户端,因为上面描述太抽象,现在具体举个例子就明白了
大家都知道去喝咖啡一般分为四种。大杯加糖,大杯不加糖,小贝加糖,小杯不加糖,对于一杯咖啡来说这4中就是两种变化,一种是大杯与小杯,加糖与不加糖,这两种变化胡良独立变化。这里就可以用桥接模式。
首先看UML类图
这里的Coffee.java代表抽象部分Abstraction
public abstract class Coffee {
protected CoffeeAddttives addttives;
public Coffee(CoffeeAddttives addttives) {
super();
this.addttives = addttives;
}
public abstract void makeCoffee();
}
LargeCoffee,SmallCoffee代表 RefinedAbstraction优化的抽象部分
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAddttives addttives) {
super(addttives);
}
@Override
public void makeCoffee() {
System.out.println("小杯的" + addttives.addSomething() + "咖啡");
}
}
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAddttives addttives) {
super(addttives);
}
@Override
public void makeCoffee() {
System.out.println("大杯的" + addttives.addSomething() + "咖啡");
}
}
CoffeeAddttives也就是Implementor角色,实现部分的抽象接口
/**
* 咖啡添加剂 往咖啡添加糖或者原味
*
*/
public abstract class CoffeeAddttives {
public abstract String addSomething();
}
Sugar、Ordinary也就是ConcreImplementor角色,
public class Ordinary extends CoffeeAddttives {
@Override
public String addSomething() {
return "原味";
}
}
public class Sugar extends CoffeeAddttives {
@Override
public String addSomething() {
return "加糖";
}
}
最后看客户端
public class Client {
public static void main(String[] args) {
//准备原味
Ordinary ordinary = new Ordinary();
//准备糖
Sugar sugar = new Sugar();
//原味大杯
LargeCoffee largeCoffee = new LargeCoffee(ordinary);
largeCoffee.makeCoffee();
//加糖大杯
largeCoffee = new LargeCoffee(sugar);
largeCoffee.makeCoffee();
//原味小杯
SmallCoffee smallCoffee = new SmallCoffee(ordinary);
smallCoffee.makeCoffee();
//加糖小杯
smallCoffee = new SmallCoffee(sugar);
smallCoffee.makeCoffee();
}
}
输出结果
小杯的原味咖啡
小杯的加糖咖啡
大杯的原味咖啡
大杯的加糖咖啡
这里的CoffeeAddttives对应的是UML类图中的实现部分也就是Implementor角色,而Coffee对应抽象部分,也就是Abstraction角色。
另外模式中定义的“抽象”与“实现”实质上对应的两个独立变化为 维护,所以上文才说任何维度辩护A类或者说多个树状类之间的耦合都可以使用桥接模式来实现解耦。
这里使用桥接模式也就是将是否加糖与大小杯两个维度实现了解耦。
此时如果我们想加个中杯的咖啡,只需要添加一个类
public class MiddleCoffee extends Coffee {
public MiddleCoffee(CoffeeAddttives addttives) {
super(addttives);
// TODO Auto-generated constructor stub
}
@Override
public void makeCoffee() {
System.out.println("中杯的" + addttives.addSomething() + "咖啡");
}
}
客户端稍作修改即可。添加以下代码
//原味小杯
MiddleCoffee middleCoffee = new MiddleCoffee(ordinary);
middleCoffee.makeCoffee();
//加糖小杯
middleCoffee = new MiddleCoffee(sugar);
middleCoffee.makeCoffee();
总结:
Bridge模式是一个非常有用的模式,也非常复杂,它很好的符合了开放-封闭原则和优先使用对象,而不是继承这两个面向对象原则。
桥接模式可以应用到许多开发中,但是她应用的却不是很多,主要是不好把握对于抽象与实现的分离。缺点就是不容易设计,虽然理解很简单。