1.介绍
桥接模式,又称为桥梁模式,是结构型设计模式之一。在现实生活中大家都知道“桥梁”是连接河道两岸的主要交通枢纽,简而言之其作用就是连接河流的两边,而我们的桥接模式与现实中的情况很相似,也是承担着连接“两边”的作用。
2.使用场景
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,可以通过桥接模式使他们在抽象层建立一个关联关系。
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,也可以考虑使用桥接模式。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
3.认识桥接模式
桥接模式角色图角色介绍
-
Abstraction: 抽象部分。
该类保持一个对实现部分对象的引用,抽象部分中的方法需要调用实现部分的对象来实现,该类一般为抽象类。 -
RefinedAbstraction: 优化的抽象部分。
抽象部分的具体实现,该类一般是对抽象部分的方法进行完善和扩展。 -
Implementor: 实现部分。
可以为接口或抽象类,其方法不一定要与抽象部分中的一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分这些基本操作的业务方法。 -
ConcreteImplementorA/ConcreteImplementorB: 实现部分的具体实现。
完善实现部分中方法定义的具体逻辑。 - Client: 客户类,客户端程序。
从代码上看
- 实现部分的抽象接口
public interface Implementor{
//实现抽象部分的具体方法
public void operationImpl();
}
- 实现具体部分的实现
public class ConcreteImplementorA implements Implementor{
@Override
public void operationImpl(){
//具体的实现
}
}
public class ConcreteImplementorB implements Implementor{
@Override
public void operationImpl(){
//具体的实现
}
}
- 抽象部分的实现
public absteact class Abstraction{
//生命一个私有成员变量引用实现部分的对象
private Implementor mImplementor;
//通过实现部分对象的引用构造抽象部分的对象
public Abstraction (Implementor implementor) {
mImplementor = implementor;
}
//通过调用实现部分具体的方法实现具体的功能
public void operation(){
mImplementor.operationImpl();
}
}
- 抽象部分的子类
public class RefinedAbstraction extends Abstraction{
public RefinedAbstraction (Implementor implementor){
super(implementor);
}
//对父类抽象部分中的方法进行扩展
public void refinedOperation(){
//对Abstraction中的方法扩展
}
}
- 客户类
public class Client{
public static void main(String[] args){
//客户调用逻辑
}
}
简单实现
简单设计一个场景,一般我们去吃牛排,服务员都会询问你,吃什么牛排,要加什么汁,几成熟。我们可以把“服务员”,“牛排”,“汁”,“几成熟”定义为桥接模式的成员:
- Client: 服务员
- Abstraction: 加什么汁,要几成熟
- RefinedAbstractionA: 黑椒汁
- RefinedAbstractionB: 七成熟
- Implementor:吃什么牛排
- ConcreteImplementorA: 服务员来一份菲力牛排(Filet Steak)
- ConcreteImplementorB: 服务员再来一份西冷牛排(Sirloin Steak)
代码实现
- Implementor
public interface Steak {
public void addSomething(String something);
}
- ConcreteImplementorA
public class FiletSteak implements Steak {
@Override public void addSomething(String something) {
Log.i("mytag",something);
}
}
- ConcreteImplementorB
public class SirloinSteak implements Steak {
@Override
public void addSomething(String something) {
Log.i("mytag",something);
}
}
- Abstraction
public abstract class Orders {
protected Steak impl;
public Orders(Steak impl){
this.impl = impl;
}
public void writeOrder(String something){
this.impl.addSomething(something);
}
}
- RefinedAbstractionA
public class Sauce extends Orders{
public Sauce(Steak impl) {
super(impl);
}
@Override
public void writeOrder(String sauce) {
super.writeOrder(sauce);
}
}
- RefinedAbstractionB
public class Cooked extends Orders {
public Cooked(Steak impl) {
super(impl);
}
@Override
public void writeOrder(String cooked) {
super.writeOrder(cooked);
}
}
- Client
//服务员出场Log.i("mytag","客官请问想吃什么牛排");
//我选择菲力牛排
Steak steak = new FiletSteak();
steak.addSomething("菲力牛排");
Log.i("mytag","客官请问加什么汁");
//我选择黑椒汁
Orders orders = new Sauce(steak);
orders.writeOrder("黑椒汁");
Log.i("mytag","客官请问要几成熟");
//7成最好吃
orders = new Cooked(steak);
orders.writeOrder("七成熟");
//分隔线
Log.i("mytag","-------------------------");
//同理西冷牛排
Log.i("mytag","客官请问还想吃什么牛排");
steak = new SirloinSteak();
steak.addSomething("西冷牛排");
Log.i("mytag","客官请问加什么汁");
orders = new Sauce(steak);
orders.writeOrder("番茄汁");
Log.i("mytag","客官请问要几成熟");
orders = new Cooked(steak);
orders.writeOrder("全熟");
编译代码:
Paste_Image.pngAndroid源码中的桥接模式实现
桥接模式在Android中应用得相当广泛,但一般而言都是作用于大范围的,我们可以在源码中很多地方看到桥接模式的应用。例如我们常用的Adapter跟AdapterView之间就是一个桥接模式。
首先ListAdapter.java:
public interface ListAdapter extends Adapter{
//继承自Adapter,扩展了自己的两个实现方法
public boolean areAllItemsEnabled();
boolean isEnabled(int position);
}
这里先来看一下父类AdapterView:
public abstract class AdapterView<T extends Adapter> extends ViewGroup {
//这里需要一个泛型的
Adapter public abstract T getAdapter();
public abstract void setAdapter(T adapter);
}
接着来看ListView的父类AbsListView,继承自AdapterView
public abstract class AbsListView extends AdapterView<ListAdapter>
//继承自AdapterView,并且指明了T为ListAdapter
/** * The adapter containing the data to be displayed by this view */
ListAdapter mAdapter;
//代码省略
//这里实现了setAdapter的方法,实例了对实现化对象的引用
public void setAdapter(ListAdapter adapter) {
//这的adapter是从子类传入上来,也就是listview,拿到了具体实现化的对象
if (adapter != null) {
mAdapterHasStableIds = mAdapter.hasStableIds();
if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds && mCheckedIdStates == null) {
mCheckedIdStates = new LongSparseArray<Integer>();
}
}
if (mCheckStates != null) {
mCheckStates.clear();
}
if (mCheckedIdStates != null) {
mCheckedIdStates.clear();
}
}
大家都知道,构建一个listview,adapter中最重要的两个方法,getCount()告知数量,getview()告知具体的view类型,接下来看看AbsListView作为一个视图的集合是如何来根据实现化对象adapter来实现的具体的view呢?
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//省略代码
//这里在加入window的时候,getCount()确定了集合的个数
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
}
接着来看
View obtainView(int position, boolean[] isScrap) {
//代码省略
//这里根据位置显示具体的view,return的child是从持有的实现对象mAdapter里面的具体实现的
//方法getview来得到的。
final View child = mAdapter.getView(position, scrapView, this);
//代码省略 return child;
}
接下来在ListView中,onMeasure调用了obtainView来确定宽高,在扩展自己的方法来排列这些view。知道了
这些以后,我们来画一个简易的UML图来看下:
以上就是Android源码中的桥接模式实现
桥接模式的优缺点
优点
-
分离抽象和实现部分
桥接模式分离了抽象和实现部分,从而极大地提高了系统的灵活性。让抽象部分和实现部分独立开来,分别定义接口,这有助于对系统进行分层,从而产生更好的结构化的系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。 -
灵活的扩展性
由于桥接模式把抽象和实现部分分离开了,而且分别定义接口,这就使得抽象部分和实现部分可以分别独立的扩展,而不会相互影响,从而大大的提高了系统的可扩展性。可动态切换实现。
由于桥接模式把抽象和实现部分分离开了,那么在实现桥接的时候,就可以实现动态的选择和使用具体的实现,也就是说一个实现不再是固定的绑定在一个抽象接口上了,可以实现运行期间动态的切换实现。
缺点
-
不容易设计
对开发者要有一定的经验要求。
最后放出一个链接,文中的Android源码中的模式实现就是出自此处:
http://blog.csdn.net/u010405231/article/details/49618511
关于桥接模式就介绍到这里,后面可能会看心情再介绍一下别的设计模式。
更多精彩文章请扫描下方二维码关注微信公众号"AndroidCzh":这里将长期为您分享原创文章、Android开发经验等!
QQ交流群: 705929135
网友评论