《模式——工程化实现及扩展》(设计模式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特征的抽象节点类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/// <summary>
/// 修改后具有Fluent特征的集合类型
/// </summary>
/// <typeparam name="T">集合元素类型</typeparam>
/// <typeparam name="TParent">父节点类型</typeparam>
class FluentCollection<TElement, TParent>
    where TElement : class
    where TParent : class
{
    protected List<TElement> list = new List<TElement>();
    TParent parent;
 
    public FluentCollection(TParent parent)
    {
        if(parent == null) throw new ArgumentNullException("parent");
        this.parent = parent;
    }
 
    /// <summary>
    /// 返回父节点
    /// </summary>
   <font style="background-color: rgba(255, 255, 0, 1)"> public TParent Parent{get{ return parent;}}</font>
 
    /// <summary>
    /// 如何获得一个TElement类型实例的委托
    /// </summary>
    public Func<TElement> GetInstance { get; set; }
 
    /// <summary>
    /// 具有fluent特征的追加操作
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public FluentCollection<TElement, TParent> Add(TElement t)
    {
        list.Add(t);
        <font style="background-color: rgba(255, 255, 0, 1)">return this;
</font>    }
 
    /// <summary>
    /// 具有fluent特征的空置操作
    /// </summary>
    /// <returns></returns>
    public FluentCollection<TElement, TParent> Skip
    {
        get
        {
            list.Add(GetInstance());
            <font style="background-color: rgba(255, 255, 0, 1)">return this;</font>
        }
    }
 
    /// <summary>
    /// 执行LINQ的foreach操作
    /// </summary>
    /// <param name="action"></param>
    public void ForEach(Action<TElement> action)
    {
        list.ForEach(action);
    }
}
 
/// <summary>
/// 父节点为table的元素
/// </summary>
class WithTableObject
{
    Table table;    //  父节点
    public WithTableObject(Table table)
    {
        if(table == null) throw new ArgumentNullException("table");
        this.table = table;
    }
 
    /// <summary>
    /// 指向父节点——table
    /// </summary>
    <font style="background-color: rgba(255, 255, 0, 1)">public Table Parent{get{ return table;}}
</font>}

 

2、定义各个节点类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
class Notation
{
    public Notation(){Data = string.Empty;}
    public Notation(string data) {Data = data; }
    public string Data { get; private set; }
}
 
/// <summary>
/// n元素
/// </summary>
class Item : Notation
{
    public Item():base(){}
    public Item(string data) : base(data){}
}
 
/// <summary>
/// col 元素
/// </summary>
class Column : Notation
{
    public Column():base(){}
    public Column(string data) : base(data) { }
}
 
/// <summary>
/// line 元素
/// </summary>
class Line
{
    FluentCollection<Item, Line> items;
    Body body;
 
    public Line(Body body)
    {
        if(body == null) throw new ArgumentNullException("body");
        this.body = body;
        items = new FluentCollection<Item, Line>(this)
                    {
                        GetInstance = () => { return new Item(); }
                    };
    }
 
    /// <summary>
    /// 父节点
    /// </summary>
    <font style="background-color: rgba(255, 255, 0, 1)">public Body Body { get { return body; } }</font>
         
    <font style="background-color: rgba(255, 255, 0, 1)">public FluentCollection<Item, Line> Items { get { return items; } }</font>
 
    <font style="background-color: rgba(255, 255, 0, 1)">public Line NewLine{get{return body.NewLine;}}</font>
}
 
 
/// <summary>
/// body 元素
/// </summary>
class Body : WithTableObject
{
    List<Line> lines = new List<Line>();
    public Body(Table table) : base(table){}
 
    <font style="background-color: rgba(255, 255, 0, 1)">public Line NewLine
</font>    {
        get
        {
            var line = new Line(this);
            lines.Add(line);
            return line;
        }
    }
 
    <font style="background-color: rgba(255, 255, 0, 1)">public List<Line> Lines { get { return lines;}}
</font>}
 
/// <summary>
/// head 元素
/// </summary>
class Head : WithTableObject
{
    FluentCollection<Column, Head> columns;
 
    public Head(Table table) : base(table)
    {
        columns = new FluentCollection<Column, Head>(this)
                        {
                            GetInstance = () => { return new Column(); }
                        };
    }
         
    <font style="background-color: rgba(255, 255, 0, 1)">public FluentCollection<Column, Head> Columns { get { return columns; } }</font>
}
 
     
class Table
{
    string name;
    Body body;
    Head head;
 
    public Table()
    {
        body = new Body(this);
        head = new Head(this);
    }
 
    <font style="background-color: rgba(255, 255, 0, 1)">public Table Name(string name)</font>
    {
        if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
        this.name = name;
        return this;
    }
 
    public override string ToString(){return name;}
 
<font style="background-color: rgba(255, 255, 0, 1)">    public Body Body{get{ return body;}}
    public Head Head{get{ return head;}}</font>
}

 

3、定义生成电子表格的数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
class Notation
{
    public Notation(){Data = string.Empty;}
    public Notation(string data) {Data = data; }
    public string Data { get; private set; }
}
 
/// <summary>
/// n元素
/// </summary>
class Item : Notation
{
    public Item():base(){}
    public Item(string data) : base(data){}
}
 
/// <summary>
/// col 元素
/// </summary>
class Column : Notation
{
    public Column():base(){}
    public Column(string data) : base(data) { }
}
 
/// <summary>
/// line 元素
/// </summary>
class Line
{
    FluentCollection<Item, Line> items;
    Body body;
 
    public Line(Body body)
    {
        if(body == null) throw new ArgumentNullException("body");
        this.body = body;
        items = new FluentCollection<Item, Line>(this)
                    {
                        GetInstance = () => { return new Item(); }
                    };
    }
 
    /// <summary>
    /// 父节点
    /// </summary>
    public Body Body { get { return body; } }
         
    public FluentCollection<Item, Line> Items { get { return items; } }
 
    public Line NewLine{get{return body.NewLine;}}
}
 
 
/// <summary>
/// body 元素
/// </summary>
class Body : WithTableObject
{
    List<Line> lines = new List<Line>();
    public Body(Table table) : base(table){}
 
    public Line NewLine
    {
        get
        {
            var line = new Line(this);
            lines.Add(line);
            return line;
        }
    }
 
    public List<Line> Lines { get { return lines;}}
}
 
/// <summary>
/// head 元素
/// </summary>
class Head : WithTableObject
{
    FluentCollection<Column, Head> columns;
 
    public Head(Table table) : base(table)
    {
        columns = new FluentCollection<Column, Head>(this)
                        {
                            GetInstance = () => { return new Column(); }
                        };
    }
         
    public FluentCollection<Column, Head> 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、单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
[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、测试结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
------ Test started: Assembly: Concept.Tests.dll ------
 
<table>
    <name>full fill</name>
    <head>
<col>first</col><col>second</col><col>thrid</col>   
    </head>
    <body>
        <line>
        <item>
<n>11</n><n>12</n><n>13</n>           
        </item>
        <item>
<n>21</n><n>22</n><n>23</n>           
        </item>
    </line>
    </body>
</table>
 
<table>
    <name>skip columns</name>
    <head>
<col>first</col><col></col><col>thrid</col>   
    </head>
    <body>
        <line>
        <item>
<n>11</n><n>12</n><n>13</n>           
        </item>
        <item>
<n>21</n><n>22</n><n>23</n>           
        </item>
    </line>
    </body>
</table>
 
<table>
    <name>skip items</name>
    <head>
<col>first</col><col>second</col><col>thrid</col>   
    </head>
    <body>
        <line>
        <item>
<n>11</n><n></n><n>13</n>           
        </item>
        <item>
<n>21</n><n>22</n><n></n>           
        </item>
    </line>
    </body>
</table>
 
<table>
    <name>skip columns and items</name>
    <head>
<col>first</col><col></col><col>thrid</col>   
    </head>
    <body>
        <line>
        <item>
<n>11</n><n></n><n>13</n>           
        </item>
        <item>
<n>21</n><n>22</n><n></n>           
        </item>
    </line>
    </body>
</table>
 
4 passed, 0 failed, 0 skipped, took 1.29 seconds (MSTest 10.0).

 

测试确认Fluent接口的有效性

posted @   蜡笔小王  阅读(2309)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示