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

Summary:

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

Motivation:

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

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

Mechanics:

1.使用Replace Constructor with Factory Method

2.编译,测试。

3.决定由什么对象负责提供访问新对象的途径。

可能是一个静态字典或一个注册表对象;也可以使用多个对象作为新对象的访问点。

4.决定这些引用对象应该预先创建好,或是应该动态创建。

如果这些引用对象是预先创建好的,而你必须从内存中将它们读取出来,那么就得确保它们在被需要的时候能够被及时加载。

5.修改工厂函数,令它返回引用对象。

如果对象是预先创建好的,就需要考虑:万一有人索求一个其实并不存在的对象,要如何处理错误?

你可能希望对工厂函数使用Rename Method,使其传达这样的信息:它返回的是一个既存对象。

6.编译,测试。

范例

   在Replace Data Value with Object中,我们留下了一个重构后的程序,此范例就从它开始。

   在上一个重构(Replace Data Value with Object)结束时,Customer对象还是值对象。就算多份订单属于同一个客户,但每个Order对象还是拥有各自的Customer对象。我们希望改变这一现状,使得一旦同一个客户拥有多份不同订单,代表这些订单的Order对象就可以共享同一个Customer对象。这就意味着:每一个客户名称只能对应一个Customer对象。

   首先使用ReplaceConstructor with Factory Method。这样,就可以控制Customer对象的创建过程,这在以后是非常重要的。我们在Customer类中定义这个工厂函数:

public class Customer
{
    public static Customer create( String name )
    {
        return new Customer( name );
    }
}
然后把原本调用构造函数的地方修改为调用工厂函数:
public Order( String customerName )
{
    customer = Customer.create( customerName );
}

然后再把构造函数声明为private:

private Customer( String name )
{
    this.name = name;
}

现在,我们必须决定如何访问Customer对象。可以通过另个一对象(例如Order中的一个字段)来访问它。但是本例并没有这样一个明显的字段可用于访问Customer对象。在这种情况下,我们可以创建一个注册表对象来保存所有Customer对象,以此作为访问点。为了简化我们的例子,我们把这个注册表保存在Customer类的static字段中,让Customer类作为访问点:

private static Dictionary instances = new Hashtable();

然后我们得决定:应该在接到请求时创建新的Customer对象,还是应该预先将它们创建好。这里我们选择后者。在应用程序的启动代码中,先把需要使用的Customer对象加载妥当。这些对象可能来自数据库,也可能来自文件。为求简单起见,我们在代码中明确生成这些对象。如果以后需要,我们可以使用Substitute Algorithem 来改变它们的创建方式。

static void loadCustomers()
{
   new Customer( "Lemon Car Hire" ).store();
   new Customer( "Associated Coffee Machines" ).store();
   new Customer( "Bilston Gasworks" ).store();
}

private void store()
{
    instances.put( this.getName(), this );
}

现在,修改工厂函数,让它返回预先创建好的Customer对象:

public static Customer create( String name )
{
    return ( Customer ) instances.get( name );
}

由于create()总是返回既有的Customer对象,所以我们应该使用Rename Method修改这个工厂函数的名称,以便强调这一点

public static Customer getNamedCustomer( String name )
 {
     return ( Customer ) instances.get( name );
}

你可能感兴趣的:(Change Value to Reference (将值对象改为引用对象))