【Java设计模式】桥接模式


✍ 在介绍桥接模式之前,我们引入一个场景:

设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4 个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:

  • 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
  • 第二种设计方案是根据实际需要对形状和颜色进行组合。

对于有 两个变化维度 ( 即两个变化的原因 ) 的系统 , 采用 方案二 来进行设计系统中类的个数更少 , 且系统扩展更为方便 。相比方案一是非常好的选择。之所以引出这个简单的例子,是因为设计方案二即是桥接模式的应用 。 桥接模式 将继承关系转换为关联关系, 从而 降低了类与类之间的耦合 , 减少了代码编写量

给桥接模式下个定义就是:

桥接模式(Bridge Pattern) : 将抽象部分与它的实现部分分离,使它们都可以独立地变化 。它是一种对象结构型模式,又称为柄体(Handle and Body) 模式或接口(Interface)

桥接模式包含如下角色:

  • Abstraction:抽象类:定义抽象类,并包含一个对实现类接口 的引用。
  • RefinedAbstraction:扩充抽象类:是抽象类角色的子类,实现父类中的业务方法,并通过组合关系调用实现类接口角色中的业务方法。
  • Implementor:实现类接口:定义实现类接口,供扩展抽象类角色调用。
  • ConcreteImplementor:具体实现类:给出实现类接口角色接口的具体实现。

✍ 演示一下:

具体的实现委托给了Account接口(Implementor:实现类接口)

public interface Account {
    Account openAccount();
    void showAccountType();
}

抽象类Bank (Abstraction:抽象类)

public abstract class Bank {
    protected Account account;  //只有子类能拿到account
    public Bank(Account account){
       this.account = account;
    }
    abstract Account openAccount();
}

定期账号(ConcreteImplementor:具体实现类)

//定期账号
public class DepositAccount implements Account{
    @Override
    public Account openAccount() {
        System.out.println("打开定期账号");
        return new DepositAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个定期账号");
    }
}

活期账号(ConcreteImplementor:具体实现类)

//活期账号
public class SavingAccount implements Account{
    @Override
    public Account openAccount() {
        System.out.println("打开活期账号");
        return new SavingAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个活期账号");
    }
}

ABC银行(RefinedAbstraction:扩充抽象类)

public class ABCBank extends Bank{
    public ABCBank(Account account) {
        super(account);
    }

    @Override
     Account openAccount() {
        System.out.println("打开ABC银行账号");
        account.openAccount();
        return account;//account来自父类
    }
}

ICBC银行(RefinedAbstraction:扩充抽象类)

public class ICBCBank extends Bank{
    public ICBCBank(Account account) {
        super(account);
    }

    @Override
    Account openAccount() {
        System.out.println("打开ICBC银行账号");
        account.openAccount();
        return account;//来自抽象类
    }
}

测试类;

public class Test {
    public static void main(String[] args) {
        Bank icbcBank = new ICBCBank(new DepositAccount());
        Account icbcAccount = icbcBank.openAccount();
        icbcAccount.showAccountType();

        Bank abcBank = new ABCBank(new SavingAccount());
        Account abcAccount = abcBank.openAccount();
        abcAccount.showAccountType();
    }
}

类图:
【Java设计模式】桥接模式_第1张图片
关注实线
换一种画法:
【Java设计模式】桥接模式_第2张图片

✍ 理解桥接模式,重点需要理解如何将 抽象化(Abstraction) 与 实现化(Implementation) 脱耦 ,使得二者可以独立地变化。

  • 抽象化:抽象化就是忽略一些信息,把不同的实体当作同样的实体对待。在面向对象中,将对象的共同性质抽取出来形成类的程即为抽象化的过程。
  • 实现化:针对抽象化给出的具体实现,就是实现化,抽象化与实现化是一对互逆的概念,实现化产生的对象比抽象化更具体,是对抽象化事物的进一步具体化的产物。
  • 脱耦:脱耦就是将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联,将两个角色之间的继承关系改为关联关系。桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。

✍ 说一下桥接模式的优缺点:
桥接模式的优点

  • 分离抽象接口及其实现部分。
  • 桥接模式有时类似于多继承方案,但是多继承方案违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差,而且多继承结构中类的个数非常庞大,桥接模式是比多继承方案更好的解决方法。
  • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
  • 实现细节对客户透明,可以对用户隐藏实现细节。

桥接模式的缺点

  • 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
  • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

✍ 在以下情况下可以使用桥接模式:

  • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • 抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
  • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
  • 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
  • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

✍ 桥接模式的应用有很多比如:
一个 Java 桌面软件总是带有所在操作系统的视感(LookAndFeel) ,如果一个Java 软件是在Unix 系统上开发的,那么开发人员看到的是Motif 用户界面的视感;在Windows 上面使用这个系统的用户看到的是Windows 用户界面的视感;而一个在Macintosh 上面使用的用户看到的则是Macintosh 用户界面的视感,Java 语言是通过所谓的Peer 架构做到这一点的。Java为AWT 中的每一个GUI 构件都提供了一个Peer 构件, 在AWT 中的Peer 架构就使用了桥接模式

JDBC 驱动程序也是桥接模式的应用之一。使用JDBC 驱动程序的应用系统就是抽象角色,而所使用的数据库是实现角色。 一个JDBC 驱动程序可以动态地将一个特定类型的数据库与一个Java 应用程序绑定在一起,从而实现抽象角色与实现角色的动态耦合。

✍ 适配器模式与桥接模式的联用

桥接模式和适配器模式用于设计的不同阶段,桥接模式用于系统的初步设计,对于存在两个独立变化维度的类可以将其分为抽象化和实现化两个角色,使它们可以分别进行变化;而在初步设计完成之后,当发现系统与已有类无法协同工作时,可以采用适配器模式。但有时候在设计初期也需要考虑适配器模式,特别是那些涉及到大量第三方应用接口的情况。

【Java设计模式】桥接模式_第3张图片

你可能感兴趣的:(Java设计模式)