如果你有一个引用对象,很小且不可改变,而且不易管理,你就需要考虑将他改为一个值对象。在Change Value to Reference我们说过,要在引用对象和值对象之间做选择,有时候并不容易,有了重构,做出选择之后,你还有一条回头路。

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

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

什么是不可变?不可变意味着如果你以Money来表示金钱,那么Money通常是一个不可变的值。这并不是意味着你的金钱不能改变。而是意味着如果你改变薪资,你必须用另一个对象来替换现在的Money对象,而不是在现在的Money对象上做修改。注意这里面的说法,这种改变就类似与我们原子级别的内置变量,举个例子

int age = ;

age = ; // right

age = int(13).setIntValue(); // false

对于内置类型int来说就是一个最简单的值类型,我们的年龄age在从13改变到14的时候,正是替换了现在的对象,产生了一个int(14)而不是直接在13对象上做修改。对于Money来说

Money mon = Money();

mon = Money(); // right

mon = mon.setValue(); // false

我们的mon也是做了对象的替换,而不会去采用setValue的形式去做修改。始终记住:值对象本身是不可修改的

  • 做法:
  • 检查重构目标,是否为不可变对象,或是否可以修改为不可变对象。如果该对象目前还不是不可变的,就使用Remove Setting Method直到它成为不可变为止。如果你实在无法将该对象修改为不可变,就放弃本次重构。
  • 建立“==”函数和hashCode()(Java)。
  • 编译,测试。
  • 考虑是否可以删除工厂函数,并将构造函数声明为public。

例子:

class Currency
{
private:
Currency(const QString &code) :
m_code(code)
{
}
public:
 QString code() const
{
return m_code;
}
private:
QString m_code;
};

这个货币类目前是一个引用对象,我们现在想得到他,必须通过这种方法

Currency *usd = Currency::get("USD");

Currency内部维护一个Hash表用来保存预先创建好的Currency实例,我们也不能直接通过构造函数来构造他们,因为此时的构造函数是私有的。要把一个引用对象变成值对象,关键动作是观察它是否可变,如果他可变,那就别用此次重构,因为后期的别名同步问题还很烦人。在这里Currency是不可变的,我们为它重载==

bool operator==(const Currency &value)
{
if (this == &value)
{
return true;
}
else
{
return this->m_code == value.code();
}
}

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

『重构--改善既有代码的设计』读书笔记----Change Reference to Value的更多相关文章

  1. 『重构--改善既有代码的设计』读书笔记----Change Value to Reference

    有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Va ...

  2. 『重构--改善既有代码的设计』读书笔记----Extract Method

    在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...

  3. 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object

    有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...

  4. 『重构--改善既有代码的设计』读书笔记---Duplicate Observed Data

    当MVC出现的时候,极大的推动了Model与View分离的潮流.然而对于一些已存在的老系统或者没有维护好的系统,你都会看到当前存在大把的巨大类----将Model,View,Controller都写在 ...

  5. 『重构--改善既有代码的设计』读书笔记----Replace Array with Object

    如果你有一个数组,其中的元素各自代表不同东西,比如你有一个 QList<QString> strList; 其中strList[0]代表选手姓名,strList[1]代表选手家庭住址,很显 ...

  6. 『重构--改善既有代码的设计』读书笔记----Self Encapsulate Field

    如果你直接访问一个字段,你就会和这个字段直接的耦合关系变得笨拙.也就是说当这个字段权限更改,或者名称更改之后你的客户端代码都需要做相应的改变,此时你可以为这个字段建立设值和取值函数并且只以这些函数来访 ...

  7. 『重构--改善既有代码的设计』读书笔记----Move Method

    明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...

  8. 『重构--改善既有代码的设计』读书笔记----Replace Data Value with Object

    当你在一个类中使用字段的时候,发现这个字段必须要和其他数据或者行为一起使用才有意义.你就应该考虑把这个数据项改成对象.在开发初期,我们对于新类中的字段往往会采取简单的基本类型形式来保存,但随着我们开发 ...

  9. 『重构--改善既有代码的设计』读书笔记----Substitute Algorithm

    重构可以把复杂的东西分解成一个个简单的小块.但有时候,你必须壮士断腕删掉整个算法,用简单的算法来取代,如果你发现做一件事情可以有更清晰的方式,那你完全有理由用更清晰的方式来解决问题.如果你开始使用程序 ...

随机推荐

  1. eclipse安装Hadoop1.1.2版本开发插件

    Hadoop1.1.2版本没有直接适合Eclipse的安装插件,需要手动打包jar文件. 我的系统配置: VMware Workstation10 CentOS-6.5-i386 hadoop-1.1 ...

  2. 修复直接删除linux系统后grub丢失错误

    如果删除了系统后,grub丢失,开机出现“grub>”的话,可以用如下代码进入目标linux系统:grub>ls (hd0,X)/boot             //x为目标系统所在分区 ...

  3. JavaScript 各种遍历方式详解

    为了方便例子讲解,现有数组和json对象如下 var demoArr = ['Javascript', 'Gulp', 'CSS3', 'Grunt', 'jQuery', 'angular']; v ...

  4. 天涯html&css基础框架

    html申明 对ie6-8在html中添加no-css3这个class和各个版本的class,对ie7以下添加lte7这个class,然后根据我们目前使用浏览器的比例,把第一的ie6放在判断第一位. ...

  5. Shell函数:Shell函数返回值、删除函数、在终端调用函数

    函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高.像其他编程语言一样,Shell 也支持函数.Shell 函数必须先定义后使用. Shell 函数的定义格式如下: f ...

  6. Gof-23种设计模式名称列表

    工欲善其事,必先利其器. 在真正使用设计模式之前,必须知道各个设计模式对应的场景.设计模式是针对某种固定的场景下产生的固定解决方案.只有明确的场景,才会有明确的设计方式和方法. 设计模式全集: Abs ...

  7. HttpURLConnection的流式输出的缺陷和解决方法

    转自:http://www.mzone.cc/article/198.html 最近在用applet写文件上传控件的时候发现使用URLConnection来对服务器进行流式输出时的一些问题.我们通常要 ...

  8. Java的redis 操作类-优化通用版本

    java操作redis多节点处理方式;http://blog.itpub.net/29254281/viewspace-1188644/首先maven引入依赖包 <dependency> ...

  9. Activiti5.16.4数据库表结构

    一.ACTIVITI 数据库E-R图(5.16.4) Activiti 5.16.4 总共有24张表,增加act_evt_log(事件日志),以及增加了对SasS的支持. 在流程定义.运行实例和历史的 ...

  10. oracle10 权限角色

    管理权限和角色 介绍 这一部分我们主要看看oracle中如何管理权限和角色,权限和角色的区别在那里.   当刚刚建立用户时,用户没有任何权限,也不能执行任何操作,oracle数据库会自动创建一个方案, ...