转自:《模式——工程化实现及扩展》(设计模式C# 版)
http://www.cnblogs.com/callwangxiang/
http://www.cnblogs.com/callwangxiang/archive/2011/05/31/ExerciseAAFluentInterface.html的参考答案
参考答案
设计要点:
- 采用连贯接口设计表格的创建过程
- 由于表格Head涉及一层嵌套、Body涉及两层嵌套,因此为了便于调整和修改,每个节点元素类型都要保留回溯到父节点的引用
1、设计具有Fluent特征的抽象节点类型
////// 修改后具有Fluent特征的集合类型/// /// 集合元素类型 /// 父节点类型 class FluentCollection where TElement : class where TParent : class { protected List list = new List (); TParent parent; public FluentCollection(TParent parent) { if(parent == null) throw new ArgumentNullException("parent"); this.parent = parent; } /// /// 返回父节点 /// public TParent Parent{get{ return parent;}} /// /// 如何获得一个TElement类型实例的委托 /// public Func GetInstance { get; set; } /// /// 具有fluent特征的追加操作 /// /// /// public FluentCollection Add(TElement t) { list.Add(t); return this; } /// /// 具有fluent特征的空置操作 /// /// public FluentCollection Skip { get { list.Add(GetInstance()); return this; } } /// /// 执行LINQ的foreach操作 /// /// public void ForEach(Action action) { list.ForEach(action); }}/// /// 父节点为table的元素/// class WithTableObject{ Table table; // 父节点 public WithTableObject(Table table) { if(table == null) throw new ArgumentNullException("table"); this.table = table; } /// /// 指向父节点——table /// public Table Parent{get{ return table;}}}
2、定义各个节点类型
class Notation{ public Notation(){Data = string.Empty;} public Notation(string data) {Data = data; } public string Data { get; private set; }}////// n元素/// class Item : Notation{ public Item():base(){} public Item(string data) : base(data){}}/// /// col 元素/// class Column : Notation{ public Column():base(){} public Column(string data) : base(data) { }}/// /// line 元素 /// class Line{ FluentCollection items; Body body; public Line(Body body) { if(body == null) throw new ArgumentNullException("body"); this.body = body; items = new FluentCollection (this) { GetInstance = () => { return new Item(); } }; } /// /// 父节点 /// public Body Body { get { return body; } } public FluentCollection Items { get { return items; } } public Line NewLine{get{return body.NewLine;}}}/// /// body 元素/// class Body : WithTableObject{ List lines = new List (); public Body(Table table) : base(table){} public Line NewLine { get { var line = new Line(this); lines.Add(line); return line; } } public List Lines { get { return lines;}} } /// /// head 元素/// class Head : WithTableObject{ FluentCollection columns; public Head(Table table) : base(table) { columns = new FluentCollection (this) { GetInstance = () => { return new Column(); } }; } public FluentCollection Columns { get { return columns; } } } class Table{ string name; Body body; Head head; public Table() { body = new Body(this); head = new Head(this); } public Table Name(string name) { if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); this.name = name; return this; } public override string ToString(){return name;} public Body Body{get{ return body;}} public Head Head{get{ return head;}}}
3、定义生成电子表格的数据类型
class Notation{ public Notation(){Data = string.Empty;} public Notation(string data) {Data = data; } public string Data { get; private set; }}////// n元素/// class Item : Notation{ public Item():base(){} public Item(string data) : base(data){}}/// /// col 元素/// class Column : Notation{ public Column():base(){} public Column(string data) : base(data) { }}/// /// line 元素 /// class Line{ FluentCollection items; Body body; public Line(Body body) { if(body == null) throw new ArgumentNullException("body"); this.body = body; items = new FluentCollection (this) { GetInstance = () => { return new Item(); } }; } /// /// 父节点 /// public Body Body { get { return body; } } public FluentCollection Items { get { return items; } } public Line NewLine{get{return body.NewLine;}}}/// /// body 元素/// class Body : WithTableObject{ List lines = new List (); public Body(Table table) : base(table){} public Line NewLine { get { var line = new Line(this); lines.Add(line); return line; } } public List Lines { get { return lines;}}} /// /// head 元素/// class Head : WithTableObject{ FluentCollection columns; public Head(Table table) : base(table) { columns = new FluentCollection (this) { GetInstance = () => { return new Column(); } }; } public FluentCollection Columns { get { return columns; } }} class Table{ string name; Body body; Head head; public Table() { body = new Body(this); head = new Head(this); } public Table Name(string name) { if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); this.name = name; return this; } public override string ToString(){return name;} public Body Body{get{ return body;}} public Head Head{get{ return head;}}}
4、单元测试
[TestClass]public class FluentInterfaceFixture{ TableWriter writer; [TestInitialize] public void Initialize() { writer = new TableWriter(); } [TestMethod] public void TestFullFillTable() { writer.Output( new Table() .Name("full fill") .Head .Columns .Add(new Column("first")) .Add(new Column("second")) .Add(new Column("thrid")) .Parent .Parent .Body .NewLine.Items.Add(new Item("11")).Add(new Item("12")).Add(new Item("13")).Parent .NewLine.Items.Add(new Item("21")).Add(new Item("22")).Add(new Item("23")).Parent .Body .Parent ); } [TestMethod] public void TestSkipColumnTable() { writer.Output( new Table() .Name("skip columns") .Head .Columns .Add(new Column("first")) .Skip .Add(new Column("thrid")) .Parent .Parent .Body .NewLine.Items.Add(new Item("11")).Add(new Item("12")).Add(new Item("13")).Parent .NewLine.Items.Add(new Item("21")).Add(new Item("22")).Add(new Item("23")).Parent .Body .Parent ); } [TestMethod] public void TestSkiItemsTable() { writer.Output( new Table() .Name("skip items") .Head .Columns .Add(new Column("first")) .Add(new Column("second")) .Add(new Column("thrid")) .Parent .Parent .Body .NewLine.Items.Add(new Item("11")).Skip.Add(new Item("13")).Parent .NewLine.Items.Add(new Item("21")).Add(new Item("22")).Skip.Parent .Body .Parent ); } [TestMethod] public void TestSkipColumnsAndItemsTable() { writer.Output( new Table() .Name("skip columns and items") .Head .Columns .Add(new Column("first")) .Skip .Add(new Column("thrid")) .Parent .Parent .Body .NewLine.Items.Add(new Item("11")).Skip.Add(new Item("13")).Parent .NewLine.Items.Add(new Item("21")).Add(new Item("22")).Skip.Parent .Body .Parent ); }}
5、测试结果
------ Test started: Assembly: Concept.Tests.dll ------full fill first second thrid
没有评论:
发表评论