《图解设计模式》笔记(一)适应设计模式

图灵社区 - 图解设计模式 - 随书下载

评论区

雨帆 2017-01-11 16:14:04

对于设计模式,我个人认为,其实代码和设计原则才是最好的老师。理解了 SOLID,如何 SOLID,自然而然地就用起来设计模式了。Github 上有一个 tdd-training,里面就是教你如何设计重构的。换句话说,此书可能不是很推荐。

设计模式的学习还是要靠 kata 练习

https://github.com/Pragmatists/tdd-trainings

一、Iterator模式:一个一个遍历

示例程序类图

在这里插入图片描述

public static void main(String[] args) {BookShelf bookShelf = new BookShelf(4);bookShelf.appendBook(new Book("Around the World in 80 Days"));bookShelf.appendBook(new Book("Bible"));bookShelf.appendBook(new Book("Cinderella"));bookShelf.appendBook(new Book("Daddy-Long-Legs"));Iterator it = bookShelf.iterator();while (it.hasNext()) {Book book = (Book)it.next();System.out.println(book.getName());}
}

角色

在这里插入图片描述

  • Iterator(迭代器)

    定义按顺序逐个遍历元素的接口(APl)。

    在示例程序中,Iterator接口扮演这个角色,它定义了两个方法:hasNext(判断是否存在下一个元素)和next(获取该元素)。

  • Concretelterator(具体的迭代器)

    负责实现Iterator角色所定义的接口(API)。

    在示例程序中,BookShelfIterator类扮演这个角色。该角色中包含了遍历集合所必需的信息。

    在示例程序中,BookShelf类的实例保存在bookShelf字段中,被指向的书的下标保存在index字段中。

  • Aggregate(集合)

    负责定义创建Iterator角色的接口(API)。这个接口(API)是一个方法,会创建出”按顺序访问保存在我内部元素的人“。

    在示例程序中,Aggregate接口扮演这个角色,它里面定义了iterator方法。

  • ConcreteAggregate(具体的集合)

    负责实现Aggregate角色所定义的接口(API)。它会创建出具体的Iterator角色,即Concretelterator角色。

    在示例程序中,由BookShelf类扮演这个角色,它实现了iterator方法

扩展思路的要点

不管实现如何变化,都可以使用lterator

不用for循环,而使用Iterator模式的一个重要的理由:引入Iterator后可以将遍历与实现分离开来。

请看下面的代码。

while (it.hasNext()) {Book book =(Book)it.next();System.out.println(book.getName());
}

这里只使用了IteratorhasNext()next(),并没有调用BookShelf的方法。

即:这里的while循环并不依赖于BookShelf的实现。

那么管理书本就可以不用数组,可以换成java.util.VectorArrayList等别的形式。

不管BookShelf如何变化,只要BookShelf的iterator方法能正确地返回Iterator的实例就行,对于BookShelf的调用者很友好。

设计模式的作用就是帮助我们编写可复用的类。

所谓“可复用”,就是指将类实现为“组件”,当一个组件发生改变时,不需要对其他的组件进行修改或是只需要很小的修改即可应对。

难以理解抽象类和接口

不要只使用具体的类来解决问题,很容易导致类之间的强耦合,这些类也难以作为组件被再次利用。

为了弱化类之间的耦合,进而使得类更加容易作为组件被再次利用,我们需要引入抽象类和接口。

Aggregate 和 Iterator 的对应

如何把BookShelfIterator类定义为BookShelf类的Concretelterator角色的:BookShelfIterator类知道BookShelf是如何实现的。因此,我们才能调用用来获取下一本书的getBookAt方法。

也就是说,如果BookShelf的实现发生了改变,即getBookAt方法这个接口(API)发生变化时,必须修改BookShelfIterator类。

正如Aggregate和Iterator这两个接口对应的一样,concreteAggregate和ConcreteIterator这两个类也是对应的。

多个 Iterator

“将遍历功能置于Aggregate角色之外”是Iterator模式的一个特征。根据这个特征,可以针对一个ConcreteAggregate角色编写多个Concretelterator角色。

迭代器的种类多种多样

在示例程序中展示的Iterator类只是很简单地从前向后遍历集合。可以改成从后向前、双向遍历、根据条件跳跃式遍历等。

不需要 deletelterator

在Java中,没有被使用的对象实例将会自动被删除(垃圾回收,GC)。因此,在iterator中不需要与其对应的deleteIterator方法。

相关的设计模式

Visitor模式(第13章)

Iterator模式是从集合中逐个取出元素进行遍历,但并没有在Iterator接口中声明对取出的元素进行何种处理。

Visitor模式则是在遍历元素集合的过程中,对元素进行相同的处理。

Composite模式(第11章)

Composite模式是具有递归结构的模式,在其中使用Iterator模式比较困难。

Factory Method模式(第4章)

在iterator方法中生成Iterator的实例时可能会使用Factory Method模式。

二、Adapter模式:加个“适配器”以便于复用

示例程序类图

继承的方式

在这里插入图片描述

委托的方式

在这里插入图片描述

public static void main(String[] args) {Print p = new PrintBanner("Hello");p.printWeak();p.printStrong();
}

角色

在这里插入图片描述

  • Target(对象)

    负责定义所需的方法。

    类比让笔记本电脑正常工作所需的直流12伏特电源。

    在示例程序中,由Print接口(使用继承时)和Print类(使用委托时)扮演此角色。

  • Client(请求者)

    负责使用Target 角色所定义的方法进行具体处理。

    类比直流12伏特电源所驱动的笔记本电脑。

    在示例程序中,由Main类扮演此角色。

  • Adaptee(被适配)

    注意不是Adapt-er(适配)角色,而是Adapt-ee(被适配)角色。

    Adaptee是一个持有既定方法的角色。

    类比交流220伏特电源。

    在示例程序中,由Banner类扮演此角色。

    如果Adaptee角色中的方法与Target角色的方法相同(也就是说家庭使用的电压就是12伏特直流电压),就不需要接下来的Adapter角色了。

  • Adapter(适配)

    Adapter模式的主人公。使用Adaptee角色的方法来满足Target角色的需求,这是Adapter模式的目的,也是Adapter角色的作用。

    类比将交流100伏特电压转换为直流12伏特电压的适配器。

    在示例程序中,由PrintBanner类扮演这个角色。

    在类适配器模式中,Adapter角色通过继承来使用Adaptee角色,而在对象适配器模式中,Adapter角色通过委托来使用Adaptee角色。

拓展思路的要点

什么时候使用Adapter模式

如果某个方法就是我们所需要的方法,那么直接在程序中使用不就可以了吗?为什么还要考虑使用Adapter模式呢?

很多时候,我们并非从零开始编程,经常会用到现有的类。特别是当现有的类已经被充分测试过了,Bug很少,而且已经被用于其他软件之中时,我们更愿意将这些类作为组件重复利用。

Adapter模式会对现有的类进行适配,生成新的类。通过该模式可以很方便地创建我们需要的方法群。

当出现Bug时,由于我们很明确地知道Bug不在现有的类(Adaptee角色)中,所以只需调查扮演Adapter角色的类即可,方便排查代码问题。

如果没有现成的代码

使用Adapter模式可以在完全不改变现有代码的前提下使现有代码适配于新的接口(API)。

此外,在Adapter模式中,并非一定需要现成的代码。只要知道现有类的功能,就可以编写出新的类。

版本升级与兼容性

版本升级时常会出现“与旧版本的兼容性”问题。现实中往往很难完全抛弃旧版本。

这时,可以使用Adapter模式使新旧版本兼容,以便同时维护新版本和旧版本。

例如,假设我们今后只想维护新版本。这时可以让新版本扮演Adaptee角色,旧版本扮演Target角色。接着编写一个扮演Adapter角色的类,让它使用新版本的类来实现旧版本的类中的方法。

在这里插入图片描述

功能完全不同的类

当然,当Adaptee角色和Target角色的功能完全不同时,Adapter模式是无法使用的。就如同我们无法用交流100伏特电压让自来水管出水一样。

相关的设计模式

Bridge模式(第9章)

Adapter模式用于连接接口(API)不同的类,而Bridge模式则用于连接类的功能层次结构与实现层次结构。

Decorator模式(第12章)

Adapter模式用于填补不同接口(API)之间的缝隙,而 Decorator模式则是在不改变接口(API)的前提下增加功能。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

第3.4章:StarRocks数据导入-Routine Load

注:本篇文章阐述的是StarRocks-3.2版本的Routine Load导入机制 一、概述 Routine Load(例行导入)支持用户提交一个常驻的导入任务,可以将消息流存储在 Kafka 的Topic中,通过订阅Topic 中的全部或部分分区的消息&#…

多个.C 文件关于全局变量如何使用

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - :来于“云”的“羽球人”。…

C语言新手写函数中出现数组时运行bug的解决

一.发现问题&#xff1a; 这是我今天写代码的一小部分&#xff0c;是创建一个数组&#xff0c;然后函数init&#xff08;&#xff09;是初始化数组&#xff0c;代码如下&#xff1a; void init(int arr[10],unsigned int k) {int i 0;for (i 0; i < k; i) {arr[i] 0;} …

深度学习系列60: 大模型文本理解和生成概述

参考网络课程&#xff1a;https://www.bilibili.com/video/BV1UG411p7zv/?p98&spm_id_frompageDriver&vd_source3eeaf9c562508b013fa950114d4b0990 1. 概述 包含理解和分类两大类问题&#xff0c;对应的就是BERT和GPT两大类模型&#xff1b;而交叉领域则对应T5 2.…

机器学习基本概念(李宏毅课程)

目录 一、概念:1、机器学习概念:2、深度学习概念&#xff1a; 二、深度学习中f(.)的输入和输出&#xff1a;1、输入&#xff1a;2、输出&#xff1a; 三、三种机器学习任务&#xff1a;1、Regression回归任务介绍&#xff1a;2、Classification分类任务介绍&#xff1a;3、Stru…

【Python】OpenCV-图片差异检测与标注

图片差异检测与标注 在图像处理领域中&#xff0c;检测两张图片之间的差异是一项重要的任务。本文将介绍一个使用OpenCV库进行图片差异检测的简单示例代码&#xff0c;并详细注释每个步骤。 1. 引言 图片差异检测是在两张图片之间寻找差异点或区域的过程。这项技术可用于监测…

http和https的区别(简述)

HTTP&#xff08;HyperText Transfer Protocol&#xff09;和HTTPS&#xff08;HTTP Secure&#xff09;都是用于在客户端和服务器之间传输数据的协议&#xff0c;但它们在安全性方面有重要的区别。 1.HTTP: 概述&#xff1a; HTTP是一种用于传输超文本的协议&#xff08;超文…

Javascript中var和let之间的区别

文章目录 一.变量提升(声)二.let和var的区别 区别&#xff1a; 1、var有变量提升&#xff0c;而let没有&#xff1b; 2、let不允许在相同的作用域下重复声明&#xff0c;而var允许&#xff1b; 3、let没有暂时性死区问题&#xff1b; 4、let创建的全局变量没有给window设置对应…

【PX4学习笔记】13.飞行安全与炸机处理

目录 文章目录 目录使用QGC地面站的安全设置、安全绳安全参数在具体参数中的体现安全绳 无人机炸机处理A&#xff1a;无人机异常时控操作B&#xff1a;无人机炸机现场处理C&#xff1a;无人机炸机后期维护和数据处理D&#xff1a;无人机再次正常飞行测试 无人机飞行法律宣传 使…

基于springboot+vue的B2B平台的医疗病历交互系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

R cox回归 ggDCA报错

临床预测模型的决策曲线分析&#xff08;DCA&#xff09;&#xff1a;基于ggDCA包 决策曲线分析法&#xff08;decision curve analysis&#xff0c;DCA&#xff09;是一种评估临床预测模型、诊断试验和分子标记物的简单方法。 我们在传统的诊断试验指标如&#xff1a;敏感性&a…

golang实现延迟队列(delay queue)

golang实现延迟队列 1 延迟队列&#xff1a;邮件提醒、订单自动取消 延迟队列&#xff1a;处理需要在未来某个特定时间执行的任务。这些任务被添加到队列中&#xff0c;并且指定了一个执行时间&#xff0c;只有达到指定的时间点时才能从队列中取出并执行。 应用场景&#xff1…

[ Python+OpenCV+Mediapipe ] 实现对象识别

一、写在前面 本文所用例子为个人学习的小结&#xff0c;如有不足之处请各位多多海涵&#xff0c;欢迎小伙伴一起学习进步&#xff0c;如果想法可在评论区指出&#xff0c;我会尽快回复您&#xff0c;不胜感激&#xff01; 所公布代码或截图均为运行成功后展示。 二、本文内容…

PEARL: 一个轻量的计算短文本相似度的表示模型

| &#x1f4bb; [code] | &#x1f4be; [data] | &#x1f917; PEARL-small | &#x1f917; PEARL-base | 论文 如何计算短文本相似度是一个重要的任务&#xff0c;它发生在各种场景中&#xff1a; 字符串匹配&#xff08;string matching&#xff09;。我们计算两个字符…

AWS安全组是什么?有什么用?

最近看到小伙伴在问&#xff0c;AWS安全组是什么&#xff1f;有什么用&#xff1f;今天我们大家就来简单聊聊&#xff0c;仅供参考哦&#xff01; AWS安全组是什么&#xff1f;有什么用&#xff1f; 【回答】&#xff1a;AWS安全组是一种虚拟防火墙&#xff0c;用于控制进出…

贝叶斯统计——入门级笔记

绪论 1.1 引言 全概率公式 贝叶斯公式 三种信息 总体信息 当把样本视为随机变量时&#xff0c;它有概率分布&#xff0c;称为总体分布&#xff0e; 如果我们已经知道总体的分布形式这就给了我们一种信息&#xff0c;称为总体信息 样本信息 从总体中抽取的样本所提供的信息 先…

【操作系统】

计算机操作系统 计算机是如何让用户得到好的体验什么是操作系统&#xff08;OS&#xff09;操作系统如何管理 计算机是如何让用户得到好的体验 计算机系统是由计算机硬件和软件组成的。用户使用计算机&#xff0c;比如在文本文件填写内容&#xff0c;通过邮箱发送邮件&#xf…

opencv图像放缩与插值-resize函数

在OpenCV中&#xff0c;resize函数用于对图像进行尺寸调整&#xff08;放大或缩小&#xff09;&#xff0c;这个过程中通常需要用到插值方法来计算新尺寸下图像像素的值。插值方法对于放缩的质量有着直接影响。 void resize(InputArray src, OutputArray dst, Size dsize, dou…

全流程点云机器学习(二)使用PaddlePaddle进行PointNet的机器学习训练和评估

前言 这不是高支模项目需要嘛&#xff0c;他们用传统算法切那个横杆竖杆流程复杂耗时很长&#xff0c;所以想能不能用机器学习完成这些工作&#xff0c;所以我就来整这个工作了。 基于上文的数据集切分 &#xff0c;现在来对切分好的数据来进行正式的训练。 本系列文章所用的…

解决app中以webview的方式嵌入h5网页,h5网页加载不出来

问题描述&#xff1a;我的h5网页在web端和手机浏览器都能正常渲染展示&#xff0c;但是嵌入到客户的webview中&#xff0c;渲染加载不出来&#xff0c;仔细检查代码之后并没有任何代码错误和后台报错。抓耳挠腮查找两天之后发现&#xff0c;原因为整个h5网页的最外层高度设置成…