闲话策略
策略,有很多解释。但鄙人个人比较看重这点:
策略,是为了实现某个目标或者针对某些问题而制定的应对方案,以最终实现目标。比如为实现生娃而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/。
策略核心部分介绍完了,觉得设计方面有问题,请尽管提,大家都是相互学习提升。
在程序员的世界里,技术不仅仅是技术。
在架构师的眼里,技术也不再是技术。
接下来,我将介绍日志策略以及其实现。
--------------------------------------------------分割线------------------------------------------------------------------
本框架将会长期维护并且更新下去,而且尽量每周分享一篇技术贴或者架构心得贴,以促进大家共同进步,如有不对的地方,请各位大神指正。