设计模式之桥接模式

写在前面

本文看下桥接设计模式。

1:介绍

1.1:什么时候桥接设计模式

当一个业务场景由多个变化维度组成,并且这多个变化的维度到底有多少种情况是不确定,比如现在我们要为瑞幸咖啡写一个系统,很自然的,需要在系统中来表示咖啡,此时思考下,咖啡有哪些维度呢,当然首先是咖啡,这是确定的,但是以下的维度却是不确定的:

1:杯子的大小,可能是大杯,中杯,小杯
2:咖啡的味道,可能是原味,加糖,加奶,加糖和奶

对于以上的这个场景,我们就可以考虑使用桥接设计模式来实现。

1.2:UML类图

原型设计模式,包含如下元素:

1:抽象化(Abstraction)角色使用多个变化维度中一个来定义,一个定义一个抽象类
2:修正抽象化(RefinedAbstraction)角色继承抽象化角色,增加额外的操作,如无特殊需求,可不需要(我理解的)
3:实现化(Implementor)角色多个变化维度的一个
4:具体实现化角色实现化角色子类,提供某个变化维度的具体变化类型

UML图如下:

在这里插入图片描述

2:实例

源码 。

2.1:场景

现在有一个接口有一个方法需要一个List<String>的参数,但是客户端只能提供逗号分割的字符串作为参数,这样就可以定义一个接受逗号分割的字符串参数的接口,并提供实现进行适配。

2.2:程序

比如现在我们要为瑞幸咖啡写一个系统,很自然的,需要在系统中来表示咖啡,此时思考下,咖啡有哪些维度呢,当然首先是咖啡,这是确定的,但是以下的维度却是不确定的:

1:杯子的大小,可能是大杯,中杯,小杯
2:咖啡的味道,可能是原味,加糖,加奶,加糖和奶

这里我们将杯子的大小来作为抽象化角色。

  • 定义实现化角色
    定义了往咖啡中加什么调料。
// 咖啡中加糖,牛奶,等的抽象接口(实现化的顶层接口)
// 抽象的是在咖啡中加什么东西(糖,牛奶,等)
public interface ICoffeeAdditives {void addSomething();
}
  • 定义具体实现化角色
    这里分别实现加奶和加糖,其它的需要的类比添加接口。
// 加奶(最终会加到咖啡中,生成加奶咖啡)
public class Milk implements ICoffeeAdditives {@Overridepublic void addSomething() {System.out.println("加奶");}
}//加糖
public class Sugar implements ICoffeeAdditives {@Overridepublic void addSomething() {System.out.println("加糖");}
}
  • 定义抽象化角色
// 抽象化Abstraction
// 抽象是咖啡杯(大杯,小杯,中杯等)
public abstract class Coffee {// 保存一个实现话的引用,从而确定另外一个变化维度的信息protected ICoffeeAdditives additives;// 这里就好像桥一样,将抽象化和实现化连接在了一起,也正是桥接设计模式名称的来源public Coffee(ICoffeeAdditives additives){this.additives=additives;}// 客户点咖啡方法的抽象public abstract void orderCoffee(int count);
}

以上在构造函数中获取往咖啡加调料的类,就好像是一个桥一样,将杯子大小和咖啡加的调料建立了联系,这也是桥接设计模式中的桥接名称的来源。

  • 定义修正抽象话角色

这里仅仅是为了学习的完整性,但并无实际作用。

// 修正抽象化角色,增加新的操作,个人认为该类可有可无,如果没有特殊的需求
// ,在桥接设计模式中也可以没有该类
public abstract class RefinedCoffee extends Coffee {public RefinedCoffee(ICoffeeAdditives additives) {super(additives);}//    public void checkQuality() {
//        Random ran = new Random();
//        System.out.println(String.format("%s 添加%s", additives.getClass().getSimpleName(), ran.nextBoolean() ? "太多" : "正常"));
//    }
}
  • 定义被子大小维度的大杯和小杯
public class SmallCoffee extends RefinedCoffee {public SmallCoffee(ICoffeeAdditives coffeeAdditives) {super(coffeeAdditives);}@Overridepublic void orderCoffee(int count) {// 点了几杯咖啡System.out.println("点了" + count + " 小杯咖啡!");// 加什么super.additives.addSomething();}
}public class LargeCoffee extends RefinedCoffee {public LargeCoffee(ICoffeeAdditives coffeeAdditives) {super(coffeeAdditives);}@Overridepublic void orderCoffee(int count) {// 点了几杯咖啡System.out.println("点了" + count + " 大杯咖啡!");// 加什么super.additives.addSomething();}
}
  • 测试
// 两大杯加奶
@Test
public void testCase1() {RefinedCoffee largeWithMilk = new LargeCoffee(new Milk());largeWithMilk.orderCoffee(2);
}

输出:

点了2 大杯咖啡!
加奶
// 8小杯加糖
@Test
public void testCase2() {SmallCoffee smallCoffee = new SmallCoffee(new Sugar());smallCoffee.orderCoffee(8);
}

输出:

点了8 小杯咖啡!
加糖

写在后面

参考文章列表

秒懂设计模式之桥接模式(Bridge Pattern) 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/26994.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云计算的学习(四)

四、云计算中的存储基础知识 1.云计算虚拟化中的存储架构 ①虚拟化存储 在虚拟化存储架构中&#xff0c;最底层为物理磁盘。 底层的硬件组成存储池&#xff0c;存储池分为NAS存储和SAN存储&#xff1b;NAS存储需要文件系统&#xff1b;SAN存储需要对存储池进行逻辑划分产生逻…

Stability AI 把绘画门槛打为 0!

本文由 GPT- 4 所创作&#xff0c;配图由 Stable Doodle 生成。 编者按 Stability AI 上新了&#xff01; 其收购的 Clipdrop 发布了全新的 Stable Doodle 工具&#xff0c;我在使用后最为直观的感受就是 —— 把绘画门槛打下来了。 在 Stable Doodle 之前&#xff0c;使用各…

动手学深度学习v2 p2 线性神经网络 线性回归

3. 线性神经网络 回归&#xff08;regression&#xff09;是能为一个或多个自变量与因变量之间关系建模的一类方法。 在自然科学和社会科学领域&#xff0c;回归经常用来表示输入和输出之间的关系。 在机器学习领域中的大多数任务通常都与预测&#xff08;prediction&#xf…

node.js 第一天

目录 使用readFile()方法读取文件内容 判断文件是否读取成功 判断文件是否写入成功 案例 考试成绩整理 path path.join&#xff08;&#xff09; path.basename() 使用readFile()方法读取文件内容 // 1. 导入 fs 模块&#xff0c;来操作文件 const fs require(fs)// 2.…

(ceph)资源池poll管理

资源池 Pool 管理 前面的文章中我们已经完成了 Ceph 集群的部署&#xff08;ceph部署: 传送门&#xff09;&#xff0c;但是我们如何向 Ceph 中存储数据呢&#xff1f;首先我们需要在 Ceph 中定义一个 Pool 资源池。Pool 是 Ceph 中存储 Object 对象抽象概念。我们可以将其理解…

Jmeter(119)-函数threadNum妙用

今天的接口场景是&#xff1a;有N个用户需要每隔5秒去查询一次数据&#xff0c;也就是说N个用户会去循环执行同一个接口。一开始的时候将用户参数化时使用了counter&#xff0c; 要执行2个线程3次循环&#xff0c;发现每次循环时&#xff0c;接口中用户参数的数据就会不一样&am…

基于PyQt5的UI界面开发——菜单与工具栏

窗口类型 我们进入QtDesigner&#xff0c;创建主窗口有三种类型&#xff1a;QMainWindow、QDialog 和 QWidget。 在新建应用程序窗口&#xff0c;通常选择 MainWindow 创建主窗口的图形界面就可以了。QtDesigner 创建的 “MainWindow” 虽然是一个空白的图形窗口&#xff0c;但…

linux 基于debian_ubuntu AB系统适配(四)- 硬盘 wifi U盘无法使用问题

1、问题起因 使用原系统可以使用,但AB系统缺不行,开始怀疑是文件系统问题,于是我把AB系统的文件系统给替换到原系统中去,结果一样可以使用。于是替换了内核文件,结果不能使用了,那问题就出现在了内核中,刚开始以为是设备树的问题,于是拿原系统的设备树与AB系统的设备树…

[Docker异常篇]解决Linux[文件异常]导致开机Docker服务无法启动

文章目录 一&#xff1a;场景复现二&#xff1a;解决思路2.1&#xff1a; 对比其他节点docker配置2.2&#xff1a;试着修改为正常节点配置2.2&#xff1a;根据上面异常显示&#xff0c;不一定是配置不对&#xff0c;可能是文件系统有损坏 三&#xff1a;解决 -> 执行命令 mo…

黄皮书-线接触热弹流润滑 Fortran+Matlab转译代码

原Fortran代码有错误&#xff0c;进行了修改&#xff0c;数值上差别不大。根据Fortran代码转的Matlab&#xff0c;可以完美运行&#xff0c;但是因为精度问题有差异&#xff0c;只能说趋势是一致的。 需要私我-资源里只是Fortran运行结果

uniapp学习之【从一个小程序跳转到另一个小程序】

uni.navigateToMiniProgram({appId: ,path: pages/index/index?id123,extraData: {data1: test},success(res) {// 打开成功} })

UEC++: 接口

1. 2. 3. 4.一般接口的源文件是不用写逻辑的&#xff0c;一般是在接口头文件中编写 5.被C类继承&#xff1a; 写完函数&#xff0c;千万不允许定义&#xff01;&#xff01;&#xff01; 添加标记宏 找到一个类&#xff1a;继承I开头的接口&#xff1a;引用头文件 错误重写&…