设计模式 | 桥接模式(bridge)

定义:

将抽象部分与它的实现部分分离,使它们都可以独立地变化

结构:(书中图,侵删)

 

一个抽象类,用于聚合实现
若干个实现抽象类的类
一个实现的父类
若干个实现了父类的具体实现类

实例:

我想到了一个工作中的例子,通常我们需要去对接一些第三方平台。
假如最开始你需要对接淘宝平台,去创建销售单。然后过段时间又需要去对接京东平台,也是要创建销售单。
你的类结构大概是这样的:

 

出于面向对象考虑,你可能会给平台加个父类,变成这样:

 

这时候又告诉你,你需要给两个平台都添加获取订单的功能,然后变成这样:

 

假设接下来又要给每个平台添加创建退货单,抓取退货单,然后又新加了两个平台,amazon,ebay什么的。
那简直就是灾难。代码没法复用,复制粘贴可不算复用,虽然每个平台都会有些不一样,但是功能本身是大同小异的。
于是呢,就引出了我们的桥接模式,按照我的理解来说,就是将系统按照各个维度拆分出来,每个维度都是独立的部分,互不影响,同时通过一座桥(这里指聚合,后面会细讲)把他们连接起来。
修改之后的类结构是这样:

 

操作父类:

package designpattern.bridge;

public abstract class Operation {
    public abstract void operate();
}

创建订单类:

package designpattern.bridge;

public class CreateOrder extends Operation {
    @Override
    public void operate() {
        System.out.println("创建订单");
    }
}

获取订单类:

package designpattern.bridge;

public class GetOrders extends Operation {
    @Override
    public void operate() {
        System.out.println("获取订单");
    }
}

平台父类(聚合类):

package designpattern.bridge;

public abstract class Platform {
    protected Operation operation;

    public void setOperation(Operation operation) {
        this.operation = operation;
    }

    public abstract void operate();
}

淘宝类:

package designpattern.bridge;

public class Taobao extends Platform {
    @Override
    public void operate() {
        System.out.print("淘宝->");
        operation.operate();
    }
}

京东类:

package designpattern.bridge;

public class JingDong extends Platform {
    @Override
    public void operate() {
        System.out.print("京东->");
        operation.operate();
    }
}

客户端:

package designpattern.bridge;

public class Client {
    public static void main(String[] args) {
        Operation createOrder=new CreateOrder();
        Operation getOrder=new GetOrders();
        
        Platform tb=new Taobao();
        tb.setOperation(createOrder);
        tb.operate();
        tb.setOperation(getOrder);
        tb.operate();
        
        System.out.println("==============================");
        
        Platform jd=new JingDong();
        jd.setOperation(createOrder);
        jd.operate();
        jd.setOperation(getOrder);
        jd.operate();
    }
}

结果输出:

淘宝->创建订单
淘宝->获取订单
==============================
京东->创建订单
京东->获取订单

 

 番外:

书中还提到一个原则:

 

然后在《effective java》这本书也看到了类似的内容,角度又有些不同:

 

大概说的是,子类必须依附于父类,如果父类修改了,子类必须得跟着一起改。甚至父类新增了一个和子类签名相同,但是返回类型不同的方法,会导致你的编译不通过。
解决方法,就是复合,也是上面说的合成-》新类不继承父类,而是包含一个拥有父类(虽然没有继承,为了前后统一,还是称之为父类)实例的域,通过这个实例去访问父类的方法。
上文提到的包装类是指的装饰模式(decorator),这里就不展开了,感兴趣的可以看看之前写的文章:设计模式 | 装饰模式(decorator)

总结:

核心还是解耦,以及开放-封闭原则。要想方设法的让新增功能的时候不影响之前的代码。设计模式只是表现形式不一样,内核都差不多。
桥接模式在系统出现多维度的时候就可以考虑使用,其实这种是在最开始就能预见到的,比如文中举的例子,通常都能想到未来可能增加功能和平台,所以在写第一个平台的第一个功能的时候就应该有意识的去设计。(哈哈哈,打脸来得总是这么的触不及防,刚说要提前去设计,就在下一章看见了文尾图中的内容)
最后就是在使用继承前要再三的确认是不是“is a”关系,即便是也不要轻易的使用继承,复合往往是更优先的选择。

 

 

 关于上图说的命令模式,可见:设计模式 | 命令模式(Command)

 

 

posted @ 2020-10-24 17:50  莫愆  阅读(401)  评论(0编辑  收藏  举报