閑話策略
策略,有很多解釋。但鄙人個人比較看重這點:
策略,是為了實現某個目標或者針對某些問題而制定的應對方案,以最終實現目標。比如為實現生娃而XXOO。
因此在本框架中,策略(Strategy),則是為了實現某些功能或者處理某些特定問題而制定的通用方案或者規則。粗淺一點,你可以理解為XXOO這種方式,不管用啥姿勢,歸根到底都離不開活塞運動。
如果還不明白,我們舉個文明點的例子,比如發送短信,這是系統中常用的功能,也許短信服務商有很多,實現發短信的方式也有很多,但是對於系統來說,只需要的是發送短信這個功能而已,如何讓系統的插件都能夠使用這個功能,那么我們就需要定制統一的接口來規范,那么根據各個服務商提供的短信發送方式,我們不難理出以下接口:
/// <summary>
/// 短信策略接口
/// </summary>
public interface ISMSStrategy : IStrategyBase
{
/// <summary>
/// 短信服務器地址
/// </summary>
string Url { get; set; }
/// <summary>
/// 短信賬號
/// </summary>
string UserName { get; set; }
/// <summary>
/// 短信密碼
/// </summary>
string Password { get; set; }
/// <summary>
/// 發送短信
/// </summary>
/// <param name="to">接收人號碼</param>
/// <param name="body">短信內容</param>
/// <returns>是否發送成功</returns>
bool Send(string to, string body);
}
不管你是小辣椒還是小冬瓜,還是小XX,通過實現這種策略,組件們都知道怎么發送短信。
Magicodes的基本策略
前面說過,Magicodes框架是一套插件框架,插件要干更多事,要實現一些比較通用的功能,那么就離不開插件策略了。
對於框架來說,將常用的策略納入框架是很有利於插件調用的。目前,Magicodes框架提供了以下策略:
-
Logger——日志策略
-
Cache——緩存策略
-
Email——郵件策略
-
ScriptMin——腳本資源壓縮策略
-
Sesstion——會話策略
-
SMS——短信策略
-
UserAuthentication——用戶驗證策略
這些只是一些基本策略,后面還會集成一些通用的支付策略,認證策略等等,當前你也可以自己定制策略。廢話先不多說了,我們繼續。先說策略管理。
策略管理
對於策略一樣,策略管理我們也得合計合計。首先,我們需要一個字典來存儲策略。
/// <summary>
/// 策略字典
/// </summary>
static private Lazy<ConcurrentDictionary<string, List<IStrategyBase>>> strategyDictionary = new Lazy<ConcurrentDictionary<string, List<IStrategyBase>>>(() =>
{
return new ConcurrentDictionary<string, List<IStrategyBase>>();
}, LazyThreadSafetyMode.ExecutionAndPublication);
這里有幾點需要注意的:
-
Lazy是用於延遲加載
-
LazyThreadSafetyMode.ExecutionAndPublication是為了確保線程安全
-
ConcurrentDictionary是為了確保線程安全,這是.NET 4.0新增的字典集合
-
之所以使用List,這是為了考慮有多個同類型策略的存在的情況,比如張三喜歡玩雙P,李四喜歡玩3P一樣,也許是客戶變態,但是也總有特殊的情況。默認,我們將第一項當做默認策略。
為了使用方便,我們再定義一個屬性來獲取該值:
public ConcurrentDictionary<string, List<IStrategyBase>> StrategyDictionary { get { return strategyDictionary.Value; } }
不然每次都通過strategyDictionary.Value獲取,多累啊,而且也不利於框架使用者使用。
接下來,我們需要定義一些公共的方法來方便干活,整個代碼定義如下:
/// <summary>
/// 策略管理
/// </summary>
public abstract class StrategyManagerBase
{
/// <summary>
/// 策略字典
/// </summary>
static private Lazy<ConcurrentDictionary<string, List<IStrategyBase>>> strategyDictionary = new Lazy<ConcurrentDictionary<string, List<IStrategyBase>>>(() =>
{
return new ConcurrentDictionary<string, List<IStrategyBase>>();
}, LazyThreadSafetyMode.ExecutionAndPublication);
/// <summary>
/// 策略字典
/// </summary>
public ConcurrentDictionary<string, List<IStrategyBase>> StrategyDictionary { get { return strategyDictionary.Value; } }
/// <summary>
/// 添加策略
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract T AddStrategy<T>(T t) where T : IStrategyBase;
/// <summary>
/// 添加策略
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract T AddStrategy<T>(string key, T t) where T : IStrategyBase;
/// <summary>
/// 添加策略
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract T AddDefaultStrategy<T>(string key, T t) where T : IStrategyBase;
/// <summary>
/// 獲取策略
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public abstract T GetDefaultStrategy<T>() where T : IStrategyBase;
/// <summary>
/// 獲取策略
/// </summary>
/// <typeparam name="T">策略類型</typeparam>
/// <param name="key">key</param>
/// <returns></returns>
public abstract T GetDefaultStrategy<T>(string key) where T : IStrategyBase;
/// <summary>
/// 獲取策略集合
/// </summary>
/// <typeparam name="T">策略類型</typeparam>
/// <param name="key">key</param>
/// <returns></returns>
public abstract List<T> GetStrategys<T>(string key) where T : IStrategyBase;
/// <summary>
/// 獲取策略集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public abstract List<T> GetStrategys<T>() where T : IStrategyBase;
}
從上面可以看出,添加和獲取都定義了。而且各位觀眾,這里可以看到,我將其定義為抽象類了。
這里我忍不住想拋出一個話題,什么時候用虛擬類,什么時候用接口呢?這個我們下回討論吧,回到正題。
車子看好了,就等彩票了。我們接着實現:
public class StrategyManager : StrategyManagerBase
{
/// <summary>
/// 獲取默認策略
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public override T GetDefaultStrategy<T>()
{
return GetDefaultStrategy<T>(typeof(T).FullName);
}
/// <summary>
/// 添加策略
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public override T AddStrategy<T>(T t)
{
AddStrategy<T>(typeof(T).FullName, t);
return t;
}
/// <summary>
/// 添加策略
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public override T AddStrategy<T>(string key, T t)
{
if (StrategyDictionary.ContainsKey(key))
{
StrategyDictionary[key].Add(t);
}
else
{
var newValue=new List<IStrategyBase>() { t };
StrategyDictionary.AddOrUpdate(key, newValue, (tKey, existingVal) =>
{
return newValue;
});
}
return t;
}
public override T GetDefaultStrategy<T>(string key)
{
if (StrategyDictionary.ContainsKey(key))
return (T)StrategyDictionary[key].First();
return default(T);
}
public override List<T> GetStrategys<T>(string key)
{
if (StrategyDictionary.ContainsKey(key))
return StrategyDictionary[key] as List<T>;
return null;
}
public override List<T> GetStrategys<T>()
{
return GetStrategys<T>(typeof(T).FullName);
}
public override T AddDefaultStrategy<T>(string key, T t)
{
if (StrategyDictionary.ContainsKey(key))
{
StrategyDictionary[key].Add(t);
//反轉元素,使后來居上
StrategyDictionary[key].Reverse();
}
else
{
var newValue = new List<IStrategyBase>() { t };
StrategyDictionary.AddOrUpdate(key, newValue, (tKey, existingVal) =>
{
return newValue;
});
}
return t;
}
}
你看一無所有,搞了個兒子出來了,也就是間接證明了,彩票換車子是可以的。所以古人雲"書中自有黃金屋,書中自有顏如玉",古人誠不欺我!!
這里就沒太多講解點了,只是語法的使用了。值得討論的,就是設計理念了。對於架構,設計理念才是最重要的。之所以這么設計,我是為了追求靈活,比如需要獲取日志策略:
public override ILoggerStrategy ApplicationLog
{
get
{
return this.StrategyManager.GetDefaultStrategy<ILoggerStrategy>();
}
}
這樣獲取的話,避免了傳統的設計方式,比如(下面代碼Word中手寫,亂的話也請忍受下,Word發博確實不方便,每次發了都得調,心里大罵微軟三聲):
Public class A
{
Public ILoggerStrategy LoggerStrategy{get;set;}
……
}
如果是這么設計的話,每添加一個策略,老子都得改這個類,這是增加我的負擔。另外也方便插件定義自己的策略,假如某XX1(插件)定義了一個微信推送的策略,那么XX2(插件)只需引用這個插件就好,策略還是共享的,不增加大家的工作量,也不增加我的工作量,大家都好。
最后
之前此貼用【MagicCode起航】賬號發布過,這里重新發布過。以后Magicodes框架的博客都會使用此賬號發布。
Magicodes框架現在已經免費開源下載了,具體請訪問http://www.magicodes.net/。
策略核心部分介紹完了,覺得設計方面有問題,請盡管提,大家都是相互學習提升。
在程序員的世界里,技術不僅僅是技術。
在架構師的眼里,技術也不再是技術。
接下來,我將介紹日志策略以及其實現。
--------------------------------------------------分割線------------------------------------------------------------------
本框架將會長期維護並且更新下去,而且盡量每周分享一篇技術貼或者架構心得貼,以促進大家共同進步,如有不對的地方,請各位大神指正。