2011年5月31日星期二

  《模式——工程化实现及扩展》(设计模式C# 版)《连贯接口 Fluent Interface》——“自我检验"参考答案

转自:《模式——工程化实现及扩展》(设计模式C# 版)

http://www.cnblogs.com/callwangxiang/

 

 

http://www.cnblogs.com/callwangxiang/archive/2011/05/31/ExerciseAAFluentInterface.html的参考答案

 

 

参考答案

 

设计要点:

  1. 采用连贯接口设计表格的创建过程
  2. 由于表格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

没有评论:

发表评论