设计模式 – 桥接模式详解

  • 2020 年 3 月 30 日
  • 筆記

基本介绍

  • 桥接模式是一种结构型设计模式。
  • 将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。
  • 基于类的最小设计原则,通过封装、聚合、继承等行为让不同的类承担不同的职责。
  • 它的主要特点是把抽象与行为实现分离,从而可以保持各部分的独立性以及应对它们的功能扩展。

UML 类图

桥接模式案例

我们以手机为例,手机有品牌(诺基亚、摩托罗拉)和样式(折叠式、直立式),我们需要生产不同的品牌和样式,比如折叠式诺基亚、直立式摩托罗拉… …

「抽象」 – 手机品牌,都有开机和关机的功能

public interface PhoneBrand {      void open();      void close();  }  

「具体」 – 手机品牌 Nokia 和 Moto

public class Nokia implements PhoneBrand {      @Override      public void open() {          System.out.println("诺基亚开机...");      }        @Override      public void close() {          System.out.println("诺基亚关机...");      }  }  
public class Moto implements PhoneBrand {      @Override      public void open() {          System.out.println("摩托罗拉开机...");      }        @Override      public void close() {          System.out.println("摩托罗拉关机...");      }  }  

「抽象」 – 手机类,以聚合的方式与品牌产生联系,充当着“桥”的角色

public abstract class AbsPhone{        private PhoneBrand brand;        public AbsPhone(PhoneBrand brand) {          this.brand = brand;      }        protected void open(){          brand.open();      }        protected void close(){          brand.close();      }  }  

「具体」 – 折叠式手机 和 直立式手机

public class FoldingPhone extends AbsPhone{        public FoldingPhone(PhoneBrand brand) {          super(brand);      }        @Override      protected void open() {          System.out.print("折叠式 - ");          super.open();      }        @Override      protected void close() {          System.out.print("折叠式 - ");          super.close();      }  }  
public class UpRightPhone extends AbsPhone{        public UpRightPhone(PhoneBrand brand) {          super(brand);      }        @Override      protected void open() {          System.out.print("直立式 - ");          super.open();      }        @Override      protected void close() {          System.out.print("直立式 - ");          super.close();      }  }  

测试

@Test  public void test(){      AbsPhone p1 = new FoldingPhone(new Nokia());      p1.open();      p1.close();      System.out.println();      AbsPhone p2 = new UpRightPhone(new Moto());      p2.open();      p2.close();  }  

结果

折叠式 - 诺基亚开机...  折叠式 - 诺基亚关机...    直立式 - 摩托罗拉开机...  直立式 - 摩托罗拉关机...  

如果我们想创建其他类型的手机,只需要改变创建方式即可。

桥接模式分析

  1. 实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统。
  2. 对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其它的部分由具体业务来完成。
  3. 桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本。
  4. 桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
  5. 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性,即需要有这样的应用场景。

桥接模式在 JDBC 中的应用

在 Java 中我们通常使用 JDBC 连接数据库,但是数据库的种类有很多(MySQL、Oracle…),它们的连接方式、协议都不尽相同,很显然不能为每种数据库都写一个接口,这样就违背了精简设计原则,于是Java设计师就提供一套接口给厂商们自己实现,一套接口给用户调用。

我们在使用 JDBC 的时候需要写这样的代码

Class.forName("数据库驱动名");  Connection conn = DriverManager.getConnection("数据库url", "用户名", "密码");  

其过程是这样的:

  • Class.forName() 的时候,通过反射机制,将 .class 文件加载进Java虚拟机内存中,Driver 类初始化,执行以下代码,向 DriverManager 中注册一个驱动。DriverManager是个 Driver 容器,管理不同的 Driver

    static {      try {          DriverManager.registerDriver(new Driver());      } catch (SQLException var1) {          throw new RuntimeException("Can't register driver!");      }  }  
  • 我们获取连接时,DriverManager 就会根据驱动返回一个相应的数据库连接

    @CallerSensitive  public static Connection getConnection(String url,      java.util.Properties info) throws SQLException {      return (getConnection(url, info, Reflection.getCallerClass()));  }  

实际应用场景

对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

  • 银行转账系统
    • 转账分类:网上转账,柜台转账,AMT 转账
    • 转账用户类型:普通用户,银卡用户,金卡用户…
  • 消息管理
    • 消息类型:即时消息,延时消息
    • 消息分类:手机短信,邮件消息,QQ 消息…