桥接模式
一、概述
一般问题:一个类需要在两个以上维度扩展,采用继承方式会导致子类数量过多
核心方案:将抽象部分与实现部分分离,使其都可以独立变化
设计意图:桥接模式不是将两个不相干的类链接,而是将一个需要多维度变化的类拆分成抽象部分和实现部分,并且在抽象层对两者做组合关联,是用组合的方式来解决继承的问题。举个例子,如果一个类在两个维度分别有m和n种变化,采用继承的方式就需要扩展出m*n个子类,且一个维度每增加一种变化就多出另一个维度变化总数的子类;如果将两个维度拆分再组合,加起来也只有m+n个子类,且每个维度独立扩展,一个维度增加一种变化只需要增加1个子类。
如上图,Abstraction就是桥接模式中的“桥”,它含有一个实现部分实例,且提供动态设置具体实现类地方法,这样抽象部分和实现部分的子类可以随意组合。
下面举一个简单的例子:夏天都喜欢吃烧烤,就以烧烤为例,我们从两个维度分析:从食材上有鸡翅、鸡腿等;从风味上有微辣、特辣等。
我们把食材做为抽象部分,把风味作为实现部分:
先看实现部分变化:
风味类Spicy
public interface Spicy{ String taste(); }
微辣SlightSpicy
public class SlightSpicy implements Spicy{ public String taste(){ return "微辣"; }
}
特辣ExtraSpicy
public class ExtraSpicy implements Spicy{ public String taste(){ return "特辣"; } }
再看抽象部分变化:
烧烤类Barbecue
public abstract class Barbecue{ protected Spicy mSpicy; //实现部分实例 public Barbecue(Spicy spicy){ 桥接模式的关键,组合实现和抽象 this.mSpicy= spicy; } public abstract void eat(); }
鸡翅类ChickenWing
public class ChickenWing extends Barbecue{ public ChickenWing (Spicy spicy){ super(spicy); } public void eat(){ System.out.println( "鸡翅:"+super.mSpicy.taste()); } }
测试:
public class Test{ public static void main(String[] args){ Barbecue barbecue = new ChickenWing(new SlightSpicy()); barbecue .eat(); Barbecue barbecue2 = new ChickenWing(new ExtraSpicy()); barbecue2 .eat(); } }
输出:
鸡翅:微辣
鸡翅:特辣
二、实战应用
我们知道Android中ListView的Adapter的设计用到了适配器模式,实际上Adapter本身还包含在一个桥接模式之中!
上图是整个AdapterView类图,对比桥接模式的UML图,不难看出整体上它是个大的桥接模式,我们抽取其中的AbsListView这个小的桥接模式来分析:
AbsListView表示集合视图,其有两个维度变化:
- 显示形式变化,如列表形式ListView或网格形式GridView;
- 数据类型变化,如字符串数组SimpleAdapter或数据库游标CursorAdapter
Android将显示形式作为抽象部分,数据类型作为实现部分,两个部分各自独立变化。
抽象部分和实现部分在AbsListView抽象层做了组合关联,体现代码如下:
public abstract class AbsListView extends AdapterView<ListAdapter>{ ListAdapter mAdapter; @Override public void setAdapter(ListAdapter adapter) { if (adapter != null) { mAdapterHasStableIds = mAdapter.hasStableIds(); if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds && mCheckedIdStates == null) { mCheckedIdStates = new LongSparseArray<Integer>(); } } clearChoices(); } }
三、总结
总结:桥接模式是一种结构型设计模式,根据最小继承原则,将各个变化部分分离,从而实现独立变化互不干涉,但又在更高的抽象层实现组合以保证各子类能动态结合。
用一句话来概括桥接模式:
“打断骨头还连着筋”
优点:
- 抽象和实现分离
- 易于扩展
缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。