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

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

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

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

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

int age = 13;

age = 14; // right

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

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

Money mon = Money(3);

mon = Money(4); // right

mon = mon.setValue(4); // 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实例,从而去掉工厂函数和控制实例创建的行为。

posted @ 2014-12-24 13:47  Ricky.K  阅读(811)  评论(0编辑  收藏  举报