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

CH09_重新组织数据

拆分变量(Split Variable)

曾用名:移除对参数的赋值(Remove Assignments to Parameters)

曾用名:分解临时变量(Split Temp)

在这里插入图片描述

let temp = 2 * (height + width);
console.log(temp);
temp = height * width;
console.log(temp);
const perimeter = 2 * (height + width);
console.log(perimeter);
const area = height * width;
console.log(area);

动机

变量有各种不同的用途,其中某些用途会很自然地导致临时变量被多次赋值,“循环变量”和“结果收集变量”就是两个典型例子。

除了这两种情况,还有很多变量用于保存一段冗长代码的运算结果,以便稍后使用。这种变量应该只被赋值一次。如果它们被赋值超过一次,就意味它们在函数中承担了一个以上的责任。如果变量承担多个责任,它就应该被替换(分解)为多个变量,每个变量只承担一个责任。

做法

  • 在待分解变量的声明及其第一次被赋值处,修改其名称。
  • 如果可能的话,将新的变量声明为不可修改。
  • 以该变量的第二次赋值动作为界,修改此前对该变量的所有引用,让它们引用新变量。
  • 测试。
  • 重复上述过程。每次都在声明处对变量改名,并修改下次赋值之前的引用,直至到达最后一处赋值。

字段改名(Rename Field)

在这里插入图片描述

class Organization {get name() {...}
}
class Organization {get title() {...}
}

动机

命名很重要,对于程序中广泛使用的记录结构,其中字段的命名格外重要。

数据结构是理解程序行为的关键。记录结构中的字段可能需要改名,类的字段也一样。在类的使用者看来,取值和设值函数就等于是字段。对这些函数的改名,跟裸记录结构的字段改名一样重要。

做法

  • 如果记录的作用域较小,可以直接修改所有该字段的代码,然后测试。后面的步骤就都不需要了。
  • 如果记录还未封装,请先使用封装记录(162)。
  • 在对象内部对私有字段改名,对应调整内部访问该字段的函数。
  • 测试。
  • 如果构造函数的参数用了旧的字段名,运用改变函数声明(124)将其改名。
  • 运用函数改名(124)给访问函数改名。

以查询取代派生变量(Replace Derived Variable with Query)

在这里插入图片描述

get discountedTotal(){return this._discountedTotal;}
set discount(aNumber){const old = this._discount;this._discount=aNumber;this._discountedTotal += old - aNumber
}
get discountedTotal(){return this_baseTotal - this._discount;}
set discount(aNumber) {this._discount=aNumber;}

动机

可变数据是软件中最大的错误源头之一。对数据的修改常常导致代码的各个部分以丑陋的形式互相耦合:在一处修改数据,却在另一处造成难以发现的破坏。完全去掉可变数据并不现实,但还是强烈建议:尽量把可变数据的作用域限制在最小范围。

有些变量其实可以很容易地随时计算出来,可以去掉这些变量。计算常能更清晰地表达数据的含义,而且也避免了“源数据修改时忘了更新派生变量”的错误。

有一种合理的例外情况:如果计算的源数据是不可变的,并且我们可以强制要求计算的结果也是不可变的,那么就不必重构消除计算得到的派生变量。

两种不同的编程风格:一种是对象风格,把一系列计算得出的属性包装在数据结构中;另一种是函数风格,将一个数据结构变换为另一个数据结构。

做法

  • 识别出所有对变量做更新的地方。如有必要,用拆分变量(240)分割各个更新点。

  • 新建一个函数,用于计算该变量的值。

  • 用引入断言(302)断言该变量和计算函数始终给出同样的值。

    如有必要,用封装变量(132)将这个断言封装起来。

  • 测试。

  • 修改读取该变量的代码,令其调用新建的函数。

  • 测试。

  • 用移除死代码(237)去掉变量的声明和赋值。

将引用对象改为值对象(Change Reference to Value)

在这里插入图片描述

反向重构:将值对象改为引用对象(256)

class Product{applyDiscount(arg) {this._price.amount -= arg;}// ...
}
class Product {applyDiscount(arg) {this._price = new Money(this._price.amount - arg, this._price.currency);}// ...
}

动机

在把一个对象(或数据结构)嵌入另一个对象时,位于内部的这个对象可以被视为引用对象,也可以被视为值对象。两者最明显的差异在于如何更新内部对象的属性:如果将内部对象视为引用对象,在更新其属性时,保留原对象不动,更新内部对象的属性;如果将其视为值对象,替换整个内部对象,新换上的对象会有想要的属性值。

如果想在几个对象之间共享一个对象,以便几个对象都能看见对共享对象的修改,那么这个共享的对象就应该是引用。

一般说来,不可变的数据结构处理起来更容易。可以放心地把不可变的数据值传给程序的其他部分,而不必担心对象中包装的数据被偷偷修改。

做法

  • 检查重构目标是否为不可变对象,或者是否可修改为不可变对象。
  • 用移除设值函数(331)逐一去掉所有设值函数。
  • 提供一个基于值的相等性判断函数,在其中使用值对象的字段。

将值对象改为引用对象(Change Value to Reference)

在这里插入图片描述

反向重构:将引用对象改为值对象(252)

let customer = new Customer(customerData);
let customer = customerRepository.get(customerData.id);

动机

一个数据结构中可能包含多个记录,而这些记录都关联到同一个逻辑数据结构。

如果共享的数据需要更新,将其复制多份的做法就会遇到巨大的困难。漏掉一个副本没有更新,就会遭遇麻烦的数据不一致。

把值对象改为引用对象会带来一个结果:对于一个客观实体,只有一个代表它的对象。这通常意味着会需要某种形式的仓库,在仓库中可以找到所有这些实体对象。只为每个实体创建一次对象,以后始终从仓库中获取该对象。

做法

  • 为相关对象创建一个仓库(如果还没有这样一个仓库的话)。
  • 确保构造函数有办法找到关联对象的正确实例。
  • 修改宿主对象的构造函数,令其从仓库中获取关联对象。每次修改后执行测试。

相关文章:

CH09_重新组织数据

拆分变量(Split Variable) 曾用名:移除对参数的赋值(Remove Assignments to Parameters) 曾用名:分解临时变量(Split Temp) let temp 2 * (height width); console.log(temp); t…...

最新 IntelliJ IDEA 旗舰版和社区版下载安装教程(图解)

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...

优化 FPGA HLS 设计

优化 FPGA HLS 设计 用工具用 C 生成 RTL 的代码基本不可读。以下是如何在不更改任何 RTL 的情况下提高设计性能。 介绍 高级设计能够以简洁的方式捕获设计,从而减少错误并更容易调试。然而,经常出现的问题是性能权衡。在高度复杂的 FPGA 设计中实现高性…...

LVGL库入门 01 - 样式

一、LVGL样式概述 1、创建样式 在 LVGL 中,样式都是以对象的方式存在,一个对象可以描述一种样式。每个控件都可以独立添加样式,创建的样式之间互不影响。 可以使用 lv_style_t 类型创建一个样式并初始化: static lv_style_t s…...

酷克数据出席永洪科技用户大会 携手驱动商业智能升级

10月27日,第7届永洪科技全国用户大会在北京召开。酷克数据作为国内云原生数仓代表企业,受邀出席本次大会,全面展示了云数仓领域最新前沿技术,并进行主题演讲。 携手合作 助力企业释放数据价值 数据仓库是商业智能(BI…...

英语教育目标转变:更加注重实际应用能力培养

今年九月份,北京市教委发布了《关于深入推进高中阶段学校考试招生改革的实施意见》。按照该意见,北京市2024年初三年级学生的初中学业水平考试英语科目听力口语考试与笔试将分离,首次计算机考试将于2023年12月17日进行。 根据《意见》规定,听力口语计算机考试共有两次考试机会…...

Java中的继承和多态

目录 1. 继承 1.1 为什么需要继承 1.2 继承概念 1.3 继承的语法 1.4 父类成员访问 1.4.1 子类中访问父类的成员变量 1.4.2 子类中访问父类的成员方法 1.5 super关键字 1.6 子类构造方法 1.7 super和this 1.8 再谈初始化 1.9 protected 关键字 1.10 继承方式…...

海外问卷调查现在还可以做吗?

可以做,海外问卷调查是一个稳定长期的互联网创业项目。 大家好,我是橙河,这篇文章讲一讲海外问卷调查现在还可以做吗? 海外问卷调查,简单来说,就是外国的商业公司对外发放的付费调查问卷,按照…...

CA证书与服务器证书

服务器证书和CA证书是网络通信中使用的两种重要的证书。服务器证书是用于验证服务器身份的证书,而CA证书是用于验证证书颁发机构(Certificate Authority)身份的证书。 服务器证书是由网站服务器申请并由CA机构颁发的。它包含了服务器的公钥和其他相关信息&#xff…...

AI智能语音识别模块(二)——基于Arduino的语音控制MP3播放器

文章目录 简介离线语音控制模块Mini MP3模块0.96寸 OLED模块实验准备安装库接线定义主要程序实验效果注意事项总结 简介 在前面一篇文章里我们对AI智能语音识别模块进行了介绍,并对离线语音模组下载固件的过程进行了一个简单描述,不知道大家还记不记得&…...

CentOS部署Minikube

基本介绍 Minikube是本地的Kubernetes,专注于使其易于为Kubernete学习和开发。 官方地址:https://minikube.sigs.k8s.io/docs/start/ 部署安装 # CentOS 7.6# 前置条件:安装好Docker或其他容器引擎或虚拟机 参见《CentOS一键部署Docker》…...

第5章_排序与分页

文章目录 1 排序数据1.1 排序规则1.2 单列排序1.3 多列排序排序演示代码 2 分页2.1 背景2.2 实现规则2.3 拓展分页演示代码 3 课后练习 1 排序数据 1.1 排序规则 使用 ORDER BY 子句排序 ASC(ascend): 升序DESC(descend):降序 …...

Elasticsearch实战:常见错误及详细解决方案

Elasticsearch实战:常见错误及详细解决方案 1.read_only_allow_delete":“true” 当我们在向某个索引添加一条数据的时候,可能(极少情况)会碰到下面的报错: {"error": {"root_cause": [{&…...

C#添加缓存,删除缓存,修改缓存

在C#中,可以使用内置的缓存功能或者使用第三方缓存库来管理缓存。下面分别介绍使用内置缓存功能和使用第三方缓存库的方法。 使用内置缓存功能: 添加缓存: 在C#中,可以使用MemoryCache类来添加缓存。以下是一个简单的示例&…...

PADS Router的操作页面及鼠标指令介绍

PADS Router的用户界面由菜单栏,工作界面,一般工具栏,状态栏,项目浏览器组,输出窗口,电子表格组成(图1): 图1 注意:如果你的界面没有显示项目浏览器&#xff…...

Android studio进入手机调试状态

首先usb插入电脑手机打开开发者模式进入点击就会在你的页面显示了...

《Pytorch新手入门》第二节-动手搭建神经网络

《Pytorch新手入门》第二节-动手搭建神经网络 一、神经网络介绍二、使用torch.nn搭建神经网络2.1 定义网络2.2 torch.autograd.Variable2.3 损失函数与反向传播2.4 优化器torch.optim 三、实战-实现图像分类(CIFAR-10数据集)3.1 CIFAR-10数据集加载与预处理3.2 定义网络结构3.3…...

C++ 模板学习笔记

C另外一种编程成为 泛型编程 ,主要利用的技术就是模板 C提供两种模板机制:函数模板和类模板 C11中,函数模板和类模板都可以设定默认参数,传送门 函数模板 一般 typename 和 class 没有区别,typename 还有个作用是使…...

1、Flink基础概念

1、基础知识 (1)、数据流上的有状态计算 (2)、框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。 (3)、事件驱动型应用,有数据流就进行处理,无数据流就不…...

分享一下怎么做小程序营销活动

小程序营销活动已经成为现代营销的必备利器,它能够帮助企业提高品牌知名度、促进产品销售,以及加强与用户的互动。然而,要想成功地策划和执行一个小程序营销活动,需要精心设计和全面规划。本文将为您介绍小程序营销活动的策划和执…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...