设计模式之桥接模式(Bridge 模式)类的功能层次类的实现层次类的层次结构的混杂与分离桥接模式的具体实例小结

  • 类的功能层次
  • 类的实现层次
  • 桥接模式的具体事例
  • 小结

Bridge的意思是桥梁,作用就是将两边连接起来。桥接模式的作用也是如此,桥接模式分别类的功能层次类的实现层次连接起来。

这里出现了两个可能有点陌生的词汇,类的功能层次和类的实现层次。

所以我们先来介绍这两种的层次结构,因为桥接模式就是为了连接这两种层次结构。

类的功能层次

用于添加的新的功能,假如现在有一个类,我们想在这个类中添加一个新的功能,同时又不改变原有的类,那么我们可以采用继承的方法,继承自这个类,然后在继承的类中添加一个具体的新的方法。这就是类的功能层次。

  • 父类拥有基本的功能
  • 子类对类的功能进行扩展,添加的新的功能

注意:类的功能层次不能太深

类的实现层次

用于添加新的实现。假如我们现在有一个抽象类或者接口,里面定义了相应的方法,但是没有实现,对于不同的具体的实现我们需要继承这个抽象类或者实现接口,这就是类的实现层次。

  • 父类通过声明抽象方法来定义接口
  • 子类通过实现具体方法来实现接口

类的层次结构的混杂与分离

所以学习了类的功能层次和实现层次之后,我们在编写子类的就可以考虑一个问题,我们要添加功能还是添加实现。当类的层次结构只有一层的时候,功能层次结构与实现层次结构是混在一起的,这样就容易是类的层次结构变得复杂难以理解。 因此,我们需要将类的功能层次和实现层次分离为两个独立的层次结构,但又不能的简单的分开,分开之后又要添加某种联系,这种联系就是桥梁,也就是我们本文要讲的桥接模式。

桥接模式的具体实例

这个实例的功能就是打印显示某个东西。

  • 我们先考虑类的功能层次

类的功能层次只需要考虑具体需要考虑哪些,具体的实现交给实现层次去实现,那么功能层次为了调用实现层次,就需要持有一个实现层次的对象,就是委托。

功能层次的基类Display

package Bridge;

public class Display {
    private DisplatImpl impl;
    
    public Display(DisplatImpl impl) {
        this.impl = impl;
    }
    
    public void open() {
        impl.rawOpen();
    }
    
    public void print() {
        impl.rawPrint();
    }
    
    public void close() {
        impl.rawClose();
    }
    
    public final void display() {
        open();
        print();
        close();
    }
}

然后我们给这个类添加功能,可以多次显示的功能 COuntPlay:

package Bridge;

public class CountDisplay extends Display{

    public CountDisplay(DisplatImpl impl) {
        super(impl);
    }
    
    public void multiDisplay(int times) {
        open();
        for(int i=0;i<times;i++)
            print();
        close();
    }
}
  • 类的实现层次

首先,类的实现层次的基类应该是一个接口或者抽象类,他定义了需要实现的方法

package Bridge;

public abstract class DisplatImpl {
    public abstract void rawOpen();
    public abstract void rawPrint();
    public abstract void rawClose();
}

然后我们看一个真正的具体实现,实现了上述的接口

public class StringDisplayImpl extends DisplayImpl {
    private String string;                              // 要显示的字符串
    private int width;                                  // 以字节单位计算出的字符串的宽度
    public StringDisplayImpl(String string) {           // 构造函数接收要显示的字符串string
        this.string = string;                           // 将它保存在字段中
        this.width = string.getBytes().length;          // 把字符串的宽度也保存在字段中,以供使用。
    }
    public void rawOpen() {
        printLine();
    }
    public void rawPrint() {
        System.out.println("|" + string + "|");         // 前后加上"|"并显示
    }
    public void rawClose() {
        printLine();
    }
    private void printLine() {
        System.out.print("+");                          // 显示用来表示方框的角的"+"
        for (int i = 0; i < width; i++) {               // 显示width个"-"
            System.out.print("-");                      // 将其用作方框的边框
        }
        System.out.println("+");                        // 显示用来表示方框的角的"+"
    }
}

最后我们来调用这两个层次:

public class Main {
    public static void main(String[] args) {
        Display d1 = new Display(new StringDisplayImpl("Hello, China."));
        Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
        CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
        d1.display();
        d2.display();
        d3.display();
        d3.multiDisplay(5);
    }
}

运行结果:

image.png

上述实例的类图:

image.png

Bridge模式的类图也是类似的:

image.png

小结

  • 分开后更容易扩展 桥接模式的特点是将类的功能层次和实现层次分开。分开之后的好处就是有利于对它们进行扩展,当要添加新的功能的时候,只要在功能层次添加类就可以了。不必对类的实现层次做任何修改。而且增加的功能可以被所有的实现使用。

例如,如果我们程序中依赖操作系统的部分划分为max,windows和linux版,我们就可以利用类的桥接层次中的实现层次来表现这些依赖操作系统的部分。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据结构笔记

python爬虫系列之数据的存储(一):json库的使用

在上一篇文章里我们讲了 xpath写法的问题还以爬取我的文章信息写了示例,但是在上一篇中我们只是爬取并打印了信息,并没有对信息进行保存。

2402
来自专栏IMWeb前端团队

Promise接口实现之jQuery 的deferred对象

本文作者:IMWeb json 原文出处:IMWeb社区 未经同意,禁止转载 Promise是什么? 我们知道JavaScript是单线程,如果遇到某...

18410
来自专栏北京马哥教育

一篇文章学会shell工具篇之sed

? sed工具执行原理; 有关sed的参数及action的常见操作方法; 定址; 模式空间和保持空间; 使用标签 1.首先先来了解一下什么是sed? sed叫...

3157
来自专栏小灰灰

Nginx 路由转发配置笔记

Nginx 路由转发配置笔记 由于预算有限,只有一台服务器,想要玩的东西不少,所以这个台服务器上会提供多重服务,因此涉及到的nginx转发就必有重要了 由ng...

6296
来自专栏java一日一条

【Java并发编程】使用wait/notify/notifyAll实现线程间通信的几点重要说明

在 Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用 wait(...

883
来自专栏salesforce零基础学习

salesforce 零基础学习(二十四)解析csv格式内容

salesforce中支持对csv格式的内容批量导入,可以使用dataloader,然而有些情况下,当用户没有相关权限使用dataloader导入情况下,就的需...

23710
来自专栏java达人

关于hashmap在多线程环境下的一个小实验

我们都知道hashmap是非线程安全的,平时我们经常是在单线程环境下使用这个类的,现在我们模拟一个多线程环境,并发操作访问一个hashmap实例,看看会出现什么...

2585
来自专栏蓝天

用 tr 过滤文件

您可以将 tr 看作为 sed 的(极其)简化的变体:它可以用一个字符来替换另一个字符,或者可以完全除去一些字符。您也可以用它来除去重复字符。这就是所有 tr ...

863
来自专栏zhisheng

Windows 64位下安装Redis超详细教程

Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(...

38212
来自专栏LIN_ZONE

PHP 常用设计模式 (转载)

单例模式顾名思义,就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

1512

扫码关注云+社区

领取腾讯云代金券