当前位置: 首页 > news >正文

重构改善既有代码的设计-学习(一):封装

1、封装记录(Encapsulate Record

 

        一些记录性结构(例如hash、map、hashmap、dictionary等),一条记录上持有什么字段往往不够直观。如果其使用范围比较宽,这个问题往往会造成许多困扰。所以,记录性结构应该被封装成为一个类。

        例如:

organization = {name: "Acme Gooseberries", country: "GB"};

        应该被重构为:

class Organization {constructor(data) {this._name = data.name;this._country = data.country;}get name() {return this._name;}set name(arg) {this._name = arg;}get country() {return this._country;}set country(arg) {this._country = arg;}
}

 2、封装集合(Encapsulate Collection)

 

        我们通常鼓励封装,但封装时人们常常犯一个 错误:只对集合变量的访问进行了封装,但依然让取值函数 返回集合本身。这使得集合的成员变量可以直接被修改,而封装它的类则全然不知,无法介入。

        修改的方式是,在类上提供一些修改集合的方法(通常是“添加”、“删除”等),这样就可以使对集合的修改必须经过类。

        例如:

class Person {get courses() {//这里直接把对象本身返回了,在哪里偷偷摸摸被改了都不知道return this._courses;}  set courses(aList) {this._courses = aList;} 
}

        应该改为:

class Person {get courses() {return this._courses.slice();}// 提供修改对象的方法,想改,就必须用类的方法addCourse(aCourse) { ... }removeCourse(aCourse) { ... }
}

3、以对象取代基本类型(Replace Primitive with Object)

 

        不要执着于用基本类型,应该把一些数据封装成对象。

        例如,本身“图案”这个字段可能只是一个字符串,用来存储一个链接,但后来随着业务的逐渐复杂,开始有尺寸、文案等等,那他们就应该被抽取出来,放在一个类里面。

4、以查询取代临时变量(Replace Temp with Query)

 

        如果一个变量只声明一次之后不再被改变,那就别再声明变量了,而是直接用一个查询操作取代他。比如:

// 这里的变量只用了一次
const basePrice = this._quantity * this._itemPrice;if (basePrice > 1000)return basePrice * 0.95;
elsereturn basePrice * 0.98;

        应该变为 :

// 构建一个查询用来替代那个变量
get basePrice() {this._quantity * this._itemPrice;}...if (this.basePrice > 1000)return this.basePrice * 0.95;
elsereturn this.basePrice * 0.98;

 5、提炼类(Extract Class)

        在实际工作中, 类会不断成长扩展。设想你有一个维护大量函数和数据的类。这样的类往往 因为太大而不易理解。此时你需要考虑哪些部分可以分离出 去,并将它们分离到一个独立的类中。如果某些数据和某些 函数总是一起出现,某些数据经常同时变化甚至彼此相依, 这就表示你应该将它们分离出去。

6、内联类(Inline Class)

 

        当一个类因为某种原因开始萎缩(可能是因为一些重构动作移走了这个类的责任),不再承担足够责任,那么他不再有单独存在的理由。应该将“萎缩类”塞进另一个类中。“另一个类”应该是和“萎缩类”关联最紧密的那个类。

7、隐藏委托关系(Hide Delegate)

 

        如果某些客户端先通过服务对象的字段得到另一个对象(受托类),然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一受托类修改了接口,变化会波及通过服务对象使用它的所有客户端。我可以在服务对象上放置一个简单的委托函数,将委托关系隐藏起来,从而去除这种依赖。这么一来,即使将来委托关系发生变化,变化也只会影响服务对象,而不会直接波及所有客户端。

        例如:现在有两个类,代表“人”的Person和代表“部门”的Department。有些客户端希望知道某人的经理是谁,为此,它必须先取得Department对象。

// 客户端必须知道 要调部门 才能知道经理
manager = aPerson.department.manager;

        这样的编码就对客户端揭露了Department的工作原理,于是客户知道:Department负责追踪“经理”这条信息。如果对客户隐藏Department,可以减少耦合。为了这一目的,我在Person中建立一个简单的委托函数。

class Person {get manager() {// 将部门这层封装起来,使客户端不感知return this.department.manager;}
}manager = aPerson.manager;

8、移除中间人(Remove Middle Man)

 

        刚刚谈到了“封装受托对象”的好处。但是这层封装也是有代价的。每当客户端要使用受托类的新特性时,你就必须在服务端添加一个简单委托函数。随着受托类的特性(功能)越来越多,更多的转发函数就会使人烦躁。服务类完全变成了一个中间人,此时就应该让客户直接调用受托类。
        很难说什么程度的隐藏才是合适的。6个月前恰如其分的封装,现今可能就显得笨拙。重构的意义就在于:你永远不必说对不起——只要把出问题的地方修补好就行了。

        做法就是把7中的例子反过来……

9、替换算法(Substitute Algorithm)

        改进算法。

相关文章:

重构改善既有代码的设计-学习(一):封装

1、封装记录(Encapsulate Record) 一些记录性结构(例如hash、map、hashmap、dictionary等),一条记录上持有什么字段往往不够直观。如果其使用范围比较宽,这个问题往往会造成许多困扰。所以,记录…...

Python图像处理【19】基于霍夫变换的目标检测

基于霍夫变换的目标检测 0. 前言1. 使用圆形霍夫变换统计图像中圆形对象2. 使用渐进概率霍夫变换检测直线2.1 渐进霍夫变换原理2.2 直线检测 3. 使用广义霍夫变换检测任意形状的对象3.1 广义霍夫变换原理3.2 检测自定义形状 小结系列链接 0. 前言 霍夫变换 (Hough Transform,…...

Spring+SprinMVC+MyBatis注解方式简易模板

SpringSprinMVCMyBatis注解方式简易模板代码Demo GitHub访问 ssm-tpl-anno 一、数据准备 创建数据库test,执行下方SQL创建表ssm-tpl-cfg /*Navicat Premium Data TransferSource Server : 127.0.0.1Source Server Type : MySQLSource Server Version :…...

Python基础第五篇(Python数据容器)

文章目录 一、数据容器入门二、数据容器 list 列表(1),list 列表定义(2),list列表的索引(3),list列表的常见操作(4),list列表的遍历 三、数据容器:tuple(元组)(1),tuple元组定义(2),tuple元组的索引(3),tuple元组的常见操作(4),tuple元组的遍…...

【H3C】配置AAA认证和Telnet远程登陆,S5130 Series交换机

AAA配置步骤为: 1.开启telent远程登陆服务 2.创建用户,设置用户名、密码、用户的服务类型 3.配置终端登录的数量 4.配置vlan-if的ip地址,用来远程登陆 5.允许对应的vlan通过 1.开启telent远程登陆服务 sys …...

GaussDB数据库中的MERGE INTO介绍

一、前言 二、GaussDB MERGE INTO 语句的原理概述 1、MERGE INTO 语句原理 2、MERGE INTO 的语法 3、语法解释 三、GaussDB MERGE INTO 语句的应用场景 四、GaussDB MERGE INTO 语句的示例 1、示例场景举例 2、示例实现过程 1)创建两个实验表,并…...

2024年上海高考数学最后四个多月的备考攻略,目标140+

亲爱的同学们,寒假已经来临,春节即将到来,距离2024年上海高考已经余额不足5个月了。作为让许多学子头疼,也是拉分大户的数学科目,你准备好了吗?今天,六分成长为您分享上海高考数学最后四个多月的…...

SSL证书自动化管理有什么好处?如何实现SSL证书自动化?

SSL证书是用于加密网站与用户之间传输数据的关键元素,在维护网络安全方面,管理SSL证书与部署SSL证书一样重要。定期更新、监测和更换SSL证书,可以确保网站的安全性和合规性。而自动化管理可以为此节省时间,并避免人为错误和不必要…...

路由器初始化配置、功能配置

实验环境 拓扑图 Ip规划表(各组使用自己的IP规划表) 部门 主机数量 网络地址 子网掩码 网关 可用ip Vlan 市场部 38 192.168.131.0 255.255.255.0 192.168.131.1 2-254 11 研发部 53 192.168.132.0 255.255.255.0 192.168.132.1 2-2…...

node介绍

1.node是什么 Node是一个基于Chrome V8引擎的JS运行环境。 Node不是一个独立的语言、node不是JS框架。 Node是一个除了浏览器之外的、可以让JS运行的环境 Node.js是一个让JS运行在服务端的开发平台,是使用事件驱动,异步非阻塞I/O,单线程&…...

海外抖音TikTok、正在内测 AI 生成歌曲功能,依靠大语言模型 Bloom 进行文本生成歌曲

近日,据外媒The Verge报道,TikTok正在测试一项新功能,利用大语言模型Bloom的AI能力,允许用户上传歌词文本,并使用AI为其添加声音。这一创新旨在为用户提供更多创作音乐的工具和选项。 Bloom 是由AI初创公司Hugging Fac…...

【ARM 嵌入式 编译系列 3.6 -- 删除lib中的某个文件】

请阅读【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 文章目录 删除lib中的某个文件 删除lib中的某个文件 比如,如果要删除 libc.a 静态库中的特定对象文件并重新使用这个静态库,在终端中可以使用 ar 命令。ar 是一个归档工具,它可以创建…...

web架构师编辑器内容-图层拖动排序功能的开发

新的学习方法 用手写简单方法实现一个功能然后用比较成熟的第三方解决方案即能学习原理又能学习第三方库的使用 从两个DEMO开始 Vue Draggable Next: Vue Draggable NextReact Sortable HOC: React Sortable HOC 列表排序的三个阶段 拖动开始(dragstart&#x…...

3.RHCSA脚本配置及通过node2改密码

运行脚本发现node2不成功 脚本破解 选第二个 Ctrl x 换行 破解成功后做node2的改密码题 回到redhat, 发现检测程序检测密码题成功,得了8分....

AtCoder Regular Contest 170(A~B)

A - Yet Another AB Problem 给你两个字符串S和T,你可以对S执行操作,选择两个字符,将前面的改为A,后面的改为B,最少操作几次可以把S改成T。如果改不成就输出-1。 从左往右一个一个改过去,分类讨论&#x…...

rk1126, 实现 yolov8 目标检测

基于 RKNN 1126 实现 yolov8 目标检测 Ⓜ️ RKNN 模型转换 ONNX yolo export model./weights/yolov8s.pt formatonnx导出 RKNN 这里选择输出 concat 输入两个节点 onnx::Concat_425 和 onnx::Concat_426 from rknn.api import RKNNONNX_MODEL ./weights/yolov8s.onnxRKNN_MOD…...

【软件测试】学习笔记-网站可扩展性架构设计

可扩展性,指的是网站的架构设计能够快速适应需求的变化,当需要增加新的功能实现时,对原有架构不需要做修改或者做很少的修改就能够快速实现新的业务需求。 从这个定义中,我们很容易就可以得出衡量网站可扩展性设计优秀与否的主要标…...

深度学习常用代码总结(k-means, NMS)

目录 一、k-means 算法 二、NMS 一、k-means 算法 k-means 是一种无监督聚类算法,常用的聚类算法还有 DBSCAN。k-means 由于其原理简单,可解释强,实现方便,收敛速度快,在数据挖掘、数据分析、异常检测、模式识别、金…...

数据结构·顺序表应用

本节应用是要用顺序表实现一个通讯录,收录联系人的姓名、性别、电话号码、住址、年龄 ​​​​​​​ 顺序表的实现在上一节中已经完成了,本节的任务其实就是应用上节写出来的代码的那些接口函数功能,做出来一个好看的,可…...

第一个 OpenGL 程序:旋转的立方体(VS2022 / MFC)

文章目录 OpenGL API开发环境在 MFC 中使用 OpenGL初始化 OpenGL绘制图形重置视口大小 创建 MFC 对话框项目添加 OpenGL 头文件和库文件初始化 OpenGL画一个正方形OpenGL 坐标系改变默认颜色 重置视口大小绘制立方体使用箭头按键旋转立方体深度测试添加纹理应用纹理换一个纹理 …...

剩余银饰的重量 - 华为OD统一考试

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C 题目描述 有N块二手市场收集的银饰,每块银饰的重量都是正整数,收集到的银饰会被熔化用于打造新的饰品。 每一回合,从中选出三块 最重的…...

redis远程连接不上解决办法

问题描述: redis远程服务端运行在192.168.3.90计算机上,客户端计算机(ip:192.168.3.110)通过redsi-cli.exe客户端工具连接时,没有反应,连接不上。 如图所示: 解决步骤: 步骤一&…...

利用Anaconda安装pytorch和paddle深度学习环境+pycharm安装后不能调用pytorch和paddlepaddle框架

问题现象: 之前安装后不能在添加pytorch和paddlepaddle框架 原因(疑似): 在终端中显示pytorch和paddle在C盘但是安装是安装在J盘 解决办法: 卸载、删除文件重新安装后可以看到文件位置在J盘中 但是选择时还是显示C…...

Eclipses安装教程

一、下载开发工具包 1、开发工具包JDK 下载地址链接:https://www.oracle.com/cn/java/technologies/downloads/ 下载教程: 1)点击链接,可以跳转到页面 2)下滑页面,找到开发工具包 3) 记住下载之…...

安装python版opencv的一些问题

安装python版opencv的一些问题 OpenCV是知名的开源计算机视觉算法库,提供了C\Python\Java版共享库。 在Python中使用OpenCV格外简单,一句命令就能安装,一行import就能引入,可谓是神器。然而,在实际使用中可能遇到一些…...

RabbitMQ入门实战

RabbitMQ 是一个开源的消息中间件,实现了高级消息队列协议(AMQP),用于在分布式系统中进行消息传递。它能够在应用之间传递消息,解耦应用组件,提高系统的可伸缩性和可维护性。RabbitMQ 使用高级消息队列协议…...

vue3-模版引用ref

1. 介绍 概念&#xff1a;通过 ref标识 获取真实的 dom对象或者组件实例对象 2. 基本使用 实现步骤&#xff1a; 调用ref函数生成一个ref对象 通过ref标识绑定ref对象到标签 代码如下&#xff1a; 父组件&#xff1a; <script setup> import { onMounted, ref } …...

C# 十大排序算法

以下是常见的十大排序算法&#xff08;按照学习和实现的顺序排列&#xff09;&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;选择排序&#xff08;Selection Sort&#xff09;插入排序&#xff08;Insertion Sort&#xff09;希尔排序&#xff08;Shell Sort&…...

面试之Glide如何绑定Activity的生命周期

Glide绑定Activity生命周期 Glide.with() 下面都是它的重载方法&#xff0c;Context&#xff0c;Activity&#xff0c;FragmentActivity, Fragment, android.app.Fragment fragment,View都可以作为他的参数&#xff0c;内容大同小异&#xff0c;都是先getRetriever&#xff0…...

从 fatal 错误到 sync.Map:Go中 Map 的并发策略

为什么 Go 语言在多个 goroutine 同时访问和修改同一个 map 时&#xff0c;会报出 fatal 错误而不是 panic&#xff1f;我们该如何应对 map 的数据竞争问题呢&#xff1f; 这篇文章将带你一步步了解背后的原理&#xff0c;并引出解决 map 并发问题的方案。 Map 数据竞争 首先…...