简介
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; } } } }
客户端使用范例
CBFileName name1 = new CBFileName<CBFileNamePolicy, CBTextExtensionPolicy>(); name1.Name = "Test1"; Console.WriteLine(name1.Name);
若是将CBTextExtensionPolicy换成CBXmlExtensionPolicy,则会得到Test1.xml。
范例UML
范例代码下载
欢迎到我的资源下载代码