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

你有一个class,衍生出许多相等实体(equal instances),你希望将它们替换为单一对象。
将这个value object(实值对象)变成一个reference object(引用对象)。

 

动机

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


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

 

作法

1. 使用Replace Constructor with Factor Method(304)。

2. 编译,测试。

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

可能是个静态字典(static dictionary)或一个注册对象(registry object)

你也可以使用多个对象作为新对象的访问点(access point)。

4. 决定这些reference object应该预先创建好,或是应该动态创建。

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

5. 修改factory method,令它返回reference object。

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

你可能希望对factory method使用Rename Method(273),使其传达这样的信息;它返回的是一个既存对象。

6. 编译,测试。

 

在Replace Data Value with Object(175)一节中,我留下了一个重构后的程序,本节范例就从它开始。我们有下列的Customer class:

class Customer {
    public Customer(String name) {
       _name = name;
    }

    public String getName() {
       return _name;
    }
    private final String _name;
}

它被以下的order class使用:

class Order...
    public Order(String customerName) {
       _customer = new Customer(customer);
    }

    public String getCustomerName() {
       return _customer.getName();
    }
   
    public void setCustomer(String customerName) {
       _customer = new Customer(customerName);
    }
    private Customer _customer;

此外,还有一些代码也会使用Customer对象:

private static int numberOfOrdersFor(Collection orders, String customer) {
    int result = 0;
    Iterator iter = orders.iterator();
    while(iter.hasNext()) {
       Order each = (Order)iter.next();
       if(each.getCustomerName().equals(customer)) result ++;
    }
    return result;
}

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

首先我使用Replace Constructor with Factory Method(304)。这样,我就可以控制Customer对象的创建过程,这在以后会是非常重要的。我在Customer class中定义这个factory method:

class Customer {
    public static Customer create(String name) {
       return new Customer(name);
    }
}

然后我把[对构造函数的调用]替换成[对factory method的调用]

class Order {
    public Order(String customer) {
       _customer = Customer.create(customer);
    }
}

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

class Customer {
    private Customer(String name) {
       _name = name;
    }
}

现在,我必须决定如何访问Customer对象。我比较喜欢通过另一个对象(例如Order class中的一个值域)来访问它。但是本例并没有这样一个明显的值域可用于访问Customer对象。在这种情况下,我通常会创建一个注册(登录)对象,作为访问点。为了简化我们的例子,我把Customer对象保存在Customer class的一个static值域中,让Customer class作为访问点:

private static Dictionary _instance = new Hashtable();

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

class Customer...
    static void loadCustomers() {
       new Customer("Lemon Car Hire").store();
        new Customer("Associated Coffee Machines").store();
        new Customer("Bilston Gasworks").store();
    }
    private void store() {
       _instance.put(this.getName(), this);
    }

现在,我要修改factory method,让它返回预先创建好的Customer对象:

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

由于create()总是返回既有的Customer对象,所以我应该使用Rename Method(273)修改这个factory method的名称,以便强调(说明)这一点。

class Customer...
public static Customer getNamed(String name) {
    return (Customer)_instances.get(name);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值