桥接模式也称为桥梁模式,是结构型设计模式之一。
将抽象部分与实现部分分离,使它们都可以独立进行变化。
从模式定义中我们了解到,这里“桥梁的”作用其实就是连接“抽象部分”与“实现部分”,但事实上,任何多维度变化类或者说多个树状类之间的耦合都可以使用桥接模式来实现解耦。
如果一个系统需要在构建的抽象化角色和具体角色之间增加更多灵活性,避免在两个层次之间建立静态的继承关系,可以通过桥接模式使它们在抽象层建立一个关联关系。
对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加,可考虑使用桥接模式。
一个类存在两个独立变化的维度,且这两个类都需要扩展。
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\Implementor.java
//实现部分的抽象接口
public interface Implementor {
/**
* 实现抽象部分的具体方法
*/
public void operationImpl();
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\ConcreteImplementorA.java
public class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
//具体实现
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\ConcreteImplementorB.java
public class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
//具体实现
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\Abstraction.java
public abstract class Abstraction {
private Implementor mImplementor;//声明一个私有成员变量引用实现部分的对象
/**
* 通过实现部分对象的引用构造抽象部分的对象
* @param implementor 实现部分对象的引用
*/
public Abstraction(Implementor implementor) {
mImplementor = implementor;
}
/**
*通过调用实现部分具体的方法实现具体的功能
*/
public void operation() {
mImplementor.operationImpl();
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\RefinedAbstraction.java
public class RefinedAbstraction extends Abstraction {
/**
* 通过实现部分对象的引用构造抽象部分的对象
*
* @param implementor 实现部分对象的引用
*/
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
/**
* 对父类抽象部分中的方法进行分离
*/
public void refinedOperation() {
//对Abstration中的方法进行扩展
}
}
角色介绍
Abstraction:抽象部分。
该类保持一个对实现部分对象的引用,抽象部分的方法需要调用实现部分的对象来实现,该类一般为抽象类。
RefinedAbstraction:优化的抽象部分。
抽象部分的具体实现,该类一般是对抽象部分的方法进行完善和扩展。
Implementor:实现部分。
可以为接口或者抽象类,其方法不一定要与抽象的部分中的一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分这些操作的业务方法。
ConcreteImplementorA/ConcreteImplementorB:实现部分的具体实现。
完善实现部分中定义的具体逻辑。
Client:客户类,客户端程序。
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\Coffee.java
//Coffee类保持了对CoffeeAdditives的引用,以便调用具体的实现。同样地,咖啡还分大杯、小杯,定义两个子类继承于Coffee
public abstract class Coffee {
protected CoffeeAdditives impl;
public Coffee(CoffeeAdditives impl) {
this.impl = impl;
}
/**
* 咖啡具体什么样子由子类决定
*/
public abstract void makeCoffee();
}
注意,这里的CoffeeAdditives其实就对应于我们UML类图中的实现部分,而Coffee则对应于抽象部分。
模式定义的所谓的“抽象”与“实现”实质上对应的是两个独立变化的维度,因此,上文我们说过,任何多维度变化类或者说多个树状类之间的耦合都可以使用桥接模式来实现解耦。在本例中,Coffee类虽然是一个抽象类,但它并非是所谓的“抽象部分”,而CoffeeAdditives也并非一定就是“实现部分”,两者各自为一维度,独立变化仅此而已。
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\CoffeeAdditives.java
而对于加进咖啡中的糖,当然也可以选择不加,定义一个抽象类
public abstract class CoffeeAdditives {
/**
* 具体要往咖啡中添加什么也是子类实现
* @return
*/
public abstract String addSomething();
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\LargeCoffee.java
public class LargeCoffee extends Coffee {
public LargeCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
Log.v(BRIDGE_PATTERN, "大杯的" + impl + "咖啡");
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\SmallCoffee.java
public class SmallCoffee extends Coffee {
public SmallCoffee(CoffeeAdditives impl) {
super(impl);
}
@Override
public void makeCoffee() {
Log.v(MainActivity.BRIDGE_PATTERN, "小杯的" + impl + "咖啡");
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\Ordinary.java
public class Ordinary extends CoffeeAdditives {
@Override
public String addSomething() {
return "原味";
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\Sugar.java
public class Sugar extends CoffeeAdditives {
@Override
public String addSomething() {
return "加糖";
}
}
D:\Users\user\ProjectFive\BridgePattern\app\src\main\java\bridgepattern\gome\com\bridgepattern\MainActivity.java
public class MainActivity extends AppCompatActivity {
public static String BRIDGE_PATTERN = "bridge_pattern";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//原味
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();
}
}
桥接模式在Android中应用相当广泛,但一般而言都是作用于大范围的,我们可以在源码中找到很多桥接模式的应用。比如在View的视图层级中,CheckBox、CompoundButton、Button、TextView和View之间构成一个继承关系的视图层级,每一层视图都仅仅是对一种类型控件的描述,其定义了该控件所拥有的基本属性和行为,但是将它们真正绘制到屏幕的部分是由与View相关的功能实现类DisplayList、HardwareLayer和Canvas负责。这两部分之间的关系可以看做是对桥接模式的应用。
除此以外,Adapter与AdapterView之间也可以看作是对桥接模式的应用。
在framework层面,有没有对桥接模式比较经典的应用呢?答案是肯定的。
比较典型的就是Window与WindowManager之间的关系
如上图所示,在framework中Window和PhoneWindow构成窗口的抽象部分,其中Window类为该抽象部分的抽象接口,PhoneWindow为抽象部分具体的实现扩展。
而WindowManager则为实现部分的基类,WindowManagerImpl为实现部分具体的逻辑实现,其使用WindowManagerGlobal通过IWindowManager接口与WindowManagerService(也就是我们所说的WMS)进行交互,并由WMS完成具体的窗口管理工作,如下为Window与WindowManager 桥梁搭建的主要代码。
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
* window manager. It provides standard UI policies such as a background, title
* area, default key processing, etc.
*(顶级窗口外观和行为策略的抽象基类。 一个
应该将此类的实例用作添加到的顶级视图
窗口管理员。 它提供标准的UI策略,例如背景,标题
区域,默认密钥处理等)
* The only existing implementation of this abstract class is
* android.view.PhoneWindow, which you should instantiate when needing a
* Window.
*/
public abstract class Window {
... ...
/**
* Set the window manager for use by this Window to, for example,
* display panels. This is not used for displaying the
* Window itself -- that must be done by the client.
*
* @param wm The window manager for adding new windows.
*/
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
//默认关闭硬件,加速调用重载方法
setWindowManager(wm, appToken, appName, false);
}
/**
* Set the window manager for use by this Window to, for example,
* display panels. This is not used for displaying the
* Window itself -- that must be done by the client.
*
* @param wm The window manager for adding new windows.
*/
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
//如果传入的WindowManager为空,则通过getSystemService获取WindowManager
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//将WindowManager与Window绑定
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
}
参考《Android源码设计模式》