C# 重构
程序员文章站
2023-08-21 23:57:55
一、Pull Up Field 提取字段 多个类中有相同的字段,可以提取到父类中。 重构前: public class Engineer { public string name { get; set; } } public class Salesman { public string name { ......
一、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(); } }
代码结构清晰简洁了不少。