重构 - 12. 处理继承关系
🏷️ 《重构》
12.1 函数上移(Pull Up Method)
反向重构:函数下移(Push Down Method)
避免重复代码是很重要的。
重构前:
class Employee
{
}
class Salesman : Employee
{
public void Rest() { }
}
class Engineer : Employee
{
public void Rest() { }
}
重构后:
class Employee
{
public void Rest() { }
}
class Salesman : Employee
{
}
class Engineer : Employee
{
}
12.2 字段上移(Pull Up Field)
反向重构:字段下移(Push Down Field)
跟函数上移类似。
重构前:
class Employee
{
}
class Salesman : Employee
{
public string Name { get; set; }
}
class Engineer : Employee
{
public string Name { get; set; }
}
重构后:
class Employee
{
public string Name { get; set; }
}
class Salesman : Employee
{
}
class Engineer : Employee
{
}
12.3 构造函数本体上移(Pull Up Constructor Body)
重构前:
class Party
{
}
class Employee : Party
{
public Employee(int id, string name, decimal monthlyCost)
{
Id = id;
Name = name;
MonthlyCost = monthlyCost;
}
public int Id { get; set; }
public string Name { get; set; }
public decimal MonthlyCost { get; set; }
}
重构后:
class Party
{
public Party(string name)
{
Name = name;
}
public string Name { get; set; }
}
class Employee : Party
{
public Employee(int id, string name, decimal monthlyCost) : base(name)
{
Id = id;
MonthlyCost = monthlyCost;
}
public int Id { get; set; }
public decimal MonthlyCost { get; set; }
}
12.4 函数下移(Push Down Method)
反向重构:函数上移(Pull Up Method)
重构前:
class Employee
{
private int _quota;
public int Quota()
{
return _quota;
}
}
class Engineer : Employee
{
}
class Salesman : Employee
{
}
重构后:
class Employee
{
}
class Engineer : Employee
{
}
class Salesman : Employee
{
private int _quota;
public int Quota()
{
return _quota;
}
}
12.5 字段下移(Push Down Field)
反向重构:字段上移(Pull Up Field)
重构前:
class Employee
{
public int Quota { get; set; }
}
class Engineer : Employee
{
}
class Salesman : Employee
{
}
重构后:
class Employee
{
}
class Engineer : Employee
{
}
class Salesman : Employee
{
public int Quota { get; set; }
}
12.6 以子类取代类型码(Replace Type Code with Subclasses)
包含旧重构:以 State/Strategy 取代类型码(Replace Type Code with State/Strategy)
包含旧重构:提炼子类(Extract Subclass)
反向重构:移除子类(Remove Subclass)
重构前:
Employee CreateEmployee(string name, string type)
{
return new Employee(name, type);
}
重构后:
Employee CreateEmployee(string name, string type)
{
switch (type)
{
case "engineer":
return new Engineer(name);
case "saleman":
return new Saleman(name);
case "manager":
return new Manager(name);
default:
return new Employee(name);
}
}
12.7 移除子类(Remove Subclass)
曾用名:以字段取代子类(Replace Subclass with Fields)
反向重构:以子类取代类型码(Replace Type Code with Subclasses)
子类存在着就有成本,所以如果子类的用处太少,就不值得存在了。
重构前:
class Person
{
public virtual string GenderCode => "X";
}
class Male : Person
{
public override string GenderCode => "M";
}
class Female : Person
{
public override string GenderCode => "F";
}
重构后:
class Person
{
public string GenderCode { get; set; }
}
12.8 提炼超类(Extract Superclass)
如果看见两个在做相似的事,可以利用基本的继承机制把他们的相似之处提炼到超类。
重构前:
class Department
{
public string Name { get; set; }
public int HeadCount { get; set; }
public decimal MonthlyCost { get; set; }
public decimal TotalAnnualCost()
{
return decimal.Multiply(decimal.Multiply(MonthlyCost, new decimal(12)), new decimal(1.2));
}
}
class Employee
{
public string Name { get; set; }
public int Id { get; set; }
public decimal MonthlyCost { get; set; }
public decimal AnnualCost()
{
return decimal.Multiply(MonthlyCost, new decimal(14));
}
}
重构后:
class Party
{
public string Name { get; set; }
public decimal MonthlyCost { get; set; }
public virtual decimal AnnualCost()
{
return decimal.Multiply(MonthlyCost, new decimal(12));
}
}
class Department : Party
{
public int HeadCount { get; set; }
public override decimal AnnualCost()
{
return decimal.Multiply(base.AnnualCost(), new decimal(1.2));
}
}
class Employee : Party
{
public int Id { get; set; }
public override decimal AnnualCost()
{
return decimal.Add(base.AnnualCost(), decimal.Multiply(MonthlyCost, new decimal(2)));
}
}
12.9 折叠继承体系(Collapse Hierarchy)
若一个类与其超类已经没多大差别,则其不值得再作为独立的类存在。
重构前:
class Employee { }
class Saleman : Employee { }
重构后:
class Employee { }
12.10 以委托取代子类(Replace Subclass with Delegate)
继承是个很强大的机制,但也有其短板:大多数语言只允许但继承;继承给类之间引入了非常紧密的联系。
使用委托可以解决上述问题。
“对象组合优于类继承”(“组合”跟“委托”是同一回事)。
重构前:
class Order
{
private Warehouse _warehouse;
public virtual int DaysToShip
{
get
{
return _warehouse.DaysToShip;
}
}
}
class PriorityOrder : Order
{
private PriorityPlan _priorityPlan;
public override int DaysToShip
{
get
{
return _priorityPlan.DaysToShip;
}
}
}
重构后:
class Order
{
private Warehouse _warehouse;
private PriorityPlanDelegate _piorityPlanDelegate;
public int DaysToShip
{
get
{
return _piorityPlanDelegate != null
? _piorityPlanDelegate.DaysToShip
: _warehouse.DaysToShip;
}
}
}
class PriorityPlanDelegate
{
private PriorityPlan _priorityPlan;
public int DaysToShip
{
get
{
return _priorityPlan.DaysToShip;
}
}
}
12.11 以委托取代超类(Replace Superclass with Delegate)
曾用名:以委托取代继承(Replace Inheritance with Delegate)
如果超类的一些函数对于子类并不适用,就说明不应该通过继承来获得超类的功能。
合理的继承关系还有一个重要特征:子类的所有实例都应该是超类的实例,通过超类的接口来使用子类的实例应该完全不出问题。
首先(尽量)使用继承,如果发现继承有问题,再使用 以委托取代超类 。
重构前:
class List
{
// ...
}
class Stack : List
{
// ...
}
重构后:
class List
{
// ...
}
class Stack
{
List _stoarge;
public Stack()
{
_stoarge = new List();
}
// ...
}
附 1. 引用
- 《重构:改善既有代码的设计》 -- 马丁·福勒(Martin Fowler)