简介
http://www.codeproject.com/KB/cs/PolicyBasedCS.aspx
这篇是我在CodeProject的发文,在这篇文章中我用一个简单的范例示范如何在C#实践Policy based design的手法。
Policy的意思是方针,或策略,也就是将原本复杂的系统,拆解成多个独立运作的“策略类型”(policy class),每一组policy class都只负责单纯如行为(behavior, method)或结构(structure)的某一方面。
除此之外我们还需要一个宿主类(host class),只需要切换不同 Policy Class,就可以得到不同的需求。
我个人认为在policy based design中,最重要的并不是所谓的design,而是分析(Analysis)。
重点不在于怎么样设计出policy,而是怎么将需求分析拆解成policy based的设计。
我们可以把这种设计思路,用生活上的例子来解释。
举例来说:做菜
料理= 食材+调味+烹调
食材包括了:牛,羊,猪,鸡,青菜,等等各种食物
调味包括了:酸,甜,苦,辣,等各种调味方式,以及调味料。
烹调包括了:煎,煮,烤,炸等等各种手法。
我们可以把所有的食材当成一个方针(policy)的群组;调味也当成一个方针(policy)的群组;烹调也是。
而料理,则是一个宿主类型(host class)。
透过食材,调味以及烹调的组合,就可以产出不同的料理。
黑胡椒牛排=牛肉+黑胡椒+煎(或烤)
烤全鸡=鸡+烤肉酱+烤
范例说明
在这个范例中,我将档名的控制分成三个Policy群组。
第一个群组是CBIFileNamePolicy,这是提供档名主体的方针。
第二个群组是CBIFilenameExtensionPolicy,这是用来处理延伸档名的方针。
第三个群组是CBFileNameControlPolicy,这是用来控制主档名的方针。
在我的设计中,我也提供了三组宿主类(host class)
/// <summary>
/// This policy will get name from CBIFileNamePolicy
/// </summary>
/// <typeparam name="TNamePolicy">Must be CBIFileNamePolicy</typeparam>
public sealed class CBFileName<TNamePolicy> : CBFileName
where TNamePolicy : CBIFileNamePolicy,new()
{
TNamePolicy _policy;
public CBFileName()
: base()
{
_policy = new TNamePolicy();
}
public override string Name
{
get
{
return _policy.Name;
}
set
{
_policy.Name = value;
}
}
}
第一个宿主类非常简单,只是单纯的取得CBIFileNamePolicy的Name属性而已。
/// <summary>
/// This policy will get name from CBIFileNamePolicy.Name + "." + CBIFilenameExtensionPolicy.Name
/// </summary>
/// <typeparam name="TNamePolicy">Must be CBIFileNamePolicy</typeparam>
/// <typeparam name="TNameExtensionPolicy">Must be CBIFilenameExtensionPolicy</typeparam>
public sealed class CBFileName<TNamePolicy, TNameExtensionPolicy> : CBFileName
where TNamePolicy : CBIFileNamePolicy, new()
where TNameExtensionPolicy : CBIFilenameExtensionPolicy, new()
{
TNamePolicy _policy1;
TNameExtensionPolicy _policy2;
public CBFileName()
: base()
{
_policy1 = new TNamePolicy();
_policy2 = new TNameExtensionPolicy();
}
public override string Name
{
get
{
return _policy1.Name + "." + _policy2.Name;
}
set
{
_policy1.Name = value;
}
}
}
第二个宿主类,则是CBIFileNamePolicy.Name + "." + CBIFilenameExtensionPolicy.Name
来取得主档名及延伸档名
/// <summary>
/// This policy will get name from
/// CBIFileNamePolicy.Name + "_" + CBIFileNameControlPolicy.Name + "." + CBIFilenameExtensionPolicy.Name
/// </summary>
/// <typeparam name="TNamePolicy">Must be CBIFileNamePolicy</typeparam>
/// <typeparam name="TNameControlPolicy">Must be CBIFileNameControlPolicy</typeparam>
/// <typeparam name="TNameExtensionPolicy">Must be CBIFilenameExtensionPolicy</typeparam>
public sealed class CBFileName<TNamePolicy, TNameControlPolicy, TNameExtensionPolicy> : CBFileName, CBIFileNameControlPolicy
where TNamePolicy : CBIFileNamePolicy, new()
where TNameControlPolicy : CBIFileNameControlPolicy, new()
where TNameExtensionPolicy : CBIFilenameExtensionPolicy, new()
{
TNamePolicy _policy1;
TNameControlPolicy _policy2;
TNameExtensionPolicy _policy3;
public CBFileName()
: base()
{
_policy1 = new TNamePolicy();
_policy2 = new TNameControlPolicy();
_policy3 = new TNameExtensionPolicy();
}
string FileName
{
get
{
return _policy1.Name + "_" + _policy2.Name + "." + _policy3.Name;
}
}
public override string Name
{
get
{
Control();
return FileName;
}
set
{
_policy1.Name = value;
}
}
public void Control()
{
while (true)
{
FileInfo info = new FileInfo(FileName);
if (info.Exists && info.Length > MaxSplitSize)
{
_policy2.Control();
}
else
{
break;
}
}
}
}
第三个宿主类则是取得CBIFileNamePolicy.Name + "_" + CBIFileNameControlPolicy.Name + "." + CBIFilenameExtensionPolicy.Name
的档名格式。
客户端使用范例
CBFileName name1 =
new CBFileName<CBFileNamePolicy, CBTextExtensionPolicy>();
name1.Name = "Test1";
Console.WriteLine(name1.Name);
这个范例会得到Test1.txt。
若是将CBTextExtensionPolicy换成CBXmlExtensionPolicy,则会得到Test1.xml。
范例UML
范例代码下载