話三國~代理者模式
王司徒巧使連環計
話說董卓自從18路諸侯聯軍退卻後,愈加囂張跋扈,不但自稱尚父且出入更是用天子儀仗,幾乎是以天子自居。朝中當然不乏漢室忠臣,其中以王允為首,已是極度不滿。但豈奈手中無兵權自己又是文官,且董卓帳下呂布驍勇無敵,因此也無所作為。因此終日鬱鬱寡歡。
有一夜,王允在家中庭院散步,忽聞在牡丹亭畔有一女子長吁短嘆。允輕聲靠近想知道是誰,一看,居然是自己的義女貂蟬,王允大怒喝道,一個婦道人家在此長吁短嘆,莫非有私情也?貂蟬驚,但仍緩緩道:我深受義父大人厚恩,無以回報,但見義父終日眉頭深鎖,必定憂心國家大事,卻不知如何協助,因此在此嘆息,如有用得到小女之處,萬死不辭。王允突然靈光一閃,大喜道:殊不知天下掌握在你手中呀!快隨我來。貂蟬不明白,但仍隨之而去。一入室中,王允突然拜倒於地,貂蟬嚇得魂不附體,立刻也跪拜在地說:義父為何如此?王允淚流滿面道:百姓有倒懸之危,君臣有累卵之急,賊臣董卓想竄漢自立,朝中文武無計可施。董卓有一義子名叫呂布,乃天下第一勇將,但我發現他父子二人皆好色之徒,我想要使美人計,先將你下嫁呂布,再獻給董卓,你從中作梗讓他二人反目,唆使呂布殺死董卓,以絕大惡。若能重建漢室光我河山,皆是你的功勞!你意下如何?貂蟬聽罷俯身於地:義父大恩無以回報,我萬死不辭!王允拜謝。按下不表。
看完以上故事,突然覺得這不就是典型的代理者模式嗎?王允的計策就是要透過貂蟬代理呂布刺殺董卓。所以就用這個故事來看看代理模式是如何運作的八。
interface IAssassin : IKillRequest
{
void Kill();
}
代理者模式的組成大致上可分為兩類,proxy(代理者)類別以及real object(被代理)的類別,在這裡定義一個共通的介面是要確保任何一個可以使用real object類別的地方都可以使用proxy類別(<=很重要)。依照故事情節,定義 了一個kill方法,這方法主要是要執行刺殺董卓的功能,因為是介面,所以並沒有實作。
/// <summary>
/// 呂布
/// </summary>
class Assassin :IAssassin
{
public override void Kill()
{
Console.WriteLine("呂布刺殺董卓");
}
}
接下來要定義real object(呂布),然後實作Kill方法。以本篇故事來說,呂布是唯一有能力刺殺董卓的男人,因此只有它具備kill方法的實作。
/// <summary>
/// 貂蟬
/// </summary>
class AssassinProxy : IAssassin
{
protected IAssassin _assassin;
public AssassinProxy(IAssassin assassin)
{
_assassin = assassin;
}
public override void Kill()
{
_assassin.Kill();
break;
}
}
再來定義貂蟬,貂蟬需要擁有real object(被代理者)類別的參考,不然貂蟬會不知道她要叫誰殺董卓,這個參考的限制便是要具備"刺殺董卓"方法的男人,在本例中,當然是三國戰神呂布囉。
static void Main(string[] args)
{
var 呂布 = new Assassin();
AssassinProxy 貂蟬 = new AssassinProxy(呂布);
貂蟬.Kill();
Console.WriteLine();
Console.Read();
}
完成了,來實際跑跑看吧,我們宣告了呂布(被代理者),接著宣告貂蟬(proxy),把呂布(被代理者)傳入當參數,接著執行kill指令。
程式碼輸出:
呂布刺殺董卓
定義
代理者模式=>為一個物件提供代理以控制這個物件的訪問
結束了嗎?當然還沒,如果只是這樣應用,那proxy類別似乎沒啥意義,直接呼叫呂布(被代理者)的類別,不是更省事嗎?因為如果仔細看故事的話,這段程式碼有兩件事不能闡述,第一件事就是王允請貂蟬代理呂布刺殺董卓(這裡注意一下,實際刺殺董卓的還是呂布不是貂蟬唷),那如果曹操請貂蟬做同樣的事,貂蟬會答應嗎?恩,權限問題這裡沒有表達出來;再來第二件事,貂蟬有實施美人計,這個情節也在程式碼看不到。
由此可見proxy類別除了執行原本real object的方法之外,它還可以額外再擴充一些行為。除此之外,衍伸應用代理模式也可使用在權限控管上,下面就來寫一個示範的例子。
/// <summary>
/// 唆使人
/// </summary>
class Person
{
public string name="";
public Person(string strName)
{
name=strName;
}
}
我們在這裡定義一個Person(唆使人)的類別,很簡單只具備一個name的屬性,來區別這個人到底是誰。
/// <summary>
/// 貂蟬
/// </summary>
class AssassinProxy : IAssassin
{
protected IAssassin _assassin;
protected Person _man;
public AssassinProxy(IAssassin assassin,Person man )
{
_assassin = assassin;
_man=man;
}
public override void Kill()
{
switch (_man.name)
{
case "曹操":
Console.WriteLine("我跟你很熟? 再不離開我就要叫囉!");
break;
case "王允":
Console.WriteLine("義父大恩,無以回報!貂蟬施展美人計");
_assassin.Kill();
break;
}
}
}
貂蟬類別新增了一個_man的屬性來存放person(唆使人),並在建構式多一個person(唆使人)的參數。以故事情節來說 ,王允想要執行呂布刺殺董卓的方法 ,透過貂蟬 ,貂蟬會判斷 王允是他的義父,所以他有權限執行此要求,所以在執行呂布的刺殺方法時,還會額外使出美人計誘惑呂布;相反的,如果是曹操跟貂蟬說"執行呂布刺殺董卓的方法",貂蟬就會判斷曹操沒權限 而大聲尖叫,因為貂蟬並不認識曹操。所以,除非person(唆使人)的name是王允,否則,貂蟬不執行呂布(被代理者)的kill方法,藉此來達到權限控管的目的。
static void Main(string[] args)
{
var 王允 = new Person("王允");
var 呂布 = new Assassin();
AssassinProxy 貂蟬 = new AssassinProxy(呂布,王允);
貂蟬.Kill();
Console.WriteLine();
Console.Read();
}
最後再看看程式執行的情況,我們宣告了呂布(被代理者),王允(唆使人)兩個類別,接著宣告貂蟬(proxy),把呂布(被代理者)和王允(唆使人)傳入當參數,接著執行kill指令。
程式碼輸出:
義父大恩,無以回報!貂蟬施展美人計
呂布刺殺董卓
static void Main(string[] args)
{
var 曹操 = new Person("曹操");
var 呂布 = new Assassin();
AssassinProxy 貂蟬 = new AssassinProxy(呂布,曹操);
貂蟬.Kill();
Console.WriteLine();
Console.Read();
}
接著依樣畫葫蘆,宣告呂布(被代理者),曹操(唆使人)兩個類別,再宣告貂蟬(proxy),把呂布(被代理者)和曹操(唆使人)傳入當參數,接著執行kill。
程式碼輸出:
我跟你很熟? 再不離開我就要叫囉!
成功!!確實達到了權限控管的效果。