Skip to content

重构 - 9. 重新组织数据

🏷️ 《重构》

9.1 拆分变量(Split Variable)

曾用名移除对参数的赋值(Remove Assignments to Parameters)
曾用名分解临时变量(Split Temp)

如果变量承担多个职责,它就应该被替换(分解)为多个变量,每个变量只承担一个责任。

重构前

csharp
var temp = 2 * (height + width);
Console.WriteLine(temp);
temp = height * width;
Console.WriteLine(temp);

重构后

csharp
var perimeter = 2 * (height + width);
Console.WriteLine(perimeter);
var area = height * width;
Console.WriteLine(area);

9.2 字段改名(Rename Field)

命名很重要,对于程序中广泛使用的记录结构,其中字段的命名格外重要。

重构前

csharp
public class Organization
{
    public string Name { get; set; }
}

重构后

csharp
public class Organization
{
    public string Title { get; set; }
}

9.3 以查询取代派生变量(Replace Derived Variable with Query)

可变数据是软件中最大的错误源头之一。

很多时候,完全去掉可变数据并不现实,但还是强烈建议:尽量把可变数据的作用域限制在最小范围。

重构前

csharp
public double DiscountTotal { get; private set; }

private double _discount;
public double Discount
{
    get
    {
        return _discount;
    }
    set
    {
        var old = _discount;
        _discount = value;
        DiscountTotal += old - value;
    }
}

重构后

csharp
public double DiscountTotal
{
    get
    {
        return _baseTotal - Discount;
    }
}

public double Discount { get; set; }

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

反向重构将值对象改为引用对象(Change Value to Reference)

在把一个对象(或数据结构)嵌入一个对象时,位于内部的这个对象可以被视为引用对象,也可以被视为值对象。两者的差异在于如何更新内部对象的属性。

若视为引用对象,更新时保留原对象不动,更新内部对象的属性;
若视为值对象,替换整个内部对象。

值对象在分布式系统和并发系统中尤为有用。

重构前

csharp
class Product
{
    public Money Price { get; set; }

    public void ApplyDiscount(double arg)
    {
        Price.Amount -= arg;
    }
}

class Money
{
    public double Amount { get; set; }
    public string Currency { get; set; }
}

重构后

csharp
class Product
{
    public Money Price { get; set; }

    public void ApplyDiscount(double arg)
    {
        Price = new Money(Price.Amount - arg, Price.Currency);
    }
}

struct Money
{
    public Money(double amount, string currency) : this()
    {
        Amount = amount;
        Currency = currency;
    }

    public double Amount { get; set; }

    public string Currency { get; set; }
}

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

反向重构将引用对象改为值对象(Change Reference to Value)

把值对象改为引用对象会带来一个结果:对于一个客观实体,只有一个代表它的对象。

这通常意味着需要某种形式的仓库,在仓库中可以找到所有这些实体对象。只为每个实体创建一次对象,以后始终从仓库获取该对象。

重构前

csharp
var customer = new Customer(customerData);

重构后

csharp
var customer = customerRepository.Find(customerData.Id);

附 1. 引用

  1. 《重构:改善既有代码的设计》 -- 马丁·福勒(Martin Fowler