今天下班回家,吃完晚飯后在網上閑逛,看了看電視劇《男人幫》的經典台詞,感覺很經典,雖然這個電視劇我早已經在上個月就看完了,但是看了看里面的經典開場白和台詞,還是不由自主的伸出大拇指,贊啊!
列舉部分台詞如下:
(1)自從我們睜開眼睛看這個世界的第一天起, 我們看到的就只有兩種人,男人和女人。 他們分屬於兩大不同的陣營,為了徹底收服對方,大家互相往死里掐。
(2)根據一個遙遠的傳說,說有一種東西叫愛情,可以徹底終結這場戰爭。 於是大家紛紛的趕緊去尋找,趕緊去幻想, 找到頭破血流才發現,原來這個感情也是另一些人在書房里炮制出來的。 於是大家更加絕望,更加痛苦,更加互相的往死里掐。
1、場景案例
尤其是上面這幾句,讓我想起了我一同事(這里用“某某哥”代替)和他女朋友的故事(這里用“某某嫂”代替),一次活動中,某某哥認識了某某嫂,那個一見鍾情呀,簡直是看不見某某嫂就吃不下飯、寫不下代碼呀,在追求中也沒少費工夫。比如:送小禮物,請客吃飯,搞浪漫等等,我們就把這幾個階段分別用代碼模擬一下把!
①第一階段贈送小禮物代碼如下:
public static void SendGift()
{
Console.WriteLine( " 送給女方精美小禮物! ");
}
static void Main( string[] args)
{
// 第一階段
SendGift();
}
② 此時、通過送精美小禮物女方已經願意與男方接觸,這時就可以一起吃飯了,代碼如下:
public static void SendGift()
{
Console.WriteLine( " 送給女方精美小禮物! ");
}
// 添加 第二階段 請客吃飯
public static void Eat()
{
Console.WriteLine( " 請女生吃牛排! ");
}
static void Main( string[] args)
{
// 第一階段
// SendGift(); // 此時第一階段已經不需要了所以注銷掉進入第二階段
// 第二階段
Eat();
}
③ 經過之前階段的接觸,兩人已經在一起了,在一起就免不了在熱戀中經歷浪漫情節,第三階段:制造浪漫、代碼如下:
public static void SendGift()
{
Console.WriteLine( " 送給女方精美小禮物! ");
}
// 添加 第二階段 請客吃飯
public static void Eat()
{
Console.WriteLine( " 請女生吃牛排! ");
}
// 添加 第三階段 浪漫:燭光晚餐等待女友
public static void Romantic()
{
Console.WriteLine( " 精心制作了紅酒、晚餐與蠟燭,等待女友回家! ");
}
static void Main( string[] args)
{
// 第一階段
// SendGift(); // 此時第一階段已經不需要了所以注銷掉進入第二階段
// 第二階段
// Eat(); // 此時第二階段也已經經過,所以注銷掉、進入第三階段
// 第三階段
Romantic();
}
看了某某哥追某某嫂的經過后,我們會發現,每當進入一個新階段的時候,我們就需要去修改我們的代碼,加入新的追女策略,並且將main函數中的調用修改成進入新的階段,那么我們怎么樣能避免,在進入新階段后不去修改調用的代碼呢?當然這個肯定難不倒你,代碼如下:
public static void SendGift()
{
Console.WriteLine( " 送給女方精美小禮物! ");
}
// 添加 第二階段 請客吃飯
public static void Eat()
{
Console.WriteLine( " 請女生吃牛排! ");
}
// 添加 第三階段 浪漫:燭光晚餐等待女友
public static void Romantic()
{
Console.WriteLine( " 精心制作了紅酒、晚餐與蠟燭,等待女友回家! ");
}
static void Main( string[] args)
{
Console.Write( " 現在是第幾階段?: ");
string level = Console.ReadLine(); // 代表當前是哪個階段
switch (level)
{
case " one ": // 第一階段
SendGift();
break;
case " two ": // 第二階段
Eat();
break;
case " three ": // 第三階段
Romantic();
break;
default:
Console.WriteLine( " 沒這個打算湊什么熱鬧? ");
break;
}
}
這樣我們就解決了在兩人進入新的階段后,無需修改main方法中的代碼!輸出結果如下:
那么如果這時兩人已經到了談婚論嫁的時候,該怎么辦呢?也就是要在新加入一個階段叫做結婚呢?
2、引入策略模式
普通的辦法還是要去新增方法,在修改調用代碼!那我們有沒有辦法呢?別着急,先看看策略模式、定義如下:“它定義了算法家族,分別封裝起來,讓他們之間可以互相替換,次模式讓算法的變化,不會影響到使用算法的客戶”。
策略模式類圖如下:
那么使用策略模式改裝,我們上面場景的類圖如下:
模擬出了類型那么我們寫代碼當然也就不難啦。
① 首先呢,我們需要抽象出來追女孩策略,這個策略里面有一個公共的接口就是去做(也就是行動的意思),例如:送禮物、吃飯、浪漫,都是需要人去做去行動的。
public abstract class PursueaGirlStrategy
{
// 追女孩策略中都有一個統一的接口,就是行動。
public abstract void Justdoit();
}
② 接下來,就是追女孩策略中,各個環節策略的實現啦,代碼如下:
public class SendGiftStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 送給女方精美小禮物! ");
}
}
// 第二階段 請客吃飯
public class EatStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 請女生吃牛排! ");
}
}
// 第三階段 浪漫:燭光晚餐等待女友
public class RomanticStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 精心制作了紅酒、晚餐與蠟燭,等待女友回家! ");
}
}
③ 最后就是,承載策略實例,提供統一調用的策略上下文啦。代碼如下:
public class PursueaGirlContext
{
PursueaGirlStrategy staregy;
public PursueaGirlContext(PursueaGirlStrategy strategy)
{
this.staregy = strategy;
}
// 調用策略的公共接口方法
public void ContextJustdoit()
{
if ( this.staregy != null)
{
this.staregy.Justdoit();
}
}
}
main方法將來調用如下:
{
// 定義追女孩策略上下文對象
PursueaGirlContext context = null;
Console.Write( " 現在是第幾階段?: ");
string level = Console.ReadLine(); // 代表當前是哪個階段
switch (level)
{
case " one ": // 第一階段
context = new PursueaGirlContext( new SendGiftStrategy());
break;
case " two ": // 第二階段
context = new PursueaGirlContext( new EatStrategy());
break;
case " three ": // 第三階段
context = new PursueaGirlContext( new RomanticStrategy());
break;
default:
Console.WriteLine( " 沒這個打算湊什么熱鬧? ");
break;
}
// 統一的策略調用模式
context.ContextJustdoit();
}
好的,策略模式與我們的場景先告一段落把。這個時候可能有的人就會問啦,策略模式跟工廠模式很想啊,都是提供一個統一的接口,有不同的實例去實例化。那么我們來看看策略模式與工廠模式的區別吧。
3、策略模式與工廠模式的區別
概念上理解:
① 策略模式:是告訴上下文,我需要去做什么,至於使用怎么實現,需要上下文去使用當前對應的策略去實現。例如:項目經理(客戶端)說:“我要實現即時消息功能”,那么我們程序員(上下文)就需要去尋找對應的策略(開發即時消息模塊的策略)去實現。
②工廠模式:是告訴工廠,此時我需要什么部件你去給我制造,例如:開發及時消息模塊,我需要JS的彈出框,我就會告訴UI組(工廠),給我做一個JS彈出框,要求模仿EXT的。
4、策略與工廠談戀愛
那么了解了他們之間的區別后,我們再來看上面策略模式實現的一個問題,例如:需要加入結婚策略時,還是需要增加結婚策略類,並且修改客戶端(MAIN方法)中的調用代碼。那么我們把提供使用策略的代碼放到工廠中呢?這樣我們以后就只需要增加新策略修改工廠就行啦!客戶端就不用修改了。
①工廠代碼代碼如下:
public class FactoryStrategy
{
// 根據客戶端參數創建策略
public static PursueaGirlContext GetStrategy( string level)
{
// 定義追女孩策略上下文對象
PursueaGirlContext context = null;
switch (level)
{
case " one ": // 第一階段 禮物
context = new PursueaGirlContext( new SendGiftStrategy());
break;
case " two ": // 第二階段 吃飯
context = new PursueaGirlContext( new EatStrategy());
break;
case " three ": // 第三階段 浪漫
context = new PursueaGirlContext( new RomanticStrategy());
break;
case " four ": // 第四階段 結婚
context = new PursueaGirlContext( new MarriedStrategy());
break;
default:
context = null;
break;
}
return context;
}
}
② 有了工廠后的客戶端(main)代碼如下:
{
Console.Write( " 現在是第幾階段?: ");
string level = Console.ReadLine(); // 代表當前是哪個階段
// 定義追女孩策略上下文對象
PursueaGirlContext context = FactoryStrategy.GetStrategy(level);
// 統一的策略調用模式
context.ContextJustdoit();
}
③ 完整代碼如下:
public abstract class PursueaGirlStrategy
{
// 追女孩策略中都有一個統一的接口,就是行動。
public abstract void Justdoit();
}
// 第一階段 送小禮物
public class SendGiftStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 送給女方精美小禮物! ");
}
}
// 第二階段 請客吃飯
public class EatStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 請女生吃牛排! ");
}
}
// 第三階段 浪漫:燭光晚餐等待女友
public class RomanticStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 精心制作了紅酒、晚餐與蠟燭,等待女友回家! ");
}
}
// 添加第四階段 結婚
public class MarriedStrategy : PursueaGirlStrategy
{
public override void Justdoit()
{
Console.WriteLine( " 兩人民政局領證! ");
}
}
// 提供策略的工廠
public class FactoryStrategy
{
// 根據客戶端參數創建策略
public static PursueaGirlContext GetStrategy( string level)
{
// 定義追女孩策略上下文對象
PursueaGirlContext context = null;
switch (level)
{
case " one ": // 第一階段 禮物
context = new PursueaGirlContext( new SendGiftStrategy());
break;
case " two ": // 第二階段 吃飯
context = new PursueaGirlContext( new EatStrategy());
break;
case " three ": // 第三階段 浪漫
context = new PursueaGirlContext( new RomanticStrategy());
break;
case " four ": // 第四階段 結婚
context = new PursueaGirlContext( new MarriedStrategy());
break;
default:
context = null;
break;
}
return context;
}
}
// 策略的宿主 承載當前需要執行的策略
public class PursueaGirlContext
{
PursueaGirlStrategy staregy;
public PursueaGirlContext(PursueaGirlStrategy strategy)
{
this.staregy = strategy;
}
// 調用策略的公共接口方法
public void ContextJustdoit()
{
if ( this.staregy != null)
{
this.staregy.Justdoit();
}
}
}
static void Main( string[] args)
{
Console.Write( " 現在是第幾階段?: ");
string level = Console.ReadLine(); // 代表當前是哪個階段
// 定義追女孩策略上下文對象
PursueaGirlContext context = FactoryStrategy.GetStrategy(level);
// 統一的策略調用模式
context.ContextJustdoit();
}
這樣我們以后如果有新的策略只需要增加新的策略類,修改工廠即可,那么細心的朋友問了,這樣只不過是把修改客戶端移到工廠里面了,將來還是需要工廠,沒關系徹底解決調用修改的話,我們將來可以利用反射!以后不管修改還是新增我們都能很好的去應對了。