zoukankan      html  css  js  c++  java
  • 设计模式 | 桥接模式(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)

  • 相关阅读:
    Oozie时bin/oozied.sh start或bin/oozied.sh run出现Bootstrap进程无法启动,http://bigdatamaster:11000/oozie界面也无法打开?
    [ACM] POJ 2253 Frogger (最短路径变形,每条通路中的最长边的最小值)
    Echoprint系列--Android编译与调用
    shell编程之文本与日志过滤
    C++中搜索、截取字符串
    Swift中的UIKit重力学
    hbase0.96 put流程 源码分析
    [Docker]初次接触
    工作日志2014-08-25
    Flex和Servlet结合上传文件报错(二)
  • 原文地址:https://www.cnblogs.com/imoqian/p/13870253.html
Copyright © 2011-2022 走看看