[DesignPattern]策略模式Strategy pattern簡易版分享+範例
用最簡單的一句話來解釋策略模式的話,就是抽象類別裡面的抽象method改用interface。
詳細解釋:
在超大型專案的時候,如果有一百個不同的類別去繼承抽象類別的時候,抽象類別裡面的method的程式碼就很容易產生重複撰寫,那之後要改就會很麻煩
舉例來說:假設抽象類別長這樣:(直接拿微軟的範例)這是一個洗衣機的抽象類別
abstract class WashingMachine
{
public WashingMachine()
{
// Code to initialize the class goes here.
}
abstract public void Wash();
abstract public void Rinse(int loadSize);//沖洗
abstract public void Spin(int speed);//脫水
}
然後是繼承這個洗衣機抽象類別的實體類別:(也是直接拿微軟的copy過來)
class MyWashingMachine : WashingMachine
{
public MyWashingMachine()
{
// Initialization code goes here.
}
override public void Wash()
{
// Wash code goes here.
}
override public void Rinse(int loadSize)
{
// Rinse code goes here.
}
override public void Spin(int speed)
{
// Spin code goes here.
}
}
假設Panasonic要研發新的洗衣機,應該也是先用軟體寫模擬程式(假設就是用C#),不會直接車床開模子做實驗來研發新產品,應該沒人會這麼笨。
那用軟體在寫模擬程式的時候,新的產品類別是不是就要叫做MyWashingMachineNo1, MyWashingMachineNo2, ......MyWashingMachineNo100, 新研發出來的洗衣機越來越多, 這個抽象類別也就被繼承了上百次,這時候產生一個問題就是:
Spin()脫水的這個method,程式碼可能將會重複撰寫的超級多次!即使後來新的洗衣機越來越多高科技脫水方式來保護衣服,但是實際上真的脫水的技術可能就那麼2種(我猜的XD),對應到將來Panasonic變成百年企業之後的一百多種洗衣機(假設Panasonic一百年後還沒倒,我猜的 XD),那麼這一百種洗衣機的脫水的method將會很多重複、一模一樣的程式碼!萬一到時候要改脫水功能的程式碼,保證會改得很痛苦!
下面是兩個新產品,繼承上面的抽象類別,但是尚未採用策略模式,內容如下:MyWashingMachine1, MyWashingMachine2
class MyWashingMachine1 : WashingMachine
{
public MyWashingMachine1()
{
// Initialization code goes here.
}
override public void Wash()
{
// Wash code goes here.
}
override public void Rinse(int loadSize)
{
// Rinse code goes here.
}
override public void Spin(int speed)
{
// Spin code goes here.
Console.WriteLine("傳統洗衣機進行脫水,轉速為" + speed.ToString());
}
}
class MyWashingMachine2 : WashingMachine
{
public MyWashingMachine2()
{
// Initialization code goes here.
}
override public void Wash()
{
// Wash code goes here.
}
override public void Rinse(int loadSize)
{
// Rinse code goes here.
}
override public void Spin(int speed)
{
// Spin code goes here.
Console.WriteLine("滾筒洗衣機進行脫水,轉速為" + speed.ToString());
}
}
並且在Main裡面這樣呼叫就可以執行:
static void Main(string[] args)
{
WashingMachine m1 = new MyWashingMachine1();
WashingMachine m2 = new MyWashingMachine2();
m1.Spin(200);
m2.Spin(300);
Console.WriteLine("press any key to continue");
Console.ReadKey();
}
可以想像當新產品來到一百種、甚至兩百種的時候,下面這2行的程式碼,很有可能就要重複寫個一兩百次:畢竟脫水方法只有兩種,但是產品卻有上百種,重複的程式碼是必然的, 那之後如果要修改脫水的method程式碼,就得改一兩百次!
Console.WriteLine("傳統洗衣機進行脫水,轉速為" + speed.ToString());
Console.WriteLine("滾筒洗衣機進行脫水,轉速為" + speed.ToString());
這時候就是要用策略模式:先新增一個脫水用的interface, 並且實做出所有的脫水class:
interface ISpin
{
void SpinMethod(int speed);
}
class MySpin1 : ISpin
{
// Explicit interface member implementation:
void ISpin.SpinMethod(int speed)
{
// Method implementation.
Console.WriteLine("傳統洗衣機進行脫水,轉速為" + speed.ToString());
}
}
class MySpin2 : ISpin
{
// Explicit interface member implementation:
void ISpin.SpinMethod(int speed)
{
// Method implementation.
Console.WriteLine("滾筒洗衣機進行脫水,轉速為" + speed.ToString());
}
}
然後回頭去改抽象類別WashingMachine類別,把抽象方法Spin()改成用interface:
abstract class WashingMachine
{
public WashingMachine()
{
// Code to initialize the class goes here.
}
abstract public void Wash();
abstract public void Rinse(int loadSize);//沖洗
public void Spin(int speed)//脫水
{
sp.SpinMethod(speed);
}
protected ISpin sp;
}
至於兩個新產品MyWashingMachine1, MyWashingMachine2的脫水method就直接改用實做後的脫水class:
class MyWashingMachine1 : WashingMachine
{
public MyWashingMachine1()
{
// Initialization code goes here.
this.sp = new MySpin1();//改用實做的脫水class
}
override public void Wash()
{
// Wash code goes here.
}
override public void Rinse(int loadSize)
{
// Rinse code goes here.
}
//override public void Spin(int speed)
//{
// // Spin code goes here.
// Console.WriteLine("傳統洗衣機進行脫水,轉速為" + speed.ToString());
//}
}
class MyWashingMachine2 : WashingMachine
{
public MyWashingMachine2()
{
// Initialization code goes here.
this.sp = new MySpin2();//改用實做的脫水class
}
override public void Wash()
{
// Wash code goes here.
}
override public void Rinse(int loadSize)
{
// Rinse code goes here.
}
//override public void Spin(int speed)
//{
// // Spin code goes here.
// Console.WriteLine("滾筒洗衣機進行脫水,轉速為" + speed.ToString());
//}
}
最後的執行結果一模一樣,且脫水的部分的程式碼就不會一直重複,且以後要是需要修改脫水部分的程式碼,只要改實做interface的Class:MySpin1, MySpin2就好了,不用改一、兩百次,是不是很方便呢?
參考資料:
interface (C# Reference)
Abstract Classes
abstract (C# 參考)
[Design Pattern] 策略模式 Strategy Pattern