IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java设计模式——桥接模式 -> 正文阅读

[Java知识库]Java设计模式——桥接模式

一、概述

桥接模式主要是将抽象和实现解耦,使得两者都可以独立变化

在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有 m×n 种,不但对应的子类很多,而且扩展困难。不同颜色和字体的文字、不同品牌和功率的汽车

桥接将继承转为关联,降低类之间的耦合度,减少代码量

试想一下,以手机为例,手机有翻盖式的,有推拉式的还有直板式的,而手机的品牌又多种多样,如果我们将每一种手机样式和品牌组合,那么就需要创建非常多的类很容易发生类爆炸问题,比如小米翻盖手机、小米推拉式手机、小米直板式手机……华为翻盖手机、华为推拉式手机等等等等,如果我们为每一种都创建一个类,这样做就会造成我们的项目中需要维护的对象大量冗余,维护成本也随之提高,而且实际上这些种类往往是无比繁多的。

桥接模式的好处就在于,我们将其中一个部分结构分离出去,成为一个独立的扩展,然后通过组合的方式将独立出去的部分再添加到我们的本类中,而本类可以通过抽象类继承的方式来进行扩展,独立的部分也可以通过实现接口或继承的方式进行扩展。

二、角色与UML图

2.1 角色与职责

Abstraction(抽象化角色)

  • 定义抽象类的接口
  • 维护一个指向Implementor类型对象的指针

RefinedAbstraction(扩展抽象化角色)

  • 扩充一由Abstraction定义的接口

Implementor(抽象实现化角色)

  • 定义实现类的接口,该接口不一定要和Abstraction的接口完全一致,事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作

ConcreteImplementor(具体实现化角色)

  • 实现Implementor接口并定义它的具体实现

2.2 UML图

在这里插入图片描述

三、示例

以手机为例,我们来构建不同品牌的不同样式的手机,可以将品牌与手机的样式拆分为两个独立的模块,使其可扩展性更强

具体类图如下所示:在这里插入图片描述
首先我们创建抽象类BasePhone

/**
 * @author ZhongJing </p>
 * @Description 手机抽象类 </p>
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
public abstract class BasePhone {

    /**
     * 组合品牌
     */
    private Brand brand;

    protected void open() {
        this.brand.open();
    }

    protected void close() {
        this.brand.close();
    }

    protected void call() {
        this.brand.call();
    }

}

然后我们编写一个折叠手机类和直板式手机类,让这两个类继承我们的BasePhone抽象类

/**
 * @author ZhongJing </p>
 * @Description 折叠手机实现类 </p>
 */
public class FoldedBasePhone extends BasePhone {

    public FoldedBasePhone(Brand brand) {
        super(brand);
    }

    public void open() {
        System.out.print("折叠手机");
        super.open();
    }

    public void close() {
        System.out.print("折叠手机");
        super.close();
    }

    public void call() {
        System.out.print("折叠手机");
        super.call();
    }

}

/**
 * @author ZhongJing </p>
 * @Description 直板手机实现类 </p>
 */
public class UpRightBasePhone extends BasePhone {

    public UpRightBasePhone(Brand brand) {
        super(brand);
    }

    public void open() {
        System.out.print("直板手机");
        super.open();
    }

    public void call() {
        System.out.print("直板手机");
        super.call();
    }

    public void close() {
        System.out.print("直板手机");
        super.close();
    }

}

创建品牌的抽象接口,也可以是抽象类,按照个人喜好

/**
 * @author ZhongJing </p>
 * @Description 品牌抽象接口 </p>
 */
public interface Brand {

    void open();

    void close();

    void call();

}

创建华为和小米两个品牌

/**
 * @author ZhongJing </p>
 * @Description 华为手机品牌 </p>
 */
public class HuaWei implements Brand {

    @Override
    public void open() {
        System.out.println("华为手机开机");
    }

    @Override
    public void close() {
        System.out.println("华为手机关机");
    }

    @Override
    public void call() {
        System.out.println("华为手机打电话");
    }
}


/**
 * @author ZhongJing </p>
 * @Description 小米手机品牌 </p>
 */
public class Mi implements Brand {

    @Override
    public void open() {
        System.out.println("小米手机开机了");
    }

    @Override
    public void close() {
        System.out.println("小米手机关机");
    }

    @Override
    public void call() {
        System.out.println("小米手机打电话");
    }
}

按照我们的类图创建好之后我们就可以开始测试了

/**
 * @author ZhongJing </p>
 * @Description 测试类 </p>
 */
public class Client {

    public static void main(String[] args) {

        // 获取折叠手机
        FoldedBasePhone phone1 = new FoldedBasePhone(new Mi());

        phone1.open();
        phone1.call();
        phone1.close();

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

        FoldedBasePhone phone2 = new FoldedBasePhone(new HuaWei());
        phone2.open();
        phone2.call();
        phone2.close();

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

        // 获取直板手机
        UpRightBasePhone phone3 = new UpRightBasePhone(new Mi());

        phone3.open();
        phone3.call();
        phone3.close();

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

        UpRightBasePhone phone4 = new UpRightBasePhone(new HuaWei());
        phone4.open();
        phone4.call();
        phone4.close();

    }

}

运行结果如下:

折叠手机小米手机开机了
折叠手机小米手机打电话
折叠手机小米手机关机
-------------
折叠手机华为手机开机
折叠手机华为手机打电话
折叠手机华为手机关机
-------------
直板手机小米手机开机了
直板手机小米手机打电话
直板手机小米手机关机
-------------
直板手机华为手机开机
直板手机华为手机打电话
直板手机华为手机关机

四、使用场景

桥接模式的使用场景如下

  • 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时
  • 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
  • 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时

在Java中的InputStreamReader就使用到了桥接模式,不过不是纯粹的桥接模式,而是桥接模式+适配器模式
在这里插入图片描述
上图可以看到,在大体上来讲,这是一个桥接模式,通过分离其中一部分实现再组合对象的方式来进行操作

在这里插入图片描述
在这里插入图片描述
可以看到所有的操作基本上实际上都是由组合进来的sd来操作的

而我们的sd是由一个叫StreamDecoder.forInputStreamReader()方法获得的,这个StreamDecoder就是一个适配器,点进去源码我们可以看到是他对Reader和InputStream进行了适配在这里插入图片描述
在这里插入图片描述
而这种方式就是我们在适配器模式一问文提到的对象适配器

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 01:50:01  更:2022-01-14 01:51:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:01:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码