返回总目录

本小节目录

  • Replace Data Value with Object(以对象取代数据值)
  • Change Value to Reference(将值对象改为引用对象)
  • Change Reference to Value(将引用对象改为值对象)

1Replace Data Value with Object(以对象取代数据值)

概要

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

动机

开发初期,你往往决定以简单的数据项表示简单的情况。但是,随着开发的进行,你可能会发现,这些简单数据项不再那么简单了。如果这样的数据项只有一两个,你还可以把相关函数放进数据项所属的对象里;但是Duplicated Code坏味道和 Feature Envy坏味道很快就会从代码中散发出来,当这些坏味道开始出现,就应该将数据值变成对象。

范例

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

class Order
{public string Customer { get; }public Order(string customer){Customer = customer;}public static int NumberOfOrderFor(List<Order> orders, string customer){return orders.Count(order => order.Customer == customer);}
}

首先新建一个Customer类来表示“客户”概念。

class Customer
{public string Name { get; }public Customer(string name){Name = name;}
}

现在来重构Order类:

class Order
{public Customer Customer { get; set; }public Order(string customerName){Customer = new Customer(customerName);}public static int NumberOfOrderFor(List<Order> orders, string customerName){return orders.Count(order => order.Customer.Name == customerName);}
}

小结

以对象取代数据值可以减少重复代码。

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

概要

你从一个类衍生出许多彼此相等的实例,希望将它们替换为同一个对象。将这个值对象变成引用对象。

动机

在许多系统中,都可以对对象分类:引用对象和值对象。前者就像“客户”、“帐户”这样的东西,每个对象都代表真实世界中的一个实物,你可以直接以相等操作符(==,用来检验同一性)检查两个对象是否相等。后者则是像“日期”、“钱”这样的东西,它们完全由其所含的数据值来定义,你并不在意副本的存在;系统中或许存在成百上千个内容为“1/1/2000”的“日期”对象。当然,你也需要知道两个值对象是否相等,所以你需要覆写Equals()以及GetHashCode())。

关于值对象和引用对象的更多介绍,请参考一下链接:

http://blog.csdn.net/u011453312/article/details/27269341

http://blog.jobbole.com/99723/

要在引用对象和值对象之间做选择有时并不容易。有时侯,你会从一个简单的值对象开始,在其中保存少量不可修改的数据。而后,你可能会希望给这个对象加入一些可修改数据,并确保对任何一个对象的修改都能影响到所有引用此一对象的地方。这时候你就需要将这个对象变成一个引用对象。

范例

看上一节重构后的代码:

class Customer
{public string Name { get; }public Customer(string name){Name = name;}}
class Order
{public Customer Customer { get; set; }public Order(string customerName){Customer = new Customer(customerName);}public static int NumberOfOrderFor(List<Order> orders, string customerName){return orders.Count(order => order.Customer.Name == customerName);}
}

到目前为止,Customer对象还是值对象。就算多份定单属于同一客户,但每个order对象还是拥有各自的Customer对象。我希望改变这一现状,使得一旦同一客户拥有多份不同定单,代表这些定单的所有Order对象就可以共享同一个Customer对象。

首先使用Replace Constructor with Factory Method,在Customer类中定义一个工厂函数:

public static Customer Create(string name)
{return new Customer(name);
}

然后把原本调用构造函数的地方改为调用工厂函数:

class Order
{public Customer Customer { get; set; }public Order(string customerName){Customer = Customer.Create(customerName);}...
}

再把构造函数改为私有的:

private Customer(string name)
{Name = name;
}

接着在Customer类中声明一个字典集合,把它保存在Customer类的static字段中,让Customer类作为访问点:

private static Dictionary<string, Customer> _instance = new Dictionary<string, Customer>();

然后在接到请求时事先将Customer创建好。

public static void LoadCustomers()
{new Customer("Lemon Car Hire").Store();new Customer("Associate Coffee MAchines").Store();new Customer("Bilson Gasworks").Store();
}
private void Store()
{_instance.Add(Name, this);
}

最后,修改工厂函数,让他返回预先创建好的Customer对象,并使用Rename Method修改该函数的名称:

public static Customer GetNamed(string name)
{_instance.TryGetValue(name, out Customer customer);return customer;
}

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

概要

你有一个引用对象,很小且不可变,而且不易管理。将它变为一个值对象。

动机

如果你发现引用对象开始变得难以使用,你就考虑是否应该把它改为值对象。引用对象必须被某种方式控制,你总是必须向其控制者请求适当的引用对象。它们可能造成内存区域之间错综复杂的关联。在分布系统和并发系统中,不可变的值对象特别有用,因为你无需考虑它们的同步关系。

值对象有一个非常重要的特性----它应该是不可变的。无论何时,只要你调用同一个对象的同一个查询函数,它返回的结果应该是一样的。如果你可以保证这一点,你可以放心的让多个对象表示同一个事物。如果值对象是可变的,你就必须确保某一个对象的修改会自动更新到其他代表相同事物的对象中去。那此时你应该使用引用对象了。

范例

class Currency
{public string Code { get; }private Currency(string code){Code = code;}
}

这个货币类目前是一个引用对象。要把一个引用对象变成值对象,关键动作是观察它是否不可变,如果不是,那就别用此次重构,因为后期的别名同步问题还很烦人。

在这里Currency是不可变的,所以重写Equals()和GetHashCode():

public override bool Equals(object obj)
{var currency = obj as Currency;return currency != null &&Code == currency.Code;
}public override int GetHashCode()
{return Code.GetHashCode();
}

完成这个之后我们进行编译,测试。现在我们想创建多少个Currency都没问题,我们还可以把他的构造函数声明为public,我们可以直接用构造函数来获取Currency实例,从而去掉工厂函数和控制实例创建的行为。

小结

我们一直说值对象是不可变的。那么什么是不可变?不可变意味着如果你以Money来表示金钱,那么Money通常是一个不可变的值。这并不是意味着你的薪资不能改变。而是意味着如果你改变薪资,你必须用另一个对象来替换现在的Money对象,而不是在现在的Money对象上做修改。你和Money对象之间的关系诶改变,但Money对象自身不能改变。

To Be Continued……

重构手法之重新组织数据【1】相关推荐

  1. 重构手法之重新组织函数

    重构手法之重新组织函数 在重构的手法中,很大的一部分是对函数进行整理,使函数能够恰当地包装代码(让代码自己说话而不是写更多的注释).重新组织函数的驱动力,往往都是由于函数过长.因为函数过长就以为着包含 ...

  2. 重构-改善既有代码的设计:重新组织数据的16种方法(六)

    重新组织数据: 1.Self Encapsulate Field 自封装字段 间接访问类的属性:你直接访问一个字段,但与字段之间的耦合关系逐渐变得笨拙.为这个字段建立取值/设值函数,并且只以这些函数来 ...

  3. 重构改善既有代码设计--重构手法19:Replace Data Value with Object (以对象取代数据值)...

    你有一笔数据项(data item),需要额外的数据和行为. 将这笔数据项变成一个对象. class Order... private string customer; ==> class Or ...

  4. 重构手法——提炼函数、搬移函数、以多态取代条件表达式

    目录 我的心路历程 我的学习概括 Extract Method(提炼函数) 动机*--做法 动机--做法* Move Method(搬移函数) 动机*--做法 动机--做法* Replace Cond ...

  5. 【DBMS 数据库管理系统】数据仓库特征 ( 特征一 : 面向主题组织数据 | 特征二 : 数据集成 | 特征三 : 数据不可更新 | 特征四 : 随时间不断变化 )

    文章目录 一.特征一 : 面向主题 数据组织方式 二.特征二 : 数据集成 三.特征三 : 数据不可更新 四.特征四 : 数据仓库中的数据 随时间不断变化 一.特征一 : 面向主题 数据组织方式 主题 ...

  6. 【DBMS 数据库管理系统】数据仓库 ( 数据仓库简介 | 操作型数据与分析性数据对比 | 数据仓库特征 | 特征一 : 面向主题组织数据 | 面向应用 | )

    文章目录 一.数据仓库简介 二.操作型数据与分析型数据对比 三.数据仓库 特征 与 定义 四.特征一 : 面向主题 数据组织方式 五.面向应用 数据组织方式 六.面向主题 组织数据 七.数据 从 面向 ...

  7. 重构手法之简化函数调用【1】

    返回总目录 本小节目录 Rename Method(函数改名) Add Parameter(添加参数) Remove Parameter(移除参数) 1Rename Method(函数改名) 概要 函 ...

  8. 数据结构 (计算机存储、组织数据方式)

    数据结构是计算机存储.组织数据的方式.数据结构是指相互之间存在一种或多种特定关系的数据元素的集合.通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率.数据结构往往同高效的检索算法和索引技术有 ...

  9. 从List分组后重新组织数据

    ///从List分组后从重组织数据var res = result.GroupBy(s => new {s.LegalUnitID,s.TYPE_CD,s.TYPE_NAME,s.TYPE_NA ...

最新文章

  1. 那些打着AI万金油旗号的产品欺骗大众,如何识别?
  2. html开启页面离线缓存,HTML5 离线缓存
  3. 一套比较完整的前端技术选型,需要规整哪些东西,你知道不?
  4. C# 字符串格式化测试小工具
  5. linux shell 读取for循环中出现难处理的数据之单引号错误实例
  6. 【Vue2.0】—解决页面闪烁的问题(八)
  7. 未来的信息化,就是挖掘企业数据、提升战略决策
  8. highcharts插件使用总结和开发中遇到的问题及解决办法
  9. 免费「模拟面试」福利反馈连载(20180128期)
  10. 卓有成效的管理者(笔记)——如何发挥人的长处
  11. 解决CAS 4.2.7 版本集群部署的各种问题
  12. InTouch蜂鸣器报警提示方法
  13. PDF书签制作的方法!
  14. 基于C#+ASP.NET 毕业设计526套(保持更新)(建议CTRL+D)
  15. 常见哈希算法、Hmac算法和BouncyCastle
  16. 原来手机还能当做扫描仪?安卓苹果都可以,纸质稿轻松电子化
  17. 100%BIM学员的疑惑:不会CAD可以学Revit吗?
  18. 值得收藏,这6种制作竞赛动图的方法妙不可言
  19. 美甲实体行业没有客户?想做线上引流?这些渠道千万别错过!
  20. 活动报名丨IDEA研究院 杨平:统一自然语言理解任务为多项式选择任务

热门文章

  1. nsarray数组越界_NSArray,NSMutableArray –目标C数组
  2. testng 监听器_TestNG侦听器
  3. Java SE 9:使用IntelliJ IDE开发和测试模块之间的隐式可读性(第5部分)
  4. 浅析C++开发工程师的薪资与发展
  5. 什么是super?如何使用super调用超类构造函数?
  6. OpenCV(一)Mac下OpenCV的安装和配置
  7. Flink状态管理和容错机制介绍
  8. WPF整理-使用ResourceDictionary管理Logical Resources
  9. 编写一个函数itob(),将整数n转换为以b进制的数,保存到s中
  10. OpenCV学习(17) 细化算法(5)