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

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

评论区

雨帆 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://www.mzph.cn/news/695368.shtml

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

相关文章

【达梦数据库】通过系统函数来配置sqllog

环境说明:达梦2024年Q4季度版之后版本支持 通过系统函数进行sqllog参数配置 -- 新增模式 SLOG_CONFIG1 和 SLOG_CONFIG2: SP_SET_SQLLOG_INI([SLOG_CONFIG1]FILE_PATH../log;PART_STOR0;[SLOG_CONFIG2]SWITCH_MODE2;SWITCH_LIMIT128);-- 删除模式名为 S…

redis复习笔记06(小滴课堂)

分布式锁核心知识介绍和注意事项 基于Redis实现分布式锁的几种坑 综合伪代码: 运行:

PDF加粗内容重复读取解决方案

文章目录 前言发现问题解决方案问题分析大致逻辑 show my code 前言 在使用pdfplumber读取PDF的过程中,由于加黑的内容会被莫名其妙的读取两次,带来了很大的困扰。这篇文章将给出解决方案。 发现问题 在在使用pdfplumber读取PDF的过程中,读…

LLaMA 2 - 你所需要的一切资源

摘录 关于 LLaMA 2 的全部资源,如何去测试、训练并部署它。 LLaMA 2 是一个由 Meta 开发的大型语言模型,是 LLaMA 1 的继任者。LLaMA 2 可通过 AWS、Hugging Face 等提供商获取,并免费用于研究和商业用途。LLaMA 2 预训练模型在 2 万亿个标记…

HarmonyOS开发技术全面分析

系统定义 HarmonyOS 是一款 “ 面向未来 ” 、面向全场景(移动办公、运动健康、社交通信、媒体娱乐等)的分布式操作系统。在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够…

python读写文件操作的三大基本步骤

目录 基本步骤 常用函数 open()函数 close()函数 read()函数 readlines()函数 readline()函数 write()函数 writelines()函数 with语句 读写操作的应用: 拷贝文件 with 语句的嵌套 逐行拷贝 基本步骤 1. 打开文件:open(filepath, mode, en…

探索亚马逊自养号测评的实际效果与使用感受

自养号在亚马逊测评中的应用给了我们一种全新的体验。通过使用亚马逊自养号,我们发现了许多令人满意的优势,这些优势不仅提升了我们的测评效率,还增加了我们的信誉度。 首先,自养号的质量可控性给了我们极大的信心。我们可以自行…

css中, grid-auto-rows: 怎样简写在grid:中

grid-auto-rows:100px; grid-template-columns:1fr 1fr; 👆可以写成👇 grid:auto-flow 100px / 1fr 1fr;在CSS Grid布局中,grid-auto-rows 属性用于指定自动生成的网格容器的行的大小。如果你想要将 grid-auto-rows 的值简写在 grid 属性中&a…

基于CNN-GRU-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 CNN(卷积神经网络)部分 4.2 GRU(门控循环单元)部分 4.3 Attention机制部分 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版…

【Vue渗透】Vue站点渗透思路

原文地址 极核GetShell 前言 本文经验适用于前端用Webpack打包的Vue站点,阅读完本文,可以识别出Webpack打包的Vue站点,同时可以发现该Vue站点的路由。 成果而言:可能可以发现未授权访问。 识别Vue 识别出Webpack打包的Vue站…

FFmpeg的HEVC解码器源代码学习笔记-1

一直想写一个HEVC的码流解析工具,看了雷神264码流解析工具,本来想尝试模仿写一个相似的265码流分析工具,但是发现265的解码过程和结构体和264的不太一样,很多结构体并没有完全暴露出来,没有想到很好的方法获得量化参数…

关键字查找,将匹配到的词标红

效果图: 候补 特别说明: 该文有很多新奇的用法,包括载入ui文件、连接信号和控件等等,有很多值得学习的地方 具体实现: 配置文件 #! [0] QT widgets uitoolsHEADERS textfinder.h SOURCES textfinder.cpp main.cpp…

自增a++和自减a--详细解析

1.自增、自减运算符是什么,有什么作用,需要注意什么? 、–;对当前变量值1、-1只能操作变量,不能操作字面量 2.自增、自减运算符放在变量前后有区别吗? 如果单独使用放前放后是没有区别的非单独使用:在变量前,先进行变量自增/…

unity学习(36)——角色选取界面(自制美工)

1.添加一个背景图片,记不住可以查之前的资料(4) 图片拖入asset,属性设成sprite;把图片拖到source image中;colour白色(透明,点一下右边的笔即可);material为…

SpringCloud-Gateway网关的使用

本文介绍如何再 SpringCloud 项目中引入 Gateway 网关并完成网关服务的调用。Gateway 网关是一个在微服务架构中起到入口和路由控制的关键组件。它负责处理客户端请求,进行路由决策,并将请求转发到相应的微服务。Gateway 网关还可以实现负载均衡、安全认…

【零基础学习CAPL】——诊断报文发送

🙋‍♂️【零基础学习CAPL】系列💁‍♂️点击跳转 文章目录 1.概述2.调用CDD的诊断报文发送3.脱离CDD进行诊断报文4.多帧诊断报文的发送4.1.直接定义报文发送4.2调用osek_tp.dll进行多帧数据发送4.3.函数介绍4.4.CAPL脚本实现1.概述 本章主要介绍基于CAPL脚本对诊断报文的…

subprocess.check_output()和subprocess.run()的区别

subprocess.check_output() 返回值:subprocess.check_output() 返回命令的标准输出(stdout)。如果命令执行失败(返回非零退出码),则抛出 CalledProcessError 异常。使用场景:只关心命令的输出&…

vue大文件读取部分内容,避免重复加载大文件,造成流量浪费

使用场景:项目点云地图是pcd文件,但是文件可能上百兆,我需要获取到文件中的版本信息,跟本地的缓存文件做比较,如果不一致,才会加载整个文件。从而节省流量。 避免重复加载整个“.pcd文件,以最大…

【PX4学习笔记】04.QGC地面站的使用

目录 文章目录 目录PX4代码烧入PX4固件代码的烧入方式1PX4固件代码的烧入方式2 QGC地面站的基础使用连接地面站的方式查看关键的硬件信息 QGC地面站的Application Settings模块Application Settings模块-常规界面单位其他设置数据持久化飞机中的数传日志飞行视图计划视图自动连…

观察者模式, 发布-订阅模式, 监听器模式

观察者模式, 发布-订阅模式, 监听器模式 观察者模式 观察者模式是一种行为型设计模式, 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 角色模型和结构图 在观察者模式中,只有两种…