改善代码设计 —— 优化物件之间的特性(Moving Features Between Objects)
1. Move Method (函数搬家)
解释:
如果 ClassA 的某个函数对 ClassB 有过多的依赖, 可以考虑将这个函数搬到 ClassB 中, 在 ClassA 的这个函数中直接调用 ClassB中这个函数的返回值.这样做的好处是减少物件与物件之间的耦合度, 很多情况下这样做更利于进一步的重构.
冲动前:
00 class EmployeeSalary01 {
02 private double baseSalary = 15000.0;
03
04 public double Salary(Employee employee)
05 {
06 return baseSalary + 10000 / employee.Level;
07 }
08 // other method with baseSalary
09 }
10 class Employee
11 {
12 public int Level { get; set; }
13 }
冲动后:
00 class EmployeeSalary01 {
02 private double baseSalary = 15000.0;
03
04 public double Salary(Employee employee)
05 {
06 return employee.Salary(baseSalary);
07 }
08 // other method with baseSalary
09 }
10 class Employee
11 {
12 public int Level { get; set; }
13 public double Salary(double baseSalary)
14 {
15 return baseSalary + 10000 / Level;
16 }
17 }
2. Move Field (值域搬家)
解释:
有一天发现公司原来计算员工工资的方法不合适了, 比如不是所有的员工起薪 (baseSalary) 都是一万五, 我想把 baseSalary 搬到 Employee 这个物件中作为员工的一个属性.这样做可使程序扩展性变得更好, 最明显的是我可以设置不同员工的起薪了.
冲动前:
00 class EmployeeSalary01 {
02 private double baseSalary = 15000.0;
03
04 public double Salary()
05 {
06 double salary = baseSalary;
07 //do some compution with salary
08 return salary;
09 }
10 }
冲动后:
00 class EmployeeSalary01 {
02 public double Salary(Employee employee)
03 {
04 double salary = employee.BaseSalary;
05 //do some compution with salary
06 return salary;
07 }
08 }
09 class Employee
10 {
11 public double BaseSalary { get; set; }
12 }
3. Extract Class (提炼类)
解释:
当某个物件做的事情过多, 这样的物件往往含有大量的字段, 属性和方法. 应该由两个或更多个物件来分担这些责任, 这时需要使用 Extract Class.冲动前:
00 class Employee01 {
02 public double BaseSalary { get; set; }
03 public double Level { get; set; }
04
05 public double Salary()
06 {
07 double salary = BaseSalary;
08 //do some complex compution with salary
09 return salary;
10 }
11 }
冲动后:
00 class EmployeeSalary01 {
02 public double Salary(Employee employee)
03 {
04 double salary = employee.BaseSalary;
05 //do some complex compution with salary
06 return salary;
07 }
08 }
09 class Employee
10 {
11 public double BaseSalary { get; set; }
12 public double Level { get; set; }
13
14 public double Salary()
15 {
16 EmployeeSalary salary = new EmployeeSalary();
17 return salary.Salary(this);
18 }
19 }
4. Inline Class (将类内联)
解释:
Inline Class 和 Extract Class 正好相反. 当一个物件没有做它应该做的事情, 还专门使用了另一个物件来协助它完成这个职责, 这时可以考虑使用 Inline Class.如上面所示的例子, 如果我觉得 Employee 这个物件本身就应该实现 Salary 的计算工作, 而不是专门写一个 Salary 的计算物件来帮助它计算, 可以使用 Inline Class 将 Salary 内联到 Employee 中去, 也就是"冲动后"的代码重构成"冲动前"代码的样子.
5. Hide Delegate (隐藏委托关系)
解释:
试想这么一个情况: 有一个 Employee 类, 这个类中含有一个部门 (Department) 属性, 并且 Department 是一种类. 如果我想知道某职工所在部门的经理人是谁的时候, 我需要通过 xxEmployee.Department.Manger 来访问. 但这样做有个缺点是对于其它代码, Department 是 public 的, 其它代码能够访问到 Department 里的其它特性. 可以在 Employee 类中写一个 GetManger() 方法进行封装, 在调用的时候只需要xxEmployee.GetManger() 就行了.冲动前:
0 class Department1 {
2 public string Manger { get; set; }
3 }
4 class Employee
5 {
6 public Department Department { get; set; }
7 }
冲动后:
00 class Department01 {
02 public string Manger { get; set; }
03 }
04 class Employee
05 {
06 private Department Department;
07
08 public string GetManger()
09 {
10 return Department.Manger;
11 }
12 }
6. Remove Middle Man (干掉中间人)
解释:
这一条与上一条 Hide Delegate 是相反的. 当我们要访问 Department 的其它很多特性时, 我们用 Hide Delegate 写了一条条简单的委托访问函数, 当这些函数多到几乎访问遍了 Department 里的内容, 可以考虑使用 Remove Middle Man 方法将这些访问函数干掉.如上面的例子, 就是将"冲动后"的代码重构成"冲动前"代码
补充:综合编程 , 其他综合 ,