我们首先回故下Builder模式的意图: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。[DP]
那我们C#中switch语句块,从一个层面上来看,就是由几部分组成的,我们来实现一个SwitchBuilder类具有这种功能.那什么
是Fluent接口,可以先看这儿wiki.
有的时候我们需要Enum类型处理复杂的类型,有一个描述字段,或还有更多其它的字段信息.我们创建一个使用static readonly
字段的类,看下面这是一个典型的实现:
/// <summary> /// EnumType /// </summary> /// <remarks>http://wintersun.cnblogs.com</remarks> public class EnumType { public static readonly EnumType ONE = new EnumType(1, "Descr1"); public static readonly EnumType TWO = new EnumType(2, "Descr2"); public static readonly EnumType THREE = new EnumType(3, "Descr3"); private readonly int id; private readonly string description; private EnumType(int id, string description) { this.description = description; this.id = id; } public int Id { get { return id; } } public string Description { get { return description; } } #region Object's override public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } return obj.GetType() != typeof (EnumType) && ((EnumType) obj).Id == Id; } public override int GetHashCode() { return id.GetHashCode(); } public override string ToString() { return string.Format("id:<{0}> and Descr:<{1}>", Id, Description); }
除了id,描述,你还可以增加更多的属生.ok,接下来我们需要定义一些接口,注意每一个接口有包含其它接口.
public interface IDo { void Do(); } public interface IBody : IDo { ICase Case(object obj); IDefault Default { get; } } public interface ICase { ICase Case(object obj); IBody Body(Action action); } public interface IDefault { IDo Body(Action action); } public interface ISwitch { ICase Switch(object obj); }
再我们的具体类:
public class SwitchBuilder : ISwitch, IDefault, ICase, IBody { private Action defaultAction; private object testObject; private IList<object> caseList; private readonly IDictionary<object, Action> caseActions = new Dictionary<object, Action>(); private SwitchBuilder() {} public static ISwitch Create() { return new SwitchBuilder(); } public ICase Switch(object obj) { caseList = new List<object>(); testObject = obj; return this; } public ICase Case(object obj) { caseList.Add(obj); return this; } public IBody Body(Action action) { foreach (var switchCase in caseList) { caseActions.Add(switchCase, action); } caseList = new List<object>(); return this; } public IDefault Default { get { return this; } } IDo IDefault.Body(Action action) { defaultAction = action; return this; } public void Do() { foreach (KeyValuePair<object, Action> caseAction in caseActions) { if (ReferenceEquals(caseAction.Key, testObject) || Equals(caseAction.Key, testObject)) { caseAction.Value(); return; } } if (defaultAction != null) { defaultAction(); } } }
如何使用呢?看这个UnitTest
[Test] public void CanCreateFluentSwitchBuilder() { EnumType state = null; EnumType enumType = EnumType.THREE; SwitchBuilder.Create() .Switch(enumType) .Case(EnumType.ONE) .Body(() => { Console.WriteLine(EnumType.ONE); state = EnumType.ONE; }) .Case(EnumType.TWO) .Case(EnumType.THREE) .Body(() => { Console.WriteLine("->" + EnumType.TWO + EnumType.THREE); state = EnumType.TWO; }) .Default .Body(() => Console.WriteLine("Def")) .Do(); Assert.AreEqual(state, EnumType.TWO); }
那些接口的一个作用在于,保证我们的SwitchBuilder使用时,要先Create然后Switch…最后do.
结论
Builder模式与Fluent接口在很多种场景下并不是那么简单的API,有时还需要简单的验证.还有其它方式实现
Fluent接口模式,例如使用嵌套类.
Author: Petter Liu http://wintersun.cnblogs.com
Reference: source