你有一个引用对象,很小且不可变,并且不易管理。将它变成一个值对象。 java
若是引用对象开始变得难以使用,也许就应该将它改成值对象。引用对象必须被某种方式控制,你老是必须向其控制者请求适当的引用对象。它们可能形成内存区域之间错综复杂的关联。在分布系统和并发系统中,不可变的值对象特别有用,由于你无需考虑它们的同步问题。 并发
值对象有一个很是重要的特性:它们应该是不可变的。不管什么时候,只要你调用同一个对象的同一个查询函数,都应该获得一样的结果。若是保证了这一点,就能够放心地以多个对象表示同一个事物。若是值对象是可变的,就必须确保对某一对象的修改会自动更新其余“表明相同事物”的对象。这台痛苦了,与其如此还不如把它变成引用对象。 函数
这里有必要澄清一下“不可变”的意思。若是以Money类表示“钱”的概念,其中有“币种”和“金额”两条信息,那么Money对象一般是一个不可变对象。这并不是意味着薪资不能变,而是意味着:若是要改变薪资,就须要使用另外一个Money对象来取代现有的Money对象,而不是在现有的Money对象上修改。你和Money对象之间的关系能够改变,可是Money对象自身不能改变。 测试
1.检查重构目标是否为不可变对象,或是否可修改成不可变对象。 this
若是该对象目前还不是不可变的,就使用Remove Setting Method,直到它成为不可变为止。 spa
若是没法将该对象修改成不可变的,就放弃使用本项重构。 code
2.创建equals() 和hashCode(). 对象
3.编译,测试。 内存
4.考虑是否能够删除工厂函数,并将构造函数声明为public。 get
咱们从一个表示“货币种类”的Currency类开始:
public class Currency { private String code; public String getCode() { return code; } private Currency( String code ) { this.code = code; } }
这个类所作的就是保存并返回一个货币种类代码。它是一个引用对象,因此若是要获得它的实例,必须这么作:
Currency usd = Currency.get("USD");Currency类维护一个包含全部Currency实例的链表。咱们不能直接使用构造函数建立实例,由于Currency构造函数是private的。
要把一个引用对象变成值对象,关键动做是:检查它是否可变。若是不是,就不能使用本项重构,由于可变的值对象会形成烦人的别名问题。
在这里,Currency对象是不可变的,因此下一步就是为它定义equals();
public boolean equals( Object arg ) { if( !( arg instanceof Currency ) ) { return false; } Currency other = ( Currency ) arg; return ( code.equals( other.getCode() ) ); }
定义了equals(),就必须同时定义hashcode()。实现hashcode() 有个简单办法:读取equals()使用的全部字段的hash码,而后对它们进行按位异或(^)操做。本例中,这很容易实现,由于equals()只是用了一个字段:
public int hashCode() { return code.hashCode(); }完成这两个函数后,咱们能够编译并测试。这两个函数的修改必须同时进行,不然依赖hash的任何集合对象(例如Hashtable、HashSet和HashMap)均可能产生意外行为。
如今,咱们能够建立任意多个Currency对象,还能够把构造函数声明为public,直接以构造函数获取Currency实例,从而去掉Currency类中的工厂函数和控制实例建立行为。