Bridge (桥梁)模式

9.1 Bridge 模式

  Bridge 的意思是 “桥梁”。就像在现实中,桥梁的功能是将河流的两侧连接起来一样,Bridge 模式的作用也是将两样东西连接起来,它们分别是 类的功能层次结构类的实现层次结构
  Bridge 模式的作用是在 “类的功能层次结构” 和 “类的实现层次结构” 之间搭建桥梁。

|| 类的层次结构的两个作用

  ◆ 希望增加新功能时
  假设现在有一个类 Something。当我们想在 Something 中增加新功能时(具体的方法),会编写一个 Something 类的子类(派生类),即 SomethingGood 类,这样就构成了一个小小的类层次结构。
在这里插入图片描述
  这就是为了增加新功能而产生的层次结构。

  • 父类具有基本功能
  • 在子类中增加新的功能
    以上这种层次结构被称为 “类的功能层次结构”。

  如果我们要继续在 SomethingGood 类的基础上增加新的功能,这是,我们可以同样地编写一个 SomethingGood 类的子类,即 SomethingBetter 类。
在这里插入图片描述
  当要增加新的功能时,我们可从各个层次的类中找出最符合自己需求的类,然后以它为父类编写子类,并在子类中增加新的功能。这就是 “类的功能层次结构”。
注意:通常来说,类的功能层次结构关系不应当过深。
  ◆ 希望增加新的实现时
  在 Template Method 模式中,学习了抽象类的作用。抽象类声明了一些抽象方法,定义了接口,然后子类负责去实现这些抽象方法。父类的任务是通过声明抽象方法的方式定义接口,而子类的任务是实现抽象方法。正是由于父类和子类的这种任务分担,我们才可以编写出具有高可替换性的类。
  这里也存在层次结构。例如,当子类 ConcreteClass 实现了父类 AbstractClass 类的抽象方法时。
在这里插入图片描述
  但是,这里的类的层次结构并非用于增加功能,也就是说,这种层次结构并非用于方便我们增加新的方法,他的真正作用是帮助我们实现下面这样的任务分担。

  • 父类通过声明抽象方法来定义结构
  • 子类通过实现具体的方法来实现接口
    这种层次结构被称为 “类的实现层次结构”。

  当我们以其他方式实现 AbstractClass 时,例如要实现一个 AnotherConcreteClass 时,类的层次结构会稍微发生一些变化。
在这里插入图片描述
  为了一种新的实现方式,我们继承了 AbstractClass 子类,并实现了其中的抽象方法,这就是类的实现层次结构。

  ◆ 类的层次结构的混杂与分离
  当我们想要编写子类时,就需要像这样确认自己的意图:“我是要增加功能呢?还是要增加实现呢?” 当类的层次结构只有一层时,功能层次结构与实现层次机构是混杂在一个层次结构中的。这样很容易使类的层次结构变得复杂,难以透彻地理解类的层次结构。 我们很难确定究竟应该在类的哪一个层次结构中去增加子类。
  因此,我们需要将 “类的功能层次结构” 与 “类的实现层次结构” 分离为两个独立的类层次结构。本章要学习的 Bridge 模式就是在这两者之间搭建桥梁,使这两者之间联系在一起。

9.2 示例程序

  作用:显示一些东西。
示例程序类图

示例程序类图
|| 类的功能层次结构:Display 类

  Display 类的功能是抽象的,负责 “显示一些东西”。该类位于 “类的功能层次结构” 的最上层。
  在 impl 字段中保存的是实现了 Display 类的具体功能的实例。该实例通过 Display 类的构造方法被传递给 Display 类,然后保存到 impl 字段中,以供后面的处理使用(impl 字段即两个层次结构的 “桥梁”)。
  注意类中的 3 个方法的实现,都调用了 impl 字段的实现方法。这样 Display 接口就被转换成了 DisplayImpl 的接口。

/**
* 负责显示的类
*
*/
public class Display {
    private DisplayImpl displayImpl;

    public Display(DisplayImpl display) {
        this.displayImpl = display;
    }

    public void open() {
        displayImpl.rawOpen();
    }

    public void print() {
        displayImpl.rawPrint();
    }

    public void close() {
        displayImpl.rawClose();
    }

    public final void display() {
        open();
        print();
        close();
    }
}
|| 类的功能层次结构:CountDisplay 类

  CountDisplay 类在 Display 类的基础上增加了一个功能。Display 类只具有显示的功能,而 CountDisplay 类则具有 “只显示规定的次数” 的功能,这就是 multiDisplay 方法。
  CountDisplay 类继承了 Display 类的 open、print、close 方法,并使用它们来增加这个新功能。这就是 “类的功能层次结构”。

/**
* 类的功能层次结构: CountDisplay 类
* 增加了 只显示规定次数 功能
*/
public class CountDisplay extends Display{

    public CountDisplay(DisplayImpl display) {
        super(display);
    }

    public void multiDisplay(int times) {
        open();
        // 循环打印 times 次
        for (int i = 0; i < times; i++) {
            print();
        }
        close();
    }
}
|| 类的实现层次结构:DisplayImpl 类

  桥的另一侧 - “类的实现层次结构”
  DisplayImpl 类位于 “类的实现层次结构” 的最上层。
  DisplayImpl 类是抽象类,声明了 rawOpen、rawPrint、rawClose 这3个抽象方法。

/**
* 类的实现层次结构:DisplayImpl 类
*/
public abstract class DisplayImpl {

    public abstract void rawOpen();
    public abstract void rawPrint();
    public abstract void rawClose();
}
|| 类的实现层次结构:StringDisplayImpl 类

  真正的实现, StringDisplayImpl 类是显示字符串的类。他继承了 DisplayImpl 类,作为其子类来使用 3 个抽象方法进行显示。

/**
* 类的实现层次结构,继承DisplayImpl,作为其子类来使用
*/
public class StringDisplayImpl extends DisplayImpl{
    private String str;
    private int width;

    public StringDisplayImpl(String str) {
        this.str = str;
        this.width = str.getBytes().length;
    }

    @Override
    public void rawOpen() {
        printLine();
    }

    @Override
    public void rawPrint() {
        System.out.println("|" + str + "|");
    }

    @Override
    public void rawClose() {
        printLine();
    }

    private void printLine() {
        System.out.print("+");
        for (int i = 0; i < width; i++) {
            System.out.print("-");
        }
        System.out.println("+");
    }
}

  DisplayImpl、StringDisplayImpl 这两个类相当于 “类的实现层次结构”。

|| Main 类

  将上述 4 个类组合起来显示字符串。

public class Main {
    public static void main(String[] args) {
        Display d1 = new Display(new StringDisplayImpl("Hello, China."));
        Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
        CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
        d1.display();
        d2.display();
        d3.display();
        d3.multiDisplay(5);
    }
}

  运行结果:

+-------------+
|Hello, China.|
+-------------+
+-------------+
|Hello, World.|
+-------------+
+----------------+
|Hello, Universe.|
+----------------+
+----------------+
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
|Hello, Universe.|
+----------------+
9.3 Bridge 模式中的登场角色

  ◆ Abstraction (抽象化)
  该角色位于 “类的功能层次结构” 的最上层。它使用 Implementor 角色的方法定义了基本的功能。该角色中保存了 Implemetor 角色的实例。在实例程序中,由 Display 类扮演此角色。
  ◆ RefinedAbstraction(改善后的抽象化)
  在 Abstraction 角色的基础上增加了新功能的角色。在示例程序中,由 CountDisplay 类扮演此角色。
  ◆ Implementor (实现者)
  该角色位于 “类的实现层次结构” 最上层。它定义了用于实现 Abstaction 角色的接口的方法。在示例程序中,由 DisplayImpl 类扮演此角色。
  ◆ Abstraction (具体实现者)
  该角色负责实现在 Implementor 角色中定义的接口。在示例程序中,由 StringDisplayImpl 类扮演此角色。
  Bridge 模式的类图如下所示。左侧的两个类构成了 “类的功能层次结构”,右侧两个类构成了 “类的实现层次结构”。类的两个层次结构之间的桥梁是 impl 字段。
Bridge 模式的类图

Bridge 模式的类图
9.4 拓展思路的要点
|| 分开后更容易扩展

  Bridge 模式的特征是将 “类的功能层次结构” 与 “类的实现层次结构” 分离开了。将类的这两个层次结构分离开有利于独立地对它们进行扩展。
  当想要增加功能时,只需要在 “类的功能层次结构” 一侧增加类即可,不必对 “类的实现层次结构” 做任何修改。而且,增加后的功能可以被 “所有的实现” 使用。
  例如,可以将 “类的功能层次结构” 应用于软件所运行的操作系统上。如果我们将某个程序中依赖于操作系统的部分划分为 Windons 、Mac、Unix 版,那么我们可以用 Bridge 模式中的 “类的实现层次结构” 来表现这些依赖于操作系统的部分。我们需要编写一个定义这些操作系统的共同接口的 Implementor 角色,然后编写 Windows、Mac、Unix 版的 3 个 ConcreteImplementor 角色。这样一来,无论在 “类的功能层次结构” 中增加多少功能,它们都可以工作于这3个操作系统上。

|| 继承是强关联,委托是弱关联

  虽然继承很容易扩展类,但是类之间也形成了一种强关联关系。只有通过修改代码,才可以改变这种关系。
  如果想要很轻松地改变类之间的关系,我们可以使用 “委托” 来代替 “继承” 关系。示例程序中 Display 类中使用了 “委托”。Display 类的 impl 字段保存了实现的实例,使得类的任务发生了转移。Display 类并非自己工作,而是将工作 “交给 impl”。
  
  

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值