一、Pull Up Field 提取字段
多個類中有相同的字段,可以提取到父類中。
重構前:
public class Engineer { public string name { get; set; } } public class Salesman { public string name { get; set; } }
重構后:
public class Employee { public string name { get; set; } } public class Engineer:Employee { } public class Salesman : Employee { }
二、Pull_Up_Method 提取方法
多個類中有相同或相似的方法時,可以提取到父類
重構前:
class Preferred_Customer { void CreateBill(DateTime date) { double chargeAmount = ChargeFor(); AddBill(date, chargeAmount); } void AddBill(DateTime date, double amount) { } public double ChargeFor() { return 1; } }
class Regular_Customer { void CreateBill(DateTime date) { double chargeAmount = ChargeFor(); AddBill(date, chargeAmount); } void AddBill(DateTime date, double amount) { } double ChargeFor() { return 2; } }
重構后:
abstract class Customer { void CreateBill(DateTime date) { double chargeAmount = ChargeFor(); AddBill(date, chargeAmount); } void AddBill(DateTime date, double amount) { } public abstract double ChargeFor(); } class Preferred_Customer: Customer { public override double ChargeFor() { return 1; } } class Regular_Customer:Customer { public override double ChargeFor() { return 2; } }
子類中的ChargeFor方法實現不同,父類中的ChargeFor為抽象方法。子類通過重寫實現。
三、Pull_Up_Constructor_Body 提取構造函數
多個類的構造函數代碼類似,可以提取到父類中
重構前:
class Manager { string _name; int _id; public Manager(string name,int id) { _name = name; _id = id; Init(); } void Init() { object obj1 = new object(); } } class Manager1 { string _name; int _id; int _grade; public Manager1(string name,int id,int grade) { _name = name; _id = id; _grade = grade; Init(); } void Init() { object obj2 = new object(); _grade = 2; } }
重構后:
abstract class Employee { protected string _name; protected int _id; public Employee(string name, int id) { _name = name; _id = id; Init(); } protected abstract void Init(); } class Manager:Employee { public Manager(string name, int id):base(name,id) { } protected override void Init() { object obj1 = new object(); } } class Manager1 : Employee { int _grade; public Manager1(string name, int id, int grade) : base(name, id) { _grade = grade; } protected override void Init() { object obj2 = new object(); _grade = 2; } }
子類中的構造函數中調用的Init方法實現不同,在父類中做成抽象方法。
四、Extract_Subclass 提煉子類
當一個類中出現根據類型調用不同的方法,或者一個類中有多個職責的時候,我們可以考慮提煉子類
重構前:

class PrintClass { string _path; string _jsonData; string _sourceBillFlag; List<int> _sourceBillId; int _lableType; public PrintClass(string path, string jsonData, string sourceBillFlag, List<int> sourceBillId, int lableType) { _path = path; _jsonData = jsonData; _sourceBillFlag = sourceBillFlag; _sourceBillId = sourceBillId; _lableType = lableType; } public void Print() { switch(_lableType) { case 1: PrintBartender(_path,_jsonData); break; case 2: PrintCodeSoft(_path, _jsonData); break; case 3: PrintCloud(_sourceBillFlag,_sourceBillId); break; } } void PrintBartender(string path, string jsonData) { } void PrintCodeSoft(string path, string jsonDat) { } void PrintCloud(string sourceBillFlag, List<int> sourceBillId) { } }
比如這個打印類中,根據類型,調不同的打印方法。
重構后:

namespace Extract_Subclass { class PrintBase { string _path; string _jsonData; public PrintBase(string path, string jsonData) { _path = path; _jsonData = jsonData; } public virtual void Print( ) { } } class BartenderPrint : PrintBase { public BartenderPrint(string path, string jsonData):base(path,jsonData) { } public override void Print() { //call bartender api } } class CodeSoftPrint : PrintBase { public CodeSoftPrint(string path, string jsonData) : base(path, jsonData) { } public override void Print() { //call CodeSoft api } } class CloudPrint:PrintBase { string _sourceBillFlag; List<int> _sourceBillId; public CloudPrint(string sourceBillFlag, List<int> sourceBillId) :base("","") { _sourceBillFlag = sourceBillFlag; _sourceBillId = sourceBillId; } public override void Print() { //Cloud print } } }
五、Extract Superclass 提煉父類
幾個類的字段,方法,構造函數等都有部分相同之處,可以提取到父類中。
重構前:

class Department { string _name; public Department(string name) { _name = name; } public string GetName() { return _name; } public int GetTotalaAnnualCost() { int result = 0; GetStaff().ForEach(p=> { result += p.GetAnnualCost(); }); return result; } private List<Employee> GetStaff() { return default(List<Employee>); } }

class Employee { string _name; string _id; int _annualCost; public Employee(string name,string id,int annualCost) { _name = name; _id = id; _annualCost = annualCost; } public string GetName() { return _name; } public int GetAnnualCost() { return _annualCost; } }
Department類中有個GetTotalaAnnualCost方法,獲取總費用,Employee中有個GetAnnualCost方法,獲取費用。我們可以提取到父類中,修改成相同的名稱。
重構后:

namespace RefactoringDome.Extract_Superclass { abstract class Part { string _name; public Part(string name) { _name = name; } public string GetName() { return _name; } public abstract int GetAnnualCost(); } } namespace RefactoringDome.Extract_Superclass.Dome { class Employee : Part { string _id; int _annualCost; public Employee(string name, string id, int annualCost) : base(name) { _id = id; _annualCost = annualCost; } public override int GetAnnualCost() { return _annualCost; } } class Department:Part { public Department(string name):base(name) { } public override int GetAnnualCost() { int result = 0; GetStaff().ForEach(p => { result += p.GetAnnualCost(); }); return result; } private List<Employee> GetStaff() { return default(List<Employee>); } } }
六、Form Template Method 模板方法
兩個方法中的流程大致相同,我們可以提煉成模板方法。
重構前:
class Customer { public string Statement() { List<string> details = GetDetails(); string result = "Rental Record for" + GetName() + "\n"; details.ForEach(p=> { result += "Details is" + p + "\n"; }); result += "Total Charge:"+GetTotalCharge(); return result; } public string HtmlStatement() { List<string> details = GetDetails(); string result = "<h1>Rental Record for<EM>" + GetName() + "</EM></h1>\n"; details.ForEach(p => { result += "<p>Details is<EM>" + p + "</EM></p>\n"; }); result += "<p>Total Charge:<EM>" + GetTotalCharge()+"</EM></p>"; return result; } public List<string> GetDetails() { return default(List<string>); } public string GetName() { return ""; } public decimal GetTotalCharge() { return 0; } }
Customer類中有兩個打印小票的方法,一個是winform調的,一個是Html調的。方法中代碼結構一樣,只是部分顯示字符串不同。
這種很符合提取成模板函數。
重構后:
namespace RefactoringDome.Form_Template_Method { abstract class Statement { public string Value(Customer customer) { List<string> details = customer.GetDetails(); string result = HeaderString(customer); details.ForEach(p => { result += DetailString(p); }); result += FooterString(customer); return result; } protected abstract string HeaderString(Customer customer); protected abstract string DetailString(string detailInfo); protected abstract string FooterString(Customer customer); } class TextStatement : Statement { protected override string HeaderString(Customer customer) { return "Rental Record for" + customer.GetName() + "\n"; } protected override string DetailString(string detailInfo) { return "Details is" + detailInfo + "\n"; } protected override string FooterString(Customer customer) { return "Total Charge:" + customer.GetTotalCharge(); } } class HtmlStatement : Statement { protected override string HeaderString(Customer customer) { return "<h1>Rental Record for<EM>" + customer.GetName() + "</EM></h1>\n"; } protected override string DetailString(string detailInfo) { return "<p>Details is<EM>" + detailInfo + "</EM></p>\n"; } protected override string FooterString(Customer customer) { return "<p>Total Charge:<EM>" + customer.GetTotalCharge() + "</EM></p>"; } } }
把不同的部分,用抽象函數代替。子類中去重寫實現具體實現。
七、Replace Inheritance with Delegation 繼承替換為委托
子類只用了父類一小部分方法。這種情況可以考慮將繼承替換為委托。
重構前:
class List { public object FirstElement() { return default(object); } public void Insert(object element) { } public void Remove(object element) { } public int FindIndex(object obj) { return 0; } public void Sort() { } } class Queue: List { public void Push(object element) { Insert(element); } public void Pop() { object obj = FirstElement(); Remove(obj); } }
Queue類繼承了List類,使用了List類的Insert、Remove、FirstElement方法。但是List類中還有Sort、FindIndex方法在子類中沒有用到。這樣父類傳達給調用端的信息並不是你想要體現的。這種情況我們應該使用List的委托。
重構后:
class Queue { List _list = new List(); public void Push(object element) { _list.Insert(element); } public void Pop() { object obj = _list.FirstElement(); _list.Remove(obj); } }
八、Replace Delegation with inheritance 委托替換為繼承
一個類中,引用了另一個類的實例,但是當前類中的方法,委托類里都有,這種情況應該用繼承替換委托。
重構前:
class Employee { Person _person = new Person(); public string GetName() { return _person.GetName(); } public void SetName(string name) { _person.SetName(name); } public new string ToString() { return "my name is:"+_person.GetLastName(); } } class Person { string _name; public string GetName() { return _name; } public void SetName(string name) { _name = name; } public string GetLastName() { return _name.Substring(1); } }
重構后:
class Employee:Person { public new string ToString() { return "my name is:" + GetLastName(); } }
代碼結構清晰簡潔了不少。