设计模式13——桥接模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。

桥接模式(Bridge)

是一种结构型模式。

目录

一、概述

1.1、主要的角色(如果有点懵的话就先跳过着小部分):

1.2、直观的理解桥接模式要干什么:

1.3、上述手机应用例子的UML图:

二、桥接模式的模板

2.1、对象之间的关系用UML图表示如下:

2.2、Java版的代码如下:


一、概述

1、将抽象部分与它的实现部分分离,使它们都可以独立地变化;
2、(实现:是指抽象类以及抽象类的派生类,对于它们的实现类。)这些实现类应该分离;
3、和 合成|聚合复用原则 相关;
4、实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。

1.1、主要的角色(如果有点懵的话就先跳过)

主要的角色分两种,但从代码(或技术)实现的角度看(为了充分使用面向对象语言的3大特性封装、继承、多态,还另外需要抽象类或接口)可能有4个:

  1. 实现类:实现类的抽象类或接口 +实现类
  2. 新提取的类:新提取的类的抽象类或接口 +新提取的类的实现类

1.2、直观的理解桥接模式要干什么:

以手机应用软件为例,常用的手机软件有微信、淘宝、美团等等。并且有着不同的手机,有着不同的操作系统,但都可以使用这些软件。(这个例子可能不恰当,但对于理解桥接模式还是可以的,所以请先停止一些细节上的吐槽)

现在假设你是应用程序开发者,你需要在开发出微信、淘宝、美团,并且你还要让它们可以在鸿蒙和苹果手机上运行:

如果按照以前的思路,那肯定是把微信开发两个版本分别运行在鸿蒙和苹果系统上,同样淘宝也是开发两个,美团也是,这样做的话要设计6个对象即可,但万一又有新的需求这样就并不一定好使了。就假设现在要开发10个软件,并且都适配4个系统,那么按照以前的思路,那你需要设计 10*4=40 个对象, 如果再多点呢,那工作量将是难以想象,并且你也清楚有很多适配工作是重复的。

那么我们可以这样,把操作系统和应用软件分开看:

此时有5个对象,相比老办法已经少一个对象了,当然如果手机应用软件更多那么少的也会更多。

  • 应用软件都定义一个统一的接口,每个应用软件都实现这个接口,但不同的是微信的实现后的结果是可以聊天,淘宝实现后的结果是可以购物,美团实现后的结果是可以点外卖。
  • 操作系统也都定义一个统一的运行应用程序的接口,每个操作系统针对接口的具体实现是完成对任何一个应用软件对象在自己的系统上正常运行。

这样再结合多态,就可以实现上面概念里的第一句话,‘将抽象部分与它的实现部分分离,使它们都可以独立地变化’。

也就是抽象分离出两部分:操作系统 + 应用软件;并且它们两可以独立增加或减少。

此时你可能会发现对于手机应用程序来说他有着不同的维度,如功能维度和运行环境维度。像这种一个事物但是对应多个维度,也就是说某个目标对象可以被抽象出多个抽象类,那么就可以尝试使用桥接模式,这样也就符合合成|聚合复用原则。

(想简单了解原则的可以点击下面链接)

设计模式2——原则篇极简版

1.3、上述手机应用例子的UML图:

如何使用?(也就是主程序要怎么调用这些对象)

先填装再使用。

如:可以给鸿蒙系统填装一个应用,然后调用操作系统的运行接口就可以让此应用运行。

(注:本例是以操作系统和应用程序看成一个一个类对象为角度去方便解释桥接模式,从而假设可以让操作系统和应用各自实现各自的统一接口,但现实开发中并非如此理想化) 

对应上文的角色分类,在本例中,把应用软件看为解决原本问题的实现类,而操作系统是在此基础上又新提取或抽象出的新提取的类。从代码角度讲:新提取的类是主程序最终调用的类,而实现类是被新提取的类调用,刚好对应我们点击图标后,操作系统接收到我们触摸屏幕的信号,然后再启动应用程序。

(再举例:物品-----对应颜色维度和形状维度)

二、桥接模式的模板

2.1、对象之间的关系用UML图表示如下:

2.2、Java版的代码如下:

实现类(抽象):

abstract class Implementor {
    public abstract void operation();
}

具体的实现类1:

public class ConcreteImplementor1 extends Implementor{
    @Override
    public void operation() {
        System.out.println("具体实现1的方法执行");
    }
}

具体的实现类2:

public class ConcreteImplementor2 extends Implementor{
    @Override
    public void operation() {
        System.out.println("具体实现2的方法执行");
    }
}

抽象分类对象(抽象):

abstract class Abstraction {
    protected Implementor implementor;

    public void setImplementor(Implementor implementor) {
        this.implementor = implementor;
    }

    public abstract void operation();
}

提炼后的抽象分类对象A:

public class RefinedAbstractionA extends Abstraction {
    @Override
    public void operation() {
        System.out.println("提炼后的A");
        implementor.operation();
    }
}

提炼后的抽象分类对象B:

public class RefinedAbstractionB extends Abstraction {
    @Override
    public void operation() {
        System.out.println("提炼后的B");
        implementor.operation();
    }
}

主程序(发起请求的类):

public class Main {
    public static void main(String[] args) {
        Abstraction abstraction;
        abstraction = new RefinedAbstractionA();
        abstraction.setImplementor(new ConcreteImplementor1());
        abstraction.operation();

        abstraction.setImplementor(new ConcreteImplementor2());
        abstraction.operation();

        System.out.println("------------------");

        abstraction = new RefinedAbstractionB();
        abstraction.setImplementor(new ConcreteImplementor1());
        abstraction.operation();

        abstraction.setImplementor(new ConcreteImplementor2());
        abstraction.operation();
    }
}

这里暂时就不再例其它编程语言的例子了,可以把上面的Java例子复制到你本地,运行main函数试一下加深理解。这些代码都是我自己学习的时候根据一些教材手敲的,不存在bug可以直接运行。

如果觉得本文还不错,就请点个赞给作者一点鼓励吧!如果有建议,也请评论指教和讨论!

  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值