结构篇-桥接模式

Posted zhixuChen333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构篇-桥接模式相关的知识,希望对你有一定的参考价值。

文章目录


前言

桥接模式(Bridge)能将抽象与实现分离,使二者可以各自单独变化而不受对方约束,使用时再将它们组合起来,就像架设桥梁一样连接它们的功能,如此降低了抽象与实现这两个可变维度的耦合度,以保证系统的可扩展性。


提示:以下是本篇文章正文内容,下面案例可供参考

一、基础建设

人类社会的发展有一条不变的规律,即“要致富,先修路”。路桥作为重要的交通基础设施,在经济发展中扮演着不可或缺的角色。它可以把原本相对独立的区域连接起来,使得贸易往来更加便利与高效,从而极大地促进经济合作与发展。古代丝绸之路连通了东西方的经贸往来,让各个国家取长补短、互惠互利,最终使各方经济发展纷纷受惠。

古有丝绸之路,21世纪则有全球化。桥接模式类似于这种全球化劳动分工的经济模式。全球产业分工后,国家可以发挥各自的优势,制造自己最擅长的产品组件,再通过合作组成产业链,以此提高生产效率并实现产品多元化。拿手机制造来说,芯片可以由美国设计制造,屏幕可以由韩国制造,摄像头则可以由日本制造……最后由中国制造其他半导体组件并完成手机的组装,从而形成手机制造产业链并使产品高效生产。如此一来,每个国家都能发挥自己的长处,生产各式各样的组件,最终组装出各种品类的产品,其中各种品牌、型号、配置应有尽有,以此满足不同的用户需求,这便是桥接模式的最大价值。

二、形与色的纠葛

既然基础建设如此重要,那么我们就用实例来分析一下桥接模式下的产业分工与合作。假设我们要画一幅抽象画,它主要由各种形状的色块组成,以此来表达世界的多样性。

1.画笔抽象类

要完成这幅作品,不同颜色的画笔是必不可少的工具,那么相应地我们就得定义这些画笔工具类。首先抛开画笔的颜色,画笔本身一定是类似的,所以我们定义一个画笔抽象类。

public abstract class Pen 
    
    public abstract void getColor();

    public void draw()
        getColor();
        System.out.println("△");
    

说明:

  1. 画笔抽象类定义了抽象方法getColor()获取颜色,并交给子类实现不同的颜色;接着在绘图方法draw()中先调用getColor()以获取具体的颜色,然后画出一个三角形

2.黑色画笔类

public class BlackPen extends Pen
    @Override
    public void getColor() 
        System.out.print("黑");
    

要点:

  1. 黑色画笔类实现了获取颜色方法getColor(),并输出了字符串“黑”,以此来模拟黑色墨水的输出。

3.客户端类

public class Client 
    public static void main(String[] args) 
        Pen blackPen = new BlackPen();
        blackPen.draw();
    

输出结果:
黑△

说明:

  1. 我们调用黑色画笔类的绘图方法draw()后成功输出了“黑△”(黑色三角形)。同理,我们可以继续定义白色画笔类,画出“白△”(白色三角形)。然而,不管我们制造多少种颜色的画笔,都只能画出三角形,这是因为我们在抽象类里硬编码了对“△”的输出,这就造成了形状被牢牢地捆绑于各类彩色画笔中,对于其他形状的绘制则无能为力,使系统丧失了灵活性与可扩展性。

三、架构产业链

我们已经利用画笔的抽象实现了颜色的多态,现在要解决的问题是对形状的抽离,将形状与颜色彻底分离开来,使它们各自扩展。既然颜色是由画笔来决定的,那么形状可以依赖尺子来规范其笔触线条走向。我们设想这样一个场景,画笔与尺子这两种工具分别产于南北两座孤岛,北岛擅长制造各色画笔,南岛则擅长制造各种形状的尺子。

1.尺子接口

尺子的功能是对笔触线条走向进行规范。为了让尺子各尽其能而不至于毫无章法地扩展,我们先定义一个尺子的高层接口。

public interface Ruler 
    public void regularize();

2.具体实现

尺子接口定义了笔触线条走向规范方法regularize(),为各种形状的尺子实现留好了接口。为保持简单,我们在这里忽略形状的大小,假设一种形状对应一个类,那么应该有正方形尺子类、三角形尺子类以及圆形尺子类。

//正方形尺子类
public class SquareRuler implements Ruler
    @Override
    public void regularize() 
        System.out.println("□");
    


//三角形尺子类
public class TriangleRuler implements Ruler
    @Override
    public void regularize() 
        System.out.println("△");
    


//圆形尺子类
public class CircleRuler implements Ruler
    @Override
    public void regularize() 
        System.out.println("○");
    

3.画笔抽象类

依照南、北岛的产业合作模式,我们同样需要对北岛产业进行重新规划,也就是对之前的画笔类相关代码进行重构。因为画笔必须有尺子的协助才能完成漂亮的画作,所以我们假设北岛制造处于“产业链下游”,修改之前的画笔抽象类,使其能够用到尺子。

public abstract class Pen 
    protected Ruler ruler;//尺子的引用

    public Pen(Ruler ruler) 
        this.ruler = ruler;
    

    public abstract void draw();

说明:

  1. 画笔类声明了尺子接口的引用,并在构造方法中将尺子对象注入进来,这样画笔就能使用尺子进行绘画了,此处便是南北产业通过桥梁的对接形成产业链的关键点。
  2. 绘图方法draw()被我们抽象化了,毕竟抽象画笔并不能确定将来要画什么形状、什么颜色、如何画等细节,所以应该留给画笔子类去实现。

4.画笔实现类

最后,我们来实现具体颜色的画笔子类。为了保持简单,我们只实现黑色和白色两种颜色的画笔。

//黑色画笔
public class BlackPen extends Pen
    public BlackPen(Ruler ruler) 
        super(ruler);
    

    @Override
    public void draw() 
        System.out.print("黑");
        ruler.regularize();
    


//白色画笔
public class WhitePen extends Pen
    public WhitePen(Ruler ruler) 
        super(ruler);
    

    @Override
    public void draw() 
        System.out.print("白");
        ruler.regularize();
    

5.客户端类

public class Client 
    public static void main(String[] args) 
        //白色画笔对应的所有形状
        new WhitePen(new CircleRuler()).draw();
        new WhitePen(new SquareRuler()).draw();
        new WhitePen(new TriangleRuler()).draw();

        //黑色画笔对应的所有形状
        new BlackPen(new CircleRuler()).draw();
        new BlackPen(new SquareRuler()).draw();
        new BlackPen(new TriangleRuler()).draw();
    

输出结果:
白○
白□
白△
黑○
黑□
黑△

说明:

  1. 客户端对各种画笔与尺子进行了相关的实例化操作,在实例化白色画笔时为其注入三角形尺子,如输出所示,这时它所画出的图形为白色三角形。有了桥接模式,客户端便可以任意组装自己需要的颜色与形状进行绘图了。

四、笛卡尔积

以上的组合方式可以用笛卡尔积表示:

颜色集合 = 黑,白,形状集合 = 圆形,正方形,三角形

那么这两个集合的笛卡尔积为:

(黑,圆形),黑,正方形),黑,三角形),

(白,圆形),白,正方形),白,三角形),

我们的例子其实比较简单,只是2色3形的笛卡儿积组合,如果再加入更多的颜色与形状,笛卡儿积的结果数量会大得惊人。举个例子,我们现有7种颜色和10种形状,组合起来就有70(7×10)种可能,假如设计程序时我们只用继承的方式去实现每种可能,那么至少需要70个类。如果颜色与形状不断增多,系统可能会出现代码冗余以及类泛滥的情况,之后每加一种颜色或形状都将举步维艰,系统扩展工作将会是一场灾难。如果利用桥接模式的设计,我们只需要17(7+10)个类便可以组装成任意可能了,并且之后对任何维度的扩展也是轻而易举的。

总结

提示:这里对文章进行总结:

  1. 桥接模式构架了一种分化的结构模型,巧妙地将抽象与实现解耦,分离出了2个维度(尺子与画笔)并允许其各自延伸和扩展,最终使系统更加松散、灵活。

  2. 我们可以把桥接模式分为“抽象方”与“实现方”2个维度阵营,其中各角色的定义如下:

    • Abstraction(抽象方):抽象一方的高层接口,多以抽象类形式出现并持有实现方的接口引用,对应本章例程中的画笔类。
    • AbstractionImpl(抽象方实施):继承自抽象方的具体子类实现,可以有多种实施并在抽象方维度上自由扩展,对应本章例程中的黑色画笔和白色画笔。
    • Implementor(实现方):实现一方的接口规范,从抽象方中剥离出来成为另一个维度,独立于抽象方并不受其干扰,对应本章例程中的尺子接口。
    • ConcreteImplementor(实现方实施):实现一方的具体实施类,可以有多个实施并在实现方维度上自由扩展,对应本章例程中的正方形尺子类、三角形尺子类、圆形尺子类。

以上是关于结构篇-桥接模式的主要内容,如果未能解决你的问题,请参考以下文章

从零开始学习Java设计模式 | 结构型模式篇:桥接模式

Java进阶篇设计模式之四 -----适配器模式和桥接模式

LInux下桥接模式详解二

Java设计模式之四 ----- 适配器模式和桥接模式

结构型模式--桥接模式

手撸golang 结构型设计模式 桥接模式