重构数据-Replace Data Value with Object以对象取代数据值二
创始人
2025-05-30 02:26:25

重构数据-Replace Data Value with Object以对象取代数据值二

1.以对象取代数据值

1.1.使用场景

你有一个数据项,需要与其他数据和行为一起使用才有意义。

开发初期,你往往决定以简单的数据项(data item)表示简单的行为。但是,随着开发的进行,你可能会发现,这些简单数据项不再那么简单了。
比如说,一开始你可能会用一个字符串来表示「电话号码」概念,但是随后你就会发现,电话号码需要「格式化」、「抽取区号」之类的特殊行为。
如果这样的数据项只有一二个,你还可以把相关函数放进数据项所属的对象里头;但是Duplication Code臭味和Feature Envy臭味很快就会从代码中散发出来。当这些臭味开始出现,你就应该将数据值(data value)变成对象(object)

1.2.如何做

  • 为待替换数值新建一个类,在其中声明一个final字段,其类型和源类中的待替换数值类型一样。然后在新类中加入这个字段的取值函数,再加上一个接受此字段为参数的构造函数。
  • 编译。
  • 将源类中的待替换数值字段的类型改为前面新建的类。
  • 修改源类中该字段的取值函数,令它调用新类的取值函数。
  • 如果源类构造函数中用到这个待替换字段(多半是赋值动作),我们就修改构造函数,令它改用新类的构造函数来对字段进行赋值动作。
  • 修改源类中待替换字段的设值函数,令它为新类创建一个实例。
  • 编译,测试。
  • 现在,你有可能需要对新类使用Change Value to Reference (179)。

1.3.示例

下面有一个代表「定单」的Order class,其中以一个字符串记录定单客户。现在,我希望改用一个对象来表示客户信息,这样我就有充裕的弹性保存客户地址、信用 等级等等信息,也得以安置这些信息的操作行为。Order class最初如下

 class Order...public Order (String customer) {_customer = customer;}public String getCustomer() {return _customer;}public void setCustomer(String arg) {_customer = arg;}// 通过属性表示客户信息private String _customer;

调用Order类的代码

   private static int numberOfOrdersFor(Collection orders, String customer) {int result = 0;Iterator iter = orders.iterator();while (iter.hasNext()) {Order each = (Order) iter.next();if (each.getCustomerName().equals(customer)) result++;}return result;}

首先,我要新建一个Customer class来表示「客户」概念。
然后在这个class中建立一个final值域,用以保存一个字符串,这是Order class目前所使用的。
我将这个新值域命名为_name,因为这个字符串的用途就是记录客户名称。
此外我还要为这个字符串加上取值函数(getter)和构造函数(constructor)

// 创建一个新类表示用户信息class Customer {// 构造器获取原先Order类中customer属性值public Customer (String name) {_name = name;}// 为属性提供get和set方法public String getName() {return _name;}private final String _name;}

现在,我要将Order中的_customer值域的型别修改为Customer;
并修改所有引用此一值域的函数,让它们恰当地改而使用Customer实体。
其中取值函数和构造函数的修改都很简单;至于设值函数(setter),我让它创建一份Customer实体。

 class Order...private Customer _customer;public Order (String customer) {// 将string类型替换为Customer类型对象_customer = new Customer(customer);}// 获取用户信息public String getCustomer() {//改为调用Customer对象获取属性值return _customer.getName();}// 设置用户信息,通过调用Customer构造器设置值public void setCustomer(String arg) {_customer = new Customer(arg);}

设值函数需要创建一个Customer实例,这是因为以前的字符串是个值对象(value object),所以现在的Customer对象也应该是个值对象。
这也就意味每个Order对象都包含自己的一个Customer对象。注意这样一条规则:值对象应该是不可修改内容的——这便可以避免一些讨厌的别名问题。日后或许我会想让Customer对象成为引用对象(reference object),但那是另一项重构手法的责任。现在我可以编译并测试了。

我需要观察Order类中的_customer字段的操作函数,并作出一些修改,使它更好地反映出修改后的新形势。
对于取值函数,我会使用Rename Method (273)改变其名称,让它更清晰地表示,它所返回的是消费者名称,而不是个Customer对象。

	// 将getCustomer名称改为getCustomerName 提高阅读性public String getCustomerName() {return _customer.getName();}

至于构造函数和设值函数,我就不必修改其签名(signature)了,但参数名称得改:

// 修改构造函数参数名称,提高阅读性
public Order (String customerName) {_customer = new Customer(customerName);
}
// 修改设置函数参数名称,提高阅读性
public void setCustomer(String customerName) {_customer = new Customer(customerName);
}

后续的其他重构也许会让我添加新的、「接受既有Customer对象作为参数」的构造函数和设值函数。
本次重构到此为止。但是这个案例和其他很多案例一样,还需要一个后续步骤。

如果想在Customer对象中加入信用等级、地址之类的其他信息,现在还做不到,因为目前的Customer还是被作为值对象(value object)来对待。
下面介绍下只对象和引用对象的区别,就能理解Customer为什么还不能投入生产使用。

值对象:当一个客户Customer下了多个订单Order后,每个订单类都将创建一个客户对象,即使多个订单属于同一个客户,但每个Order对象还是拥有各自的Customer对象。所以对于多个订单Order来说没办法共享同一个客户的信息。
引用对象:同 一客户拥有多份不同定单,代表这些定单的所有Order对象就可以共享同一个Customer对象以及对象中的所有属性信息。

相关内容

热门资讯

汽车产业已经有“恒大”了?价格... 中国汽车产业即将迎来重大考验!近日,以直率著称的长城汽车董事长魏建军在接受媒体专访时,发出惊人警告:...
九牧的三重跃升:新场景、新智造... AI时代,中国卫浴加速征战世界。文 | 华商韬略 熊剑辉当上过春晚的宇树人形机器人,化身“礼仪小姐姐...
限流|限流算法 一、概念限流顾名思义,就是对请求或并发数进行限制;通过对一个时间窗口内的...
浙江金融反腐风暴:工行浙江分行... 靴子落地。5月30日,据中央纪委国家监委驻中国工商银行纪检监察组、辽宁省纪委监委消息:中国工商银行浙...
四年前收购的一家公司,如今要上... 这位实控人四年前收购了个企业,现在就准备让公司在港交所上市了!5月29日,港交所官网披露,江苏日御光...
美的集团董事长方洪波:小米进入... 5月30日,美的集团(000333.SZ、00300.HK,简称美的)董事长兼总裁方洪波在美的集团2...
产品研发利好引发连日大涨 舒泰... 新京报贝壳财经讯(记者丁爽)5月30日,舒泰神再度大涨收场。至当日收盘,公司股价涨15.02%,报2...
sql 标准的隔离级别 事务并发执行时遇到的一致性问题脏读(Dirty Read)如果一个事务读...
【读书笔记】电子商务 目录1,四种业务模式2,三种电商模式2.1 运营模式:“流...
5月收官,个股平均涨5%!机构... A股5月收官,全月大盘维持震荡,概念题材热点飞速轮动。今年的5月并不是“5穷”,两市5000余只个股...
说到底,钱生钱就这4个办法|小... 点击 “简七读财” ,发送消息“理财小工具”免费领取40个赚钱工具资源包~晚上好呀~不少朋友吐槽,...
一杯咖啡3块钱,“外卖补贴”带... 本文来源:时代周报 作者:孙艺格 图源:库迪咖啡官网1元的超大杯奶茶、1.68元的美式咖啡、2.6...
中国联塑创始人之子上任执行董事... 一则人事变动,让国内管道建材头部企业中国联塑集团控股有限公司(以下简称“中国联塑”)受到关注。中国联...
谷粒学院SpringSecur... 登录功能前端分析前端会调用此接口去实现登录// 登录export function login(us...
【基于协同过滤算法的推荐系统项... 本文目录1、推荐系统的关键元素1.1 数据1.2 算法1.3 业务领域1.4 展示信息2、推荐算法的...
公告精选丨中国交建:拟以5亿元... 今日焦点中国交建:拟以5亿元-10亿元回购公司A股股份中国交建公告称,公司拟不低于5亿元,不超过10...
javascript数组常用方... 数组对于程序语言的重要性自不必多说,而在使用javascript的时候难免也会需要用到...
SpringBoot学习--基... 本专栏主要记录SpringBoot学习之路 文章目录1 SpringBoot基本介绍1.1 官方文档...
重组停牌!渤海汽车拟购海纳川旗... 5月30日,渤海汽车(600960.SH)发布公告称,公司拟通过发行股份及支付现金的方式,购买北京海...
Spring学习(五) 事物管理: 一、事物管理的回顾: 1、事物的概念: 事物&...
java线程同步 并发:同一个对象被多个线程同时操作处理多线程问题时,多个线程访问同一个对...
代码审计(二) 一、DevSecOps的概念DevSecOps 是描述开发、安全和运营集成的术语。它是一种文化、自动...
西安高新“楼市新政”,一场“教... 第 2302期〡2025/05/30西安各区域的土地市场和区域价值或将重新洗牌。上周,西安高新区一份...
603023,下周复牌!正式摘... 2025.05.30本文字数:855,阅读时长大约2分钟5月30日,*ST威帝公告称,公司股票将于2...
第十章 STM32+ESP82... 前言 最近有不少小伙伴私信留言,想要我推出一章能够通过APP进行远程控制并获取传感器信...
试题 算法训练 逗志芃的暴走 问题描述   逗志芃是有妹子的现充,但是有时候妹子就是烦恼。因为逗志芃太逗了ÿ...
德邦证券董事会改组完成,山东财... 山东财金集团披露,5月29日,德邦证券在济南召开2025年度第一次临时股东会,会议选举产生公司新一届...
法网:郑钦文2-0胜资格赛黑马... 北京时间5月30日,2025赛季网球大满贯法国公开赛继续进行,在女单第三轮的一场比赛中,赛会8号种子...
宗馥莉接手父亲名下娃哈哈实业公... 天眼查App显示,近日,浙江娃哈哈实业股份有限公司发生工商变更,宗庆后卸任法定代表人、董事长、总经理...
北交所上市公司恒拓开源大宗交易... 每经讯,2025年5月30日,北交所上市公司恒拓开源(834415,收盘价:17.83元)发生一笔大...