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

news2024/11/16 6:33:55

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

评论区

雨帆 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.coloradmin.cn/o/1462013.html

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

相关文章

Android的ViewModel

前言 在Compose的学习中,我们在可组合函数中使用rememberSaveable​​​​​​​保存应用数据,但这可能意味着将逻辑保留在可组合函数中或附近。随着应用体量不断变大,您应将数据和逻辑从可组合函数中移出。 而在之前的应用架构学习中&…

Duilib显示gif颜色背景与原图不符GifUI

//xml <GifUI name"gif_option_new" float"true" pos"608,28,0,0" width"28" height"14" gif"new.gif"/>遇到两个问题。 1、图片背景只有第一帧显示&#xff0c;每一帧的背景色一样&#xff0c;字不同&…

FISCO BCOS(十七)利用脚本进行区块链系统监控

要利用脚本进行区块链系统监控&#xff0c;你可以使用各种编程语言编写脚本&#xff0c;如Python、Shell等 利用脚本进行区块链系统监控可以提高系统的稳定性、可靠性&#xff0c;并帮助及时发现和解决潜在问题&#xff0c;从而确保区块链网络的正常运行。本文可以利用脚本来解…

Redis-内存管理

Redis是基于内存存储的&#xff0c;非关系型&#xff0c;键值对数据库。因此&#xff0c;对Redis来说&#xff0c;内存空间的管理至关重要。那Redis是如何内存管理的呢&#xff1f; 一、最大内存限制 Redis 提供了 maxmemory 参数允许用户设置 Redis 可以使用的最大内存大小。…

【2024.02.22】定时执行专家 V7.0 发布 - TimingExecutor V7.0 Release - 龙年春节重大更新版本

目录 ▉ 新版本 V7.0 下载地址 ▉ V7.0 新功能 ▼2024-02-21 V7.0 - 更新日志▼ ▉ V7.0 新UI设计 ▉ 新版本 V7.0 下载地址 BoomWorks软件的最新版本-CSDN博客文章浏览阅读10w次&#xff0c;点赞9次&#xff0c;收藏41次。▉定时执行专家—毫秒精度、专业级的定时任务执行…

psp游戏存档收集SAVEDATA

不想从头开始 ppsspp存档目录 pc&#xff1a;ppsspp解压目录\memstick\PSP\SAVEDATA 安卓&#xff1a;根目录\PSP\SAVEDATA 噬神者2(日版) NPJH50832099c645531020001000 風燐-https://wwl.lanzouq.com/iI1R01owozxa 咲夜-https://wwl.lanzouq.com/id1tX1owp2uf につてのぬ…

Laravel01 课程介绍以及Laravel环境搭建

Laravel01 课程介绍 1. Laravel2. mac开发环境搭建(通过Homebrew)3. 创建一个项目 1. Laravel 公司中面临着PHP项目与Java项目并行&#xff0c;所以需要我写PHP的项目&#xff0c;公司用的框架就是Laravel&#xff0c;所以在B站上找了一门课学习。 Laravel中文文档地址 https…

(っ•̀ω•́)っ 如何在PPT中为文本框添加滚动条

本人在写技术分享的PPT时&#xff0c;遇到问题&#xff1a;有一大篇的代码&#xff0c;如何在一张PPT页面上显示&#xff1f;急需带有滚动条的文本框&#xff01;百度了不少&#xff0c;自己也来总结一篇&#xff0c;如下&#xff1a; 1、找到【文件】-【选项】 2、【自定义功…

数据库管理-第153期 Oracle Vector DB AI-05(20240221)

数据库管理153期 2024-02-21 数据库管理-第153期 Oracle Vector DB & AI-05&#xff08;20240221&#xff09;1 Oracle Vector的其他特性示例1&#xff1a;示例2 2 简单使用Oracle Vector环境创建包含Vector数据类型的表插入向量数据 总结 数据库管理-第153期 Oracle Vecto…

如何修改docker容器的端口映射

要修改 Docker 容器的端口映射&#xff0c;你需要停止并删除现有的容器&#xff0c;然后使用新的端口映射重新运行容器。以下是详细步骤&#xff1a; 停止容器&#xff1a; 使用 docker stop 命令停止正在运行的容器。替换 <container_id> 为你要停止的容器的 ID 或者容器…

物联网在智慧景区中的应用:提升游客体验与运营效率

目录 一、物联网技术概述 二、物联网在智慧景区中的应用 1、智能门票系统 2、智能导览系统 3、智能安全监控系统 4、智能环保系统 三、物联网在智慧景区中提升游客体验 1、提高游览便捷性 2、个性化服务体验 3、提升游客安全感 四、物联网在智慧景区中提升运营效率 …

Python爬虫实战入门:爬取360模拟翻译(仅实验)

文章目录 需求所需第三方库requests 实战教程打开网站抓包添加请求头等信息发送请求&#xff0c;解析数据修改翻译内容以及实现中英互译 完整代码 需求 目标网站&#xff1a;https://fanyi.so.com/# 要求&#xff1a;爬取360翻译数据包&#xff0c;实现翻译功能 所需第三方库 …

零基础学习8051单片机(十五)

本次先看书学习&#xff0c;并完成了课后习题&#xff0c;题目出自《单片机原理与接口技术》第五版—李清朝 答: &#xff08;1&#xff09;当 CPU正在处理某件事情的时候&#xff0c;外部发生的某一件事件请求 CPU 迅速去处理&#xff0c;于是&#xff0c;CPU暂时中止当前的工…

【前端】夯实基础 css/html/js 50个练手项目(持续更新)

文章目录 前言Day 1 expanding-cardsDay 2 progress-steps 前言 发现一个没有用前端框架的练手项目&#xff0c;很适合我这种纯后端开发夯实基础&#xff0c;内含50个mini project&#xff0c;学习一下&#xff0c;做做笔记。 项目地址&#xff1a;https://github.com/bradtr…

纯血鸿蒙来画龙!基于HarmonyOS ArkTS来操作SVG图片

大家好&#xff0c;龙年报喜&#xff0c;大地回春&#xff0c;作为程序员&#xff0c;以代码之名&#xff0c;表达对于龙年的祝福。本节将演示如何在基于HarmonyOS ArkTS的Image组件来实现画一条中国龙&#xff0c;祝大家“码”上“鸿”福到&#xff01; 本文涉及的所有源码&a…

Java Web演化史:从Servlet到SpringBoot的技术进程及未来趋势

引言 在快速演进的IT世界里&#xff0c;Java Web开发始终屹立不倒&#xff0c;它不仅承担着历史的厚重&#xff0c;也始终面向未来。 自诞生之日起&#xff0c;Java Web技术就在不断地进化&#xff0c;以适应不同时代的需求。 本文将回顾Java Web开发的重要里程碑&#xff0c;…

Stable diffusion UI 介绍-文生图

1.提示词&#xff1a; 你希望图中有什么东西 2.负面提示词&#xff1a;你不希望图中有什么东西 选用了什么模型 使用参数 1.采样器 sampling method 使用什么算法进行采样 2.采样迭代步数 sampling steps 生成图像迭代的步数&#xff0c;越多越好&#xff0c;但是生成速度越大越…

qt-OPENGL-星系仿真

qt-OPENGL-星系仿真 一、演示效果二、核心程序三、下载链接 一、演示效果 二、核心程序 #include "model.h"Model::Model(QOpenGLWidget *_glWidget) { glWidget _glWidget;glWidget->makeCurrent();initializeOpenGLFunctions(); }Model::~Model() {destroyV…

如何添加或编辑自定义WordPress侧边栏

WordPress侧边栏是许多WordPress网站上的固定装置。它为您的内容提供了一个垂直空间&#xff0c;您可以在其中帮助读者导航、增加电子邮件列表或社交关注、展示广告等。 因为它是许多WordPress网站不可或缺的一部分&#xff0c;所以我们认为侧边栏值得拥有自己的大型指南。在这…

JS前端高频面试

JS数据类型有哪些&#xff0c;区别是什么 js数据类型分为原始数据类型和引用数据类型。 原始数据类型包括&#xff1a;number&#xff0c;string&#xff0c;boolean&#xff0c;null&#xff0c;undefined&#xff0c;和es6新增的两种类型&#xff1a;bigint 和 symbol。&am…