(227)Replace_Type_Code_With_State_Strategy
State/Strategy取代型別代碼
class之中有一個數值型別的代碼,但她會影響行為,但你無法使用Subclassing 來處理
他跟(223)Replace_Type_Code_with_Subclasses非常像
範例
非常常見的作法,而且往往越加越多,非常痛苦
public class Employee
{
public const int ENGINEER = 0;
public const int SALESMAN = 1;
public const int MANAGER = 2;
public int Type { get; set; }
public int Salary { get; set; }
public int Commission { get; set; }
public int Bouns { get; set; }
public Employee(int type)
{
Type = type;
}
// 根據不同身分取得不同運算邏輯
public int GetPayAmount()
{
switch (Type)
{
case ENGINEER:
return Salary;
case SALESMAN:
return Salary + Commission;
case MANAGER:
return Salary + Bouns;
}
throw new Exception("Unknow type");
}
}
先建立虛擬類別、並且每個邏輯都繼承虛擬類別
並建立一個factory method 來讓client端切換執行不同的策略邏輯
abstract class EmployeeType
{
public abstract int Type { get; }
// 使用factory method 來切換要建立的物件
public static EmployeeType Create(int type)
{
switch (type)
{
case Employee.ENGINEER:
return new Engineer();
case Employee.SALESMAN:
return new Salesman();
case Employee.MANAGER:
return new Manager();
}
throw new Exception("Unknow type");
}
}
class Engineer : EmployeeType
{
public override int Type
{
get {return Employee.ENGINEER;}
}
}
class Salesman : EmployeeType
{
public override int Type
{
get { return Employee.SALESMAN; }
}
}
class Manager : EmployeeType
{
public override int Type
{
get { return Employee.MANAGER; }
}
}
開始把不需要存在於Client 端的程式碼都搬走了
abstract class EmployeeType
{
// 從Client搬到抽象類別
public const int ENGINEER = 0;
public const int SALESMAN = 1;
public const int MANAGER = 2;
public abstract int Type { get; }
// 使用factory method 來切換要建立的物件
public static EmployeeType Create(int type)
{
switch (type)
{
case ENGINEER: // 直接引用
return new Engineer();
case SALESMAN: // 直接引用
return new Salesman();
case MANAGER: // 直接引用
return new Manager();
}
throw new Exception("Unknow type");
}
....
class Engineer : EmployeeType
{
public override int Type
{
// get {return Employee.ENGINEER;}
get {return ENGINEER;} // 因為繼承EmployeeType 所以也直接引用即可
}
}
開始改造Client程式碼
public class Employee
{
// 步驟一:建立虛擬類別提供client 選擇策略
private EmployeeType Type {get;set;};
// 重構建構式,由Client決定之後的執行策略
public Employee(EmployeeType type){
Type = type;
}
// 這邊有怪怪的味道,已經拆分SubClass,把邏輯回歸到他們原本身邊吧
public int GetPayAmount()
{
switch (Type)
{
case EmployeeType.ENGINEER:
return Salary;
case EmployeeType.SALESMAN:
return Salary + Commission;
case EmployeeType.MANAGER:
return Salary + Bouns;
}
throw new Exception("Unknow type");
}
...
最後一步驟:把所有商業邏輯都寫回給每個物件吧!!!
abstract class EmployeeType
{
public const int ENGINEER = 0;
public const int SALESMAN = 1;
public const int MANAGER = 2;
public abstract int Type { get; }
// 讓每個員工自己實現自己的方法
public abstract int GetPayAmount(Employee employee);
...
class Engineer : EmployeeType
{
public override int Type
{
get {return ENGINEER;}
}
// 員工靠業績
public override int GetPayAmount(Employee employee)
{
return employee.Salary;
}
}
class Salesman : EmployeeType
{
public override int Type
{
get { return SALESMAN; }
}
// 銷售員就是賺抽成
public override int GetPayAmount(Employee employee)
{
return employee.Salary + employee.Commission;
}
}
class Manager : EmployeeType
{
public override int Type
{
get { return MANAGER; }
}
// 老闆靠紅利
public override int GetPayAmount(Employee employee)
{
return employee.Salary + employee.Bouns;
}
}
後繼
這個方法跟223的差異除了把邏輯抽到各自SubClass以外
最大的差異在於,223把決定權在Class本身,227把決定權交給Client,其實這就是策略模式得一個特色
223跟227都是很棒的方法,而且也是最容易學習的設計模式,策略模式,簡單工廠模式
這兩個學會其實已經可以運用在非常多地方,邏輯也可以整理的非常清楚
請各位多看幾遍