Replace Data Value with Object (以对象取代数据值)

Summary:  

有一个数据项,需要与其他数据和行为一起使用才有意义。将数据项变成对象。

Motivation: 

开发初期,我们以简单的数据项表示简单的情况。但是随着开发的进行,你可能会发现,这些简单数据项不再那么简单了。比如说,一开始你可能会用一个字符串来表示“电话号码”概念,但是随后就会发现,电话号码需要“格式化”、“抽取区号”之类的特殊行为。如果这样的数据有一两个,还可以把相关函数放进数据项所属的对象里;但是Duplicate Code坏味道和Feature Envy坏味道很快就会从代码中散发出来。当这些坏味道开始出现,就应该将数据值变成对象。

Mechanics: 

1.为带替换数据新建一个类,在其中声明一个final字段,其类型和源类中的带替换数值类型一样。然后在新类中加入这个字段的取值函数,再加上一个接受此字段为参数的构造函数。

2.编译

3. 将源类中的带替换数值字段的类型改为前面新建的类。

4. 修改源类中该字段的取值函数,令它调用新类的取值函数。

5. 如果源类构造函数中用到这个待替换字段,我们就修改构造函数,令它改用新类的构造函数来对字段进行赋值动作。

6.修改源类中待替换字段的设值函数,令它为新类创建一个实例。

7.编译,测试

8. 现在,可能需要对新类使用Change Value to Reference.

范例

下面有一个代表“订单”的Order类,其中以一个字符串记录订单客户。现在,我们希望改用一个对象来表示客户信息,这样就有充裕的弹性保存客户地址、信用等级等信息,也得以安置这些信息的操作行为。Order类最初如下:

public class Order
{
    private String customer;

    public Order( String customer )
    {
        this.customer = customer;
    }

    public String getCustomer()
    {
        return customer;
    }

    public void setCustomer( String arg )
    {
        customer = arg;
    }
}

使用Order类的代码可能像下面这样:

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

首先,新建一个Customer类表示“客户”概念。然后在这个类中建立一个final字段,用以保存一个字符串,这是Order类目前所使用的。将这个新字段命名为name,为这个字符串加上取值函数和构造函数.

public class Customer
{
    private final String name;

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

    public String getName()
    {
        return name;
    }
}
现在,将Order中的customer字段的类型修改为Customer,并修改所有引用该字段的函数,让它们恰当地改而引用Customer对象。其中取值函数和构造函数的修改都很简单。至于设值函数,让它创建一个customer实例。

public class Order
{
    private Customer customer;

    public Order( String customer )
    {
        this.customer = new Customer( customer );
    }

    public String getCustomer()
    {
        return customer.getName();
    }

    public void setCustomer( String arg )
    {
        customer = new Customer( arg );
    }
}
设值函数需要创建一个Customer实例,这是因为以前的字符串是个值对象,所以现在的Customer对象也应该是个值对象。这也就意味着每个对象都包含自己的一个Customer对象。注意这样一条规则:值对象应该是不可修改内容的--这便可避免一些讨厌的别名问题。

我们需要观察Order类中的customer字段的操作函数,并作出一些修改,使它更好地反映出修改后的新形势。对于取值函数,可以使用Rename Method改变名称,让它更清晰地表示,它所返回的是消费者名称,而不是个Customer对象。

public void setCustomerName( String arg )
{
   customer = new Customer( arg );
}
至于构造函数和设值函数,就不必修改其签名了,但参数名称得改:

public Order( String customerName )
{
   customer = new Customer( customerName );
}
public void setCustomerName( String customerName )
{
   customer = new Customer( customerName );
}
后继的其他重构也许会添加“接受现有Customer对象作为参数”的构造函数和设值函数。

转载于:https://my.oschina.net/u/134516/blog/131263

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值