今天下班,同事們無聊中又聊到了食堂(怎麼寫食堂?吃貨啊!),辦公區離食堂遠的同事老阮在大家你一句我一句的誘惑下,終於忍不住了決定不管在遠也要找時間去嚐嚐,但是因爲上班不順路也不是很方便,就委託我們宿舍的老李同志幫忙第二天先去開卡充值,熱心腸的老李當然不會拒絕嘍。
1、模擬場景
有了這個前奏今天的主題就當然又有了,那麼首先我們用代碼來實現上面的功能,首先來分析一下上面的場景:
①我們需要對卡片充值,所以需要一個卡片類,代碼如下:
- /// <summary>
- /// 卡片類
- /// </summary>
- public class Card
- {
- //卡片名稱
- private string cardName = string.Empty;
- public string CardName
- {
- get
- {
- return cardName;
- }
- set
- {
- cardName = value;
- }
- }
- //構造方法
- public Card() { }
- public Card(string cName)
- {
- cardName = cName;
- }
- }
- /// <summary>
- /// 老阮
- /// </summary>
- public class MrRuan
- {
- //他有一個工卡
- private Card myCard = new Card("mrRuan");
- public Card MyCard
- {
- get
- {
- return myCard;
- }
- }
- }
- /// <summary>
- /// 櫃檯類
- /// </summary>
- public sealed class Counter
- {
- //在第一次調用類成員時,初始化唯一實例
- private static readonly Counter instance = new Counter();
- private Counter()
- {
- }
- //返回類型實例屬性
- public static Counter Instance
- {
- get
- {
- return instance;
- }
- }
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- //激活工卡的過程
- Console.WriteLine("{0}的工卡激活成功!",card.CardName);
- }
- }
- /// <summary>
- /// 熱心腸的老李
- /// </summary>
- public class MrLi
- {
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- Counter.Instance.ActivationCard(card);
- }
- }
- static void Main(string[] args)
- {
- //實例化老阮
- MrRuan ruan = new MrRuan();
- //實例化老李
- MrLi li = new MrLi();
- //將卡片給老李,老李負責去激活
- li.ActivationCard(ruan.MyCard);
- }
這時你要問了,那代理模式具體的定義是什麼呀?到底什麼是代理模式下?彆着急繼續往下看吧。
2、代理模式
代理(Proxy)模式定義:爲其他對象提供一種代理以控制對這個對象的訪問。 類圖如下:
這時我們發現了多了一個接口ICounter,那麼實現了接口的代理類與具體類的代碼如下:
- /// <summary>
- /// 櫃檯類也就是具體類提供的功能規則
- /// </summary>
- public interface ICounter
- {
- void ActivationCard(Card card);
- }
- /// <summary>
- /// 熱心腸的老李
- /// </summary>
- public class MrLi : ICounter
- {
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- Counter.Instance.ActivationCard(card);
- }
- }
- /// <summary>
- /// 櫃檯類
- /// </summary>
- public sealed class Counter : ICounter
- {
- //在第一次調用類成員時,初始化唯一實例
- private static readonly Counter instance = new Counter();
- private Counter()
- {
- }
- //返回類型實例屬性
- public static Counter Instance
- {
- get
- {
- return instance;
- }
- }
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- //激活工卡的過程
- Console.WriteLine("{0}的工卡激活成功!",card.CardName);
- }
- }
在面向對象設計中,對象之間需要進行交互和通信。例如:上面的代理類MrLi調用了具體類櫃檯類counter的激活卡片的方法(ActiviationCard),那麼這個時候代理類MrLi不在代理counter櫃檯的激活卡片功能了,而是去另一個counterNew的櫃檯去激活,但是counterNew櫃檯激活卡片的方法是(CounterActiviationCard),怎麼辦?我們需要去修改調用counter的類,那麼如何降低耦合性呢?當然就是將接口和實現分離開來,這樣代理間和櫃檯對象之間的依賴就是基於接口,而不是實現!
例如:目前MrLi與counter之間的調用如下:
- /// <summary>
- /// 熱心腸的老李
- /// </summary>
- public class MrLi
- {
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- Counter.Instance.ActivationCard(card);
- }
- }
- /// <summary>
- /// 新的櫃檯類
- /// </summary>
- public sealed class NewCounter
- {
- //在第一次調用類成員時,初始化唯一實例
- private static readonly NewCounter instance = new NewCounter();
- private NewCounter()
- {
- }
- //返回類型實例屬性
- public static NewCounter Instance
- {
- get
- {
- return instance;
- }
- }
- //激活工卡方法
- public void CounterActivationCard(Card card)
- {
- //激活工卡的過程
- Console.WriteLine("{0}的工卡激活成功!", card.CardName);
- }
- }
所以我們需要使用接口分離實現。代碼如下:
- /// <summary>
- /// 櫃檯類也就是具體類提供的功能規則
- /// </summary>
- public interface ICounter
- {
- void ActivationCard(Card card);
- }
- /// <summary>
- /// 熱心腸的老李
- /// </summary>
- public class MrLi : ICounter
- {
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- Counter.Instance.ActivationCard(card);
- }
- }
- /// <summary>
- /// 櫃檯類
- /// </summary>
- public sealed class Counter : ICounter
- {
- //在第一次調用類成員時,初始化唯一實例
- private static readonly Counter instance = new Counter();
- private Counter()
- {
- }
- //返回類型實例屬性
- public static Counter Instance
- {
- get
- {
- return instance;
- }
- }
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- //激活工卡的過程
- Console.WriteLine("{0}的工卡激活成功!",card.CardName);
- }
- }
- /// <summary>
- /// 新的櫃檯類
- /// </summary>
- public sealed class NewCounter : ICounter
- {
- //在第一次調用類成員時,初始化唯一實例
- private static readonly NewCounter instance = new NewCounter();
- private NewCounter()
- {
- }
- //返回類型實例屬性
- public static NewCounter Instance
- {
- get
- {
- return instance;
- }
- }
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- //激活工卡的過程
- Console.WriteLine("{0}的工卡激活成功!", card.CardName);
- }
- }
這時細心的朋友還會說,Mr.Li的ActivationCard方法中調用的是具體的counter類型如果換成Newcounter,還是要去修改它的代碼,你現在只能是不用去修改調用方法了而已,想的好,還記得我們當時的工廠模式嗎?它的好處不就是降低耦合嗎?爲什麼不用?
那麼加入工廠類(CounterProvider),在修改一下MrLi的調用使它的調用依賴於抽象接口而不是具體的實現,代碼如下:
- /// <summary>
- /// 熱心腸的老李
- /// </summary>
- public class MrLi : ICounter
- {
- //激活工卡方法
- public void ActivationCard(Card card)
- {
- ICounter counter = CounterProvider.GetCounter();
- counter.ActivationCard(card);
- }
- }
- /// <summary>
- /// 櫃檯類工廠
- /// </summary>
- public class CounterProvider
- {
- public static ICounter GetCounter()
- {
- ICounter counter = null;
- //從配置文件確定實例化那個櫃檯類
- if (ReadConfig)
- {
- counter = Counter.Instance;
- }
- else
- {
- counter = NewCounter.Instance;
- }
- }
- }
3、應用場景
那麼代理模式的幾種使用場景我們來看一看:
① 遠程代理:爲一個對象在不同地址空間提供局部代表。這樣可以隱藏一個對象存在於不同地址空間的事實,例如:老阮(MrRuan)在地點A,老李在地點B,餐廳櫃檯也在地點B,那麼老李和老軟住在一起(都在地點A住),那麼老李就是餐廳(地點B)在老軟與老李住處(地點A)的代表。
② 虛擬代理:是根據需要創建開銷很大的對象。通過它來存放實例化需要很長時間的真是對象,例如:老阮(MrRuan)在地點A,到餐廳櫃檯(地點B),因爲距離遠卻是很費勁,而老李剛好在這裏(地點B)上班,所以讓老李去辦是很可行的辦法。(不太恰當)
③ 安全代理:用來控制真是對象訪問時的權限,例如:老阮跟餐廳的櫃檯MM剛分手不方便去辦理,所以需要藉助老李去完成事項的辦理。
④ 智能代理:是指當調用真是的對象時,代理去處理另外一些事情,例如:老李幫助老阮辦理卡片激活時,順便說說老阮的好話,讓她倆能夠和好。