设计模式-桥接模式

桥接模式介绍

桥接模式(Bridge Pattern)也称为桥梁模式,是结构型设计模式之一。顾名思义其与现实中的桥梁作用相同,有连接两岸的作用。

桥接模式定义

将抽象部分和实现部分分离,使它们都可以独立地进行变化。

桥接模式使用场景

  1. 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
  2. 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

桥接模式 UML 图


角色介绍:

  • Abstraction:抽象部分。该类保持了一个对象实现部分的引用,该类或者继承类可通过调用实现部分对象的方法来完成一些功能。
  • RefinedAbstraction:优化的抽象部分。该类是对抽象部分的方法进行完善和扩展。
  • Implementor:实现部分。定义一类功能的基本操作。
  • ConcreteImplementor:具体实现部分。

桥接模式实现

现实生活中桥接模式的应用很多,比如喝咖啡,杯子大小可以分为大杯、小杯,甜度可以分为加糖、不加糖,杯子大小与加糖与否是独立变化的,但对于咖啡两者又存在联系;再比如笔,粗细可以分为0.7mm 笔头,0.5mm笔头,颜色可以分为红色、黑色,两者彼此独立,也存在联系。

看完例子可能并不能体会到桥接模式,下面就笔的生产为例,笔头有0.7mm、有0.5mm笔头,暂且我们以大、小来区分,我们设计的类结构如下:


没毛病,这时假如我们要生产两种颜色的笔,分别为黑色、红色。这时比较直接的设计如下:

看似没毛病,细思极恐,这才是项目初期,假如我们笔的粗细还增加了0.3mm,0.25mm等,颜色增加到了 5 种颜色;再假如我们除了支持笔的粗细、笔的颜色、还支持带笔帽、或者为自动笔等,这样显著问题就是类的数量爆棚,另一个问题就是牵一发而动全身。对象的继承关系实在编译就定义好了,所以无法运行时改变从父类继承的实现。子类的实现与它的父类就非常紧密的依赖,以至于父类实现中的任何变化都会导致子类的变化。这种依赖关系限制了灵活性并最终限制了复用性。

笔的大小与颜色变化独立,属于两个维度,我们可以将其分离,重新设计如下:


这样笔的大小和颜色就分离开来,两者可以独立变化,笔支持持有了颜色的引用,在这里是聚合的关系,当需要生产黑色 0.77mm笔时,只需要在 BigPen 中通过Color的应用设置颜色即可。这种就是桥接模式。
抽象部分(Abstraction)

public abstract class Pen {
    protected Color color;

    public Pen(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

优化的抽象部分(RefinedAbstraction)

public class BigPen extends Pen {
    public BigPen(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("0.7mm的" + color.makeColor() + "笔");
    }

}
public class SmallPen extends Pen {
    public SmallPen(Color color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("0.5mm的" + color.makeColor() + "笔");
    }
}

实现部分

public interface Color {
    String makeColor();
}

具体的实现部分

public class BlackColor implements Color {
    @Override
    public String makeColor() {
        return "黑色";
    }
}
public class RedColor implements Color {
    @Override
    public String makeColor() {
        return "红色";
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        Color redColor = new RedColor();
        Color blackColor = new BlackColor();
        Pen pen1 = new BigPen(redColor);
        Pen pen2 = new BigPen(blackColor);
        Pen pen3 = new SmallPen(redColor);
        Pen pen4 = new SmallPen(blackColor);
        pen1.draw();
        pen2.draw();
        pen3.draw();
        pen4.draw();
    }
}

运行结果:

0.7mm的红色笔
0.7mm的黑色笔
0.5mm的红色笔
0.5mm的黑色笔

如果需要增加是否带笔帽,只需新建接口,在 Pen 中传入即可,只增加必要的类,并且每个维度可以独立变化,也符合了开放-封闭原则。

总结

优先使用对象的组合、聚合有助于保持每个类的封装,并被集中在单个任务上。这样类和类继承层次可以保持较小规模。

优点
1.分离抽象接口及其实现部分。提高了比继承更好的解决方案。
2.桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
3.实现细节对客户透明,客户无需关心实现细节,它已经由抽象层通过聚合关系完成了封装。

注意事项
桥接模式是非常简单的,使用该模式时主要考虑如何拆分抽象和实现,并不是一涉及继承就要考虑使用该模式,那还要继承干什么呢?桥接模式的意图还是对变化的封装,尽量把可能变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。因此读者在进行系统设计时,发现类的继承有N层时,可以考虑使用桥接模式。

Android 源码中的桥接模式

在应用层,对于普通控件、View 和 Canvas 就可以看做桥接模式,View 为抽象角色,Canvas 为实现角色。
在 Framwork 内部的源码中,比较经典的就是 Window 、WindowManager 和 WindowManagerService 之间的关系,如下图:


  • Window 和 PhoneWindow 构成了窗口的抽象部分,Window 为抽象接口,PhoneWindow 为抽象部分的具体实现及扩展。
  • WindowManager 为实现部分的实现接口,WindowManagerImpl 为实现部分的具体逻辑实现。

这就是桥接模式。其中 WindowManagerImpl 使用 WindowManagerGlobal 对象,通过 IWindowManager 接口与 WindowManagerService 进行交互,并有 WMS 完成具体的窗口管理工作。

Window 和 WindowManager 的桥梁搭建的主要代码如下:
Window.java

public abstract class Window {
    private WindowManager mWindowManager;
    ...
    
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

  public WindowManager getWindowManager() {
      return mWindowManager;
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343