CH06_第一组重构(下)

封装变量(Encapsulate Variable | 132)

曾用名:自封装字段(Self-Encapsulate Field)

曾用名:封装字段(Encapsulate Field)

在这里插入图片描述

let defaultOwner = {firstName: "Martin", lastName: "Fowler"};
let defaultOwnerData = {firstName: "Martin", lastName: "Fowler"};
export function defaultOwner() {return defaultOwnerData;}
export function setDefaultOwner(arg) {defaultOwnerData = arg;}

动机

重构的作用就是调整程序中的元素。函数相对容易调整一些,因为函数只有一种用法,就是调用。在改名或搬移函数的过程中,总是可以比较容易地保留旧函数作为转发函数(即旧代码调用旧函数,旧函数再调用新函数)。这样的转发函数通常不会存在太久,但的确能够简化重构过程。

如果数据的可访问范围变大,重构的难度就会随之增大,这也是说全局数据是大麻烦的原因。

如果想要搬移一处被广泛使用的数据,最好的办法往往是先以函数形式封装所有对该数据的访问。

封装能提供一个清晰的观测点,可以由此监控数据的变化和使用情况,还可以轻松地添加数据被修改时的验证或后续逻辑。数据的作用域越大,封装就越重要。处理遗留代码时,一旦需要修改或增加使用可变数据的代码,可以借机把这份数据封装起来,从而避免继续加重耦合一份已经广泛使用的数据。

面向对象方法如此强调对象的数据应该保持私有(private),背后也是同样的原理。每当看见一个公开(public)的字段时,考虑使用封装变量来缩小其可见范围。

封装数据很重要,不过,不可变数据更重要。如果数据不能修改,就根本不需要数据更新前的验证或者其他逻辑钩子。

做法

  • 创建封装函数,在其中访问和更新变量值。
  • 执行静态检查。
  • 逐一修改使用该变量的代码,将其改为调用合适的封装函数。每次替换之后,执行测试。
  • 限制变量的可见性。
  • 测试。
  • 如果变量的值是一个记录,考虑使用封装记录(162)。

封装值

对数据结构的引用做封装,能控制对该数据结构的访问和重新赋值;但并不能控制对结构内部数据项的修改。

控制结构内部数据的修改方法:

  • 取值函数中返回数据的一份副本(保护源数据,防止源数据变化导致的意外事故)

  • 阻止对数据的修改(禁止对数据结构内部的数值做任何修改)

数据封装很有价值,但往往并不简单。到底应该封装什么,以及如何封装,取决于数据被使用的方式,以及想要修改数据的方式。

变量改名(Rename Variable | 137)

在这里插入图片描述

let a = height * width;
let area = height * width; 

动机

好的命名是整洁编程的核心。变量名起得好,变量可以很好地解释一段程序在干什么。

变量使用范围越广,名字的好坏就越重要。

机制

  • 如果变量被广泛使用,考虑运用封装变量(132)将其封装起来。
  • 找出所有使用该变量的代码,逐一修改。(已发布变量,不能进行这个重构)
  • 测试。

引入参数对象(Introduce Parameter Object | 140)

在这里插入图片描述

function amountInvoiced(startDate, endDate) {...}
function amountReceived(startDate, endDate) {...}
function amountOverdue(startDate, endDate) {...}
function amountInvoiced(aDateRange) {...}
function amountReceived(aDateRange) {...}
function amountOverdue(aDateRange) {...}

动机

一组数据项(作为函数参数)总是同时出现(这样一组数据就是所谓的数据泥团)。

将数据组织成结构是一件有价值的事,因为这让数据项之间的关系变得明晰。使用新的数据结构,参数的参数列表也能缩短。

做法

  • 如果暂时还没有一个合适的数据结构,就创建一个
  • 测试
  • 使用改变函数声明(124)给原来的函数新增一个参数,类型是新建的数据结构
  • 测试
  • 调整所以调用者,传入新数据结构的适当实列。修改每一处,执行测试
  • 用新数据结构中的每一项元素,逐一取代参数列表中与之对应的参数项,然后删除原来的参数。测试

函数组合成类(Combine Functions into class | 144)

在这里插入图片描述

function base(aReading) {...}
function taxableCharge(aReading) {...}
function calculateBaseCharge(aReading) {...}
class Reading {base() {...}taxableCharge() {...}calculateBaseCharge() {...}
}

动机

类,在大多数现代编程语言中都是基本的构造。它们把数据与函数捆绑到同一个环境中,将一部分数据与函数暴露给其他程序元素以便协作。

如果发现一组函数相互操作同一块数据(通常是将这块数据作为参数传递给函数),可以将这几个函数足见2一个类。类能明确地给这些函数提供一个共用的环境,在对象内部调用这些函数可以少传许多参数,从而简化函数调用。

做法

  • 运用封装记录(162)对多个函数共用的数据记录加以封装。
  • 对于使用该记录结构的每个函数,运用搬移函数(198)将其移入新类。(如果函数调用时传入的参数已经是新类的成员,则从参数列表中去除之。)
  • 用以处理该数据记录的逻辑可以用提炼函数(106)提炼出来,并移入新类。

函数组合成变换(Combine Functions into Transfrom | 149)

在这里插入图片描述

动机

在软件中经常有这类操作:一个数据项在一个函数中处理加工后,有进入到其他函数中继续处理加工,经过几番处理,才得到最终需要的结果(可能我们的初衷不这样,但由于后期新需求、功能的添加才形成这种现象)。

一个方式是采用数据变换(transform)函数:这种函数接受源数据作为输入,计算出所有的派生数据,将派生数据以字段形式填入输出数据。

函数组合成变换的替代方案是函数组合成类(144),后者的做法是先用源数据创建一个类,再把相关的计算逻辑搬移到类中。

做法

  • 创建一个变换函数,输入参数是需要变换的记录,并直接返回该记录的值。
  • 挑选一块逻辑,将其主体一如变换函数中,把结果作为字段添加到输出记录中。修改客户端代码,令其使用这个新字段
  • 测试
  • 针对其他相关的计算逻辑,重复上述步骤

拆分阶段(Split Phase | 154)

在这里插入图片描述

const orderData = orderString.split(/\s+/);
const productPrice = priceList[orderData[0].split("-")[1]];
const orderPrice = parseInt(orderData[1]) * productPrice;
const orderRecord = parseOrder(order);
const orderPrice = price(orderRecord, priceList);
function parseOrder(aString) {
const values = aString.split(/\s+/);return ({productID: values[0].split("-")[1],quantity: parseInt(values[1]),});
}
function price(order, priceList) {return order.quantity * priceList[order.productID];
}

动机

一段代码在同时处理两件不同的事。

最简洁的拆分方法之一,就是把一大段行为分成顺序执行的两个阶段。

做法

  • 将第二阶段的代码提炼成独立的函数
  • 测试
  • 引入一个中转数据结构,将其作为参数添加到提炼出的新函数的参数中
  • 测试
  • 逐一检查提炼出的“第二阶段函数”的每个参数。如果某个参数被第一阶段用到,将其移入中转数据结构。每次搬移之后都要执行测试。
  • 对第一阶段的代码运用提炼函数(106),让提炼出的函数返回中转数据结构。

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

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

相关文章

用半天时间从零开始复习前端之html

目录 前言 科班生的标配:半天听完一门标记型语言 准备工作 webstorm2022 webstrom 第一个html页面 body h系列标签 行标签和块标签 列表标签 表格标签(另起一篇) 万能的input 1.快速生成多个标签 2.同时选中多个 前言 科班生的标…

系统报错“由于找不到msvcp140.dll无法继续执行代码”的处理方法

我在使用电脑时,突然发现了一个错误提示:“无法启动程序,因为找不到msvcp140.dll文件”。这让我非常困惑,因为我确定这个文件应该存在于我的电脑上。但是电脑依然报错“由于找不到msvcp140.dll无法继续执行代码”,这个…

【周末闲谈】如何利用AIGC为我们创造有利价值?

个人主页:【😊个人主页】 系列专栏:【❤️周末闲谈】 系列目录 ✨第一周 二进制VS三进制 ✨第二周 文心一言,模仿还是超越? ✨第二周 畅想AR 文章目录 系列目录前言AIGCAI写作AI绘画AI视频生成AI语音合成 前言 在此之…

Linux防火墙(iptables)

一、linux的防火墙组成 linux的防火墙由netfilter和iptables组成。用户空间的iptables制定防火墙规则,内核空间的netfilter实现防火墙功能。 netfilter(内核空间)位于Linux内核中的包过滤防火墙功能体系,称为Linux防火墙的“内核…

MHA高可用及故障切换

一、什么是 MHA MHA(MasterHigh Availability)是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点的问题。 MySQL故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作。 MHA能在故障切换的过程中最大…

Vue中如何实现城市3D分布图

cityfenbu.vue <template><div ><el-card class"seriesmap-box-card"><div slot"header" class"clearfix"><span>城市分布图 (点击可下钻到县)</span></div><div><div class"series-ma…

c语言练习45:模拟实现内存函数memcpy

模拟实现内存函数memcpy 针对内存块&#xff0c;不在乎内存中的数据。 拷贝内容有重叠的话应用memmove 模拟实现&#xff1a; 代码&#xff1a; 模拟实现memcpy #include<stdio.h> #include<assert.h> void* my_memcpy(void* dest, const void* src, size_t num…

【Linux】网络编程网络基础(C++)

目录 一、计算机网络背景 二、认识 "协议" 三、网络协议初识 【3.1】协议分层 【3.2】OSI七层模型 【3.3】TCP/IP五层(或四层)模型 四、网络传输基本流程 【4.1】网络传输流程图 【4.2】数据包封装和分用 五、网络中的地址管理 一、计算机网络背景 【独立…

谷粒商城----缓存与分布式锁

1、缓存使用 为了系统性能的提升&#xff0c;我们一般都会将部分数据放入缓存中&#xff0c;加速访问。而 db 承担数据落盘工作。 哪些数据适合放入缓存&#xff1f;  即时性、数据一致性要求不高的  访问量大且更新频率不高的数据&#xff08;读多&#xff0c;写少&…

The WebSocket session [x] has been closed and no method (apart from close())

在向客户端发送消息时&#xff0c;session关闭了。 不管是单客户端发送消息还是多客户端发送消息&#xff0c;在发送消息之前判断session 是否关闭 使用 isOpen() 方法

Nginx 学习(九)集群概述与LVS工作模式的配置

一 集群 1 概述 通过高速网络将很多服务器集中起来一起提供同一种服务&#xff0c;在客户端看来就像是只有一个服务器可以在付出较低成本的情况下获得在性能、可靠性、灵活性方面的相对较高的收益任务调度是集群系统中的核心技术 2 目的 提高性能。如计算密集型应用&…

【C++进阶】:AVL树(平衡因子)

AVL树 一.概念二.插入1.搜索二叉树2.平衡因子 三.旋转1.更新平衡因子2.旋转1.左单旋2.右单旋3.先右旋再左旋4.先左旋再右旋 四.完整代码 一.概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元…

2023区块链应用操作员认证(4级)报名来弘博创新

区块链应用操作员&#xff0c;是指运用区块链技术及工具&#xff0c;从事政务、金融、医疗、教育、养老等场景系统应用操作的人员。 腾讯作为广东省第一批公布的社会培训评价组织&#xff0c;可开展职业技能等级认定职业(工种)区块链应用操作员(4-3-2-1级)。 证书含金量 证书是…

Redis 删除策略

文章目录 Redis 删除策略一、过期数据二、数据删除策略1、定时删除2、惰性删除3、定期删除4、删除策略对比 三、逐出算法 Redis 删除策略 一、过期数据 Redis是一种内存级数据库&#xff0c;所有数据均存放在内存中&#xff0c;内存中的数据可以通过TTL指令获取其状态 XX &a…

100万级连接,爱奇艺WebSocket网关如何架构

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;很多小伙伴拿到一线互联网企业如阿里、网易、有赞、希音、百度、滴滴的面试资格。 最近&#xff0c;尼恩指导一个小伙伴简历&#xff0c;写了一个《高并发网关项目》&#xff0c;此项目帮这个小伙拿到 字节/阿里/微…

BPPISE数据科学案例框架

本专题共10篇内容&#xff0c;包含淘宝APP基础链路过去一年在用户体验数据科学领域&#xff08;包括商详、物流、性能、消息、客服、旅程等&#xff09;一些探索和实践经验。 在商详页基于用户动线和VOC挖掘用户决策因子带来浏览体验提升&#xff1b;在物流侧洞察用户求助时间与…

Kafka3.0.0版本——增加副本因子

目录 一、服务器信息二、启动zookeeper和kafka集群2.1、先启动zookeeper集群2.2、再启动kafka集群 三、增加副本因子3.1、增加副本因子的概述3.2、增加副本因子的示例3.2.1、创建topic(主题)3.2.2、手动增加副本存储 一、服务器信息 四台服务器 原始服务器名称原始服务器ip节点…

被问到: http 协议和 https 协议的区别怎么办?别慌,这篇文章给你答案

前言 作为软件测试师&#xff0c;大家都知道一些常用的网络协议是我们必须要了解和掌握的&#xff0c;比如 HTTP 协议&#xff0c;HTTPS 协议就是两个使用非常广泛的协议&#xff0c;所以也是面试官问的面试的时候问的比较多的两个协议&#xff1b;因为这两个协议有相似和关联的…

为什么说网络安全是风口行业?是it行业最后的红利?

前言 “没有网络安全就没有国家安全”。当前&#xff0c;网络安全已被提升到国家战略的高度&#xff0c;成为影响国家安全、社会稳定至关重要的因素之一。 网络安全行业特点 1、就业薪资非常高&#xff0c;涨薪快 2021年猎聘网发布网络安全行业就业薪资行业最高人均33.77万&…

移除链表元素_每日一题

“路虽远&#xff0c;行则将至” ❤️主页&#xff1a;小赛毛 ☕今日份刷题&#xff1a;移除链表元素 题目描述&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例1&…