一般範例中的責任鏈,負責組合各實作的 Handler 時通常會如下方這樣組合,這樣的做法不管從操作上還是閱讀上都比較不友善:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// Init
IHandler positiveEven = new PositiveEvenHandler();
IHandler negativeEven = new NegativeEvenHandler();
IHandler positiveOdd = new PositiveOddHandler();
IHandler negativeOdd = new NegativeOddHandler();
// Configure
positiveEven.SetNext(negativeEven);
negativeEven.SetNext(positiveOdd);
positiveOdd.SetNext(negativeOdd);
// Call the chain
positiveEven.Handle(1);
positiveEven.Handle(-1);
positiveEven.Handle(2);
positiveEven.Handle(-2);
這篇主要是紀錄透過簡單的修改讓 Handler 能更簡單的組合責任鏈。
以 Fluent API 風格組合
根據上面的範例,如果能將組合責任鏈改成 Fluent API 風格,能有效提升易用性,如下:1
2
3
4
5
6
7
8
9
10
11// Init and Configure
IHandler root = new PositiveEvenHandler();
root.SetNext(new NegativeEvenHandler())
.SetNext(new PositiveOddHandler())
.SetNext(new NegativeOddHandler());
// Call the chain
root.Handle(1);
root.Handle(-1);
root.Handle(2);
root.Handle(-2);
而各節點的實作重點則是將 void SetNext(IHandler next)
改成回傳下一個節點的實例 IHandler SetNext(IHandler next)
,非常簡單就能讓整個責任鏈更易用,如下範例: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
105public interface IHandler
{
IHandler SetNext(IHandler handler);
void Handle(int number);
}
public class PositiveEvenHandler : IHandler
{
private IHandler _nextHandler;
public IHandler SetNext(IHandler handler)
{
_nextHandler = handler;
return handler;
}
public void Handle(int number)
{
if (number > 0 && number % 2 == 0)
{
Console.WriteLine($"Positive even number {number}");
return;
}
if (_nextHandler != null)
{
_nextHandler.Handle(number);
}
}
}
public class NegativeEvenHandler : IHandler
{
private IHandler _nextHandler;
public IHandler SetNext(IHandler handler)
{
_nextHandler = handler;
return handler;
}
public void Handle(int number)
{
if (number < 0 && -number % 2 == 0)
{
Console.WriteLine($"Negative even number {number}");
return;
}
if (_nextHandler != null)
{
_nextHandler.Handle(number);
}
}
}
public class PositiveOddHandler : IHandler
{
private IHandler _nextHandler;
public IHandler SetNext(IHandler handler)
{
_nextHandler = handler;
return handler;
}
public void Handle(int number)
{
if (number > 0 && number % 2 == 1)
{
Console.WriteLine($"Positive odd number {number}");
return;
}
if (_nextHandler != null)
{
_nextHandler.Handle(number);
}
}
}
public class NegativeOddHandler : IHandler
{
private IHandler _nextHandler;
public IHandler SetNext(IHandler handler)
{
_nextHandler = handler;
return handler;
}
public void Handle(int number)
{
if (number < 0 && -number % 2 == 1)
{
Console.WriteLine($"Negative odd number {number}");
return;
}
if (_nextHandler != null)
{
_nextHandler.Handle(number);
}
}
}
其他作法 - Next 屬性取代 SetNext 方法
也是個簡化組合的程式碼的方式,但這種方式當整個責任鏈很長時可讀性稍差,搭配 DI 操作起來也不太順暢。 但優點就是直接用自動實作屬性就好,不用再額外實作 SetNext 方法。
1 | IHandler chain = new PositiveEvenHandler |
結論
之前的文章提到過的,設計模式只是個樣板,實務上應該針對語言特性與應用場景做適當的調整。