一、基本概念
1.1 定义
桥接模式将 抽象部分 和 实现部分 分离,使它们可以独立的变化。抽象部分 会拥有 实现部分的接口对象,有了该对象后,就能够通过这个接口来调用 具体实现部分的功能。
桥接在程序上就体现成了 抽象部分拥有实现部分的接口对象,维护桥接就是维护这个关系,桥接模式中的桥接是一个 单方向 的关系,只能够 抽象部分去使用实现部分的对象,而不能反过来。
1.2 Demo
- 定义 实现部分的接口或者抽象类,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分这些基本操作的业务的方法。
/**
* 实现部分的接口对象。
*/
public interface Implementor {
/**
* 操作行为。
*/
void operation();
}
其具体的实现分为两种:
public class ImplementorA implements Implementor {
@Override
public void operation() {
Log.d("Implementor", "ImplementorA.operation");
}
}
和
public class ImplementorB implements Implementor {
@Override
public void operation() {
Log.d("Implementor", "ImplementorB.operation");
}
}
- 抽象部分 拥有 实现部分的接口对象,抽象部分 中的方法需要调用 实现部分的对象 来实现,该类一般为抽象类。
/**
* 抽象部分。
*/
public abstract class Abstraction {
/**
* 抽象部分拥有实现部分的接口对象。
*/
private Implementor mImplementor;
/**
* 设置接口对象。
*
* @param implementor 接口对象。
*/
public void setImplementor(Implementor implementor) {
this.mImplementor = implementor;
}
/**
* 获取接口对象。
*
* @return 接口对象。
*/
public Implementor getImplementor() {
return mImplementor;
}
/**
* 调用接口对象的方法来完成操作。
*/
protected void operation() {
if (mImplementor != null) {
mImplementor.operation();
}
}
}
- 优化的抽象部分,即抽象部分的实现类。
/**
* 抽象部分的具体实现。
*/
public class RefinedAbstraction extends Abstraction {
@Override
protected void operation() {
getImplementor().operation();
}
}
1.3 应用场景
- 如果一个系统需要在构建的 抽象化角色 和 具体化角色 之间增加更多的灵活性,避免在两个层次之间建立静态的 继承联系,可以通过桥接模式使他们在抽象层建立一个 关联关系。
- 那些不希望使用继承或因为多层次继承导致系统类的个数极具增加的系统。
- 一个类存在 两个独立变化的维度,而这两个维度都需要进行扩展。
二、Android 源码应用
2.1 Window 体系
在 Framework 源码解析知识梳理(2) - 应用进程与 WMS 的通信实现 一文中,我们介绍了应用进程与WMS
的通信模式,它其实就是桥接模式的一个体现,其架构体系图如下所示:
对应的映射关系为:
-
Window
->Abstraction
-
PhoneWindow
->RefinedAbstraction
-
WindowManager
->Implementor
-
WindowManagerImpl
->ImplementorA/ImplementorB
2.2 Adapter 体系
三、项目应用场景
3.1 列表加载案例
依照惯例,举一个在实际项目中用到桥接模式的例子,这是我们项目中用于处理 图片列表预加载 的代码,我们定义了两个
AsyncListView
AsyncLoader
业务场景是这样的:当列表滚动的时候,需要根据列表当前展示Item
的可见区域进行计算,对于区域外满足条件的Item
分别进行不同的处理:
- 可见范围内:发起请求,优先级为高
- 可见范围内,加载范围内:发起请求,优先级为低
- 加载范围外,缓存范围内:取消请求,但不缓存请求
- 缓存范围外:清除缓存
这里我们就会出现两个维度:
- 负责计算可视区域的
AsyncListView
,其实现类有可能是ListView
、RecyclerView
、GridView
。 - 负责加载数据的
AsyncLoader
,其实现类有可能是RecyclerView.Adapter
、BaseAdapter
等。
这时候就需要桥接模式,将这两个维度嫁接起来,架构图如下所示:
这里的抽象部分就是AsyncListView
,它拥有实现部分的接口对象AsyncLoader
:
- 抽象部分
AsyncListView
根据可见范围,计算出各种请求的Position
,通过其内部持有的实现部分的接口对象AsyncLoader#onWindowSliding
进行通知。 - 实现部分
AsyncLoader
收到通知后,根据Position
找到对应的数据,然后发起或者取消请求。