桥接模式
介绍
结构型模式之一,顾名思义,目的为连接两边。这里的两边可以指的是两个独立变化的方向,如电器和开关,开关很多种,电器很多种,两者独立变化又是耦合。通过桥接模式,可将多维度变化类或者多个树状类之间的耦合解耦。
Android中view视图层级,控件与绘制到屏幕相关实现类DisplayList、HardWareLayer和Canvas可以看作桥接模式。Adapter和AdapteView也可以看作桥接模式。Window和WindowManager之间也可以看作桥接模式,Window为抽象部分,PhoneWindow为具体实现扩展,而WindowManager为实现部分的基类,WindowManagerImpl为具体逻辑实现,通过使用WindowManagerGlobal通过IWindowManager接口与WMS进行交互,由WMS完成具体的窗口管理工作。
UML
- Abstraction : 抽象部分,保持一个对实现部分的引用,需要调用实现部分的对象来实现。
- RefineAbstraction : 具体抽象部分,一般是抽象部分方法进行完善。
- Implementor : 实现部分,可以接口可以抽象类,一般提供基本操作,由抽象部分业务方法中来调用。
- ConcreteImplementorA、ConcreteImplementorB : 具体实现,完善实现逻辑。
其实看了UML图后,你就会发现和前一个讲到的装饰者模式挺像的。
使用场景
- 多维度变化或者多个树状图之间的耦合需要解偶时
- 避免两个层次之间建立静态的继承关系,通过桥梁模式在抽象层建立关联关系
- 不希望使用继承或者多层继承导致系统类的个数急剧增加的系统
事例
比如我们在饮品点买饮品,除开要买什么饮品,还有大杯、中杯、小杯,加冰和不加冰,那么我们用代码来实现一下.
- 建立抽象部分:这里将饮品定位抽象,持有杯抽象和加冰抽象
/**
* 先定义抽象的饮品,这里指代饮品类型
*/
public abstract class AbsBriageAction {
/**
* 持有杯大小引用
*/
private ICup iCup;
/**
* 持有加冰不加冰引用
*/
private IIce iIce;
/**
* 具体的饮品由子类去实现
*/
abstract void makeDrinks();
public void setiCup(ICup iCup) {
this.iCup = iCup;
}
public void setiIce(IIce iIce) {
this.iIce = iIce;
}
protected String getiCup() {
return this.iCup.getCup();
}
protected String getiIce() {
return iIce.getIce();
}
}
/**
* 饮品的大小杯抽象
*/
public interface ICup {
/**
* 获取大杯还是小杯
*
* @return 大杯或小杯
*/
String getCup();
}
/**
* 饮品加冰或不加冰抽象
*/
public interface IIce {
/**
* 加冰和不加冰
*
* @return 加冰或不加冰
*/
String getIce();
}
- 实现大小杯和加冰不加冰:继承杯抽象和加不加冰抽象
/**
* 大杯
*/
public class BigCup implements ICup {
@Override
public String getCup() {
return "大杯";
}
}
/**
* 小杯
*/
public class SmallCup implements ICup {
@Override
public String getCup() {
return "小杯";
}
}
/**
* 加冰
*/
public class AddIce implements IIce {
@Override
public String getIce() {
return "加冰";
}
}
/**
* 不加冰
*/
public class NoIce implements IIce {
@Override
public String getIce() {
return "不加冰";
}
}
- 在看看具体抽象:这里用橙汁和百香果汁
/**
* 橙汁
*/
public class OringeDrinks extends AbsBriageAction {
@Override
void makeDrinks() {
System.out.println("橙汁" + getiCup() + getiIce());
}
}
/**
* 百香果饮品
*/
public class PassionFruitDrinks extends AbsBriageAction {
@Override
void makeDrinks() {
System.out.println("百香果" + getiCup() + getiIce());
}
}
- 测试类:
public static void main(String[] args) {
//橙汁大杯加糖
AbsBriageAction absBriageAction = new OringeDrinks();
ICup bigCup = new BigCup();
IIce addIce = new AddIce();
absBriageAction.setiCup(bigCup);
absBriageAction.setiIce(addIce);
absBriageAction.makeDrinks();
//百香果小杯不加糖
AbsBriageAction passionFruit = new PassionFruitDrinks();
ICup smallCup = new SmallCup();
IIce noIce = new NoIce();
passionFruit.setiCup(smallCup);
passionFruit.setiIce(noIce);
passionFruit.makeDrinks();
}
- 输出:
橙汁大杯加冰
百香果小杯不加冰
类似UML中的,通过饮品抽象中的持有大小杯与加冰抽象,在抽象层建立联系,使得他们三者都可以独立进行变化。
优缺点
优点
- 分离抽象与实现,更灵活的扩展性以及对客户来说透明的实现。
缺点
- 不容易设计,理解简单,设计不容易。
总结:单看UML和装饰者还挺像的哈,不过他们的偏向是不一样的,这个结构型模式,通过在抽象层建立联系,使得组件可以独立进行变化,扩展性是挺强的,遇到类似场景的时候,可以考虑下,不过确实不太好设计。