首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

《重构》笔记摘录 - 6.重新组织数据

  • 25-04-16 12:20
  • 4069
  • 13298
juejin.cn

1 拆分变量(Split Variable)

变量有各种不同的用途,其中某些用途会很自然地导致临时变量被多次赋值。

“循环变量”和“结果收集变量”就是两个典型例子:循环变量会随循环的每次运行而改变;结果收集变量负责将通过整个函数的运算而构成的某个值收集起来。

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

如果变量承担多个责任,它就应该被替换(分解)为多个变量,每个变量只承担一个责任。同一个变量承担两件不同的事情,会让代码阅读者糊涂。

2字段改名(Rename Field)

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

数据结构对于帮助阅读者理解特别重要。多年以前,Fred Brooks 就说过:“只给我看你的工作流程却隐藏表单,我将仍然一头雾水。但是如果你给我展示表单,或许不需要流程图,就能柳暗花明。”现在已经不太有人画流程图了,不过道理还是一样的。

数据结构是理解程序行为的关键。既然数据结构如此重要,就很有必要保持它们的整洁。一如既往地,我在一个软件上做的工作越多,对数据的理解就越深,所以很有必要把我加深的理解融入程序中。

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

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

可变数据是软件中最大的错误源头之一。对数据的修改常常导致代码的各个部分以丑陋的形式互相耦合:在一处修改数据,却在另一处造成难以发现的破坏。

很多时候,完全去掉可变数据并不现实,但我还是强烈建议:尽量把可变数据的作用域限制在最小范围。有些变量其实可以很突易地随时计算出来。如果能去掉这些变量,也算朝着消除可变性的方向迈出了一大步。计算常能更清晰地表达数据的含义,而且也避免了“源数据修改时忘了更新派生变量”的错误。

有一种合理的例外情况:如果计算的源数据是不可变的,并且我们可以强制要求计算的结果也是不可变的,那么就不必重构消除计算得到的派生变量。因此,“根据源数据生成新数据结构”的变换操作可以保持不变,即便我们可以将其替换为计算操作。

实际上,这是两种不同的编程风格:一种是对象风格,把一系列计算得出的属性包装在数据结构中;另一种是函数风格,将一个数据结构变换为另一个数据结构。如果源数据会被修改,而你必须负责管理派生数据结构的整个生命周期,那么对象风格显然更好。但如果源数据不可变,或者派生数据用过即弃,那么两种风格都可行。

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

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

如果把一个字段视为值对象,我可以把内部对象的类也变成值对象。值对象通常更容易理解,主要因为它们是不可变的。

一般说来,不可变的数据结构处理起来更容易。我可以放心地把不可变的数据值传给程序的其他部分,而不必担心对象中包装的数据被偷偷修改。我可以在程序各处复制值对象,而不必操心维护内存链接。值对象在分布式系统和并发系统中尤为有用。值对象和引用对象的区别也告诉我,何时不应该使用本重构手法。如果我想在几个对象之间共享一个对象,以便几个对象都能看见对共享对象的修改,那么这个共享的对象就应该是引用。

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

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

例如,我可能会读取一系列订单数据,其中有多条订单属于同一个顾客。遇到这样的共享关系时,既可以把顾客信息作为值对象来看待,也可以将其视为引用对象。如果将其视为值对象,那么每份订单数据中都会复制顾客的数据;而如果将其视为引用对象,对于一个顾客,就只有一份数据结构,会有多个订单与之关联。如果顾客数据永远不修改,那么两种处理方式都合理。

把同一份数据复制多次可能会造成一点困扰,但这种情况也很常见,不会造成太大问题。过多的数据复制有可能会造成内存占用的问题,但就跟所有性能问题一样,这种情况并不常见。如果共享的数据需要更新,将其复制多份的做法就会遇到巨大的困难。此时我必须找到所有的副本,更新所有对象。只要漏掉一个副本没有更新,就会遭遇麻烦的数据不一致。这种情况下,可以考虑将多份数据副本变成单一的引用,这样对顾客数据的修改就会立即反映在该顾客的所有订单中。

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

注:本文转载自juejin.cn的使一颗心免于哀伤的文章"https://juejin.cn/post/7491971657201909814"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

143
阅读
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top