Академический Документы
Профессиональный Документы
Культура Документы
2-018-02
004.42
34
34
ISBN 978-5-496-01649-0
,
. ,
, .
, ,
, ,
.NET-.
.NET,
.NET Framework. , SOLID, .
,
C#
.NET.
32.973.2-018-02
004.42
.
.
, , , . , ,
, .
ISBN 978-5-496-01649-0
, 2015
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
I.
1. (Strategy) . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
2. (Template Method) . . . . . . .
37
3. (Mediator) . . . . . . . . . . . . . . . . . . . . . . . . .
57
4. (Iterator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5. (Observer) . . . . . . . . . . . . . . . . . . . . . .
83
6. (Visitor) . . . . . . . . . . . . . . . . . . . . . . . . . .
100
7. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
112
II.
8. (Singleton) . . . . . . . . . . . . . . . . . . . . . . . . .
122
9. (Abstract Factory) . . . .
137
10. (FactoryMethod) . . . . . . .
145
11. (Builder) . . . . . . . . . . . . . . . . . . . . . . . . .
160
III.
12. (Adapter) . . . . . . . . . . . . . . . . . . . . . . . . . .
188
13. (Facade) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
197
14. (Decorator) . . . . . . . . . . . . . . . . . . . . . .
201
221
IV.
17. . . . . . . . . . . . . . . . . .
231
18. / . . . . . . . . . . . . . . . . . . . . . . . . . . . .
243
19. . . . . . . . . . . . . . . . . . . . . . . . . .
260
20. . . . . . . . . . . . . . . . . . . .
275
21. . . . . . . . . . . . . . . . . . . . .
284
22. . . . . . . . .
305
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
311
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
313
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
GoF- .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
I.
1. (Strategy) . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2. (Template Method) . . . . . . .
37
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
. . . . . . . . . . . . . . . . . . . . . 39
. . . . . . . . . . . . . . . . . . . . . 42
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3. (Mediator) . . . . . . . . . . . . . . . . . . . . . . . . .
57
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
? ! . . . . . . . . . . . . . . . . . . . . . 64
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4. (Iterator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
C#/.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
foreach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Push-based- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
5. (Observer) . . . . . . . . . . . . . . . . . . . . . .
83
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
IObserver/IObservable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
. . . . . . . . . . . . . . . . . . . . . . . . . . 93
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
. . . . . . . . . . . . . . . . . . . . . . . 94
. . . . . . . . . . . . . . . . . . . . . . . . 95
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6. (Visitor) . . . . . . . . . . . . . . . . . . . . . . . . . .
100
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
vs. . . . . . . . . . . . . . . . . . . . . . . . . . 109
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
7. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
112
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
II.
8. (Singleton) . . . . . . . . . . . . . . . . . . . . . . . . .
122
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Lazy of T . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
. . . . . . . . . . . . . . 126
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Singleton vs. Ambient Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Singleton vs. Static Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
9. (Abstract Factory) . . . .
137
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
10
. . . . . . . . . . . . . . . . . . . . . . . . . . . 143
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
10. (FactoryMethod) . . . . . . .
145
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
. . . . . . . . . . . . . . . . . . . . . 149
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Func . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
. . . . . . . . . . . . . . . . . . . . . 157
. . . . . . . . . . . . . . . . . . . . 157
. . . . . . . . . . . . . . . . . . . . . . 158
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
11. (Builder) . . . . . . . . . . . . . . . . . . . . . . . . .
160
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
III.
12. (Adapter) . . . . . . . . . . . . . . . . . . . . . . . . . .
188
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
13. (Facade) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
197
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
14. (Decorator) . . . . . . . . . . . . . . . . . . . . . .
201
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
11
12
16. (Proxy) . . . . . . . . . . . . . . . . . . . . . . . .
221
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Lazy<T> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
.NET Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
IV.
17. . . . . . . . . . . . . . . . . .
231
SRP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
. . . . . . . . . . . . . . . . . . . . . . . . . . . 233
SRP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
18. / . . . . . . . . . . . . . . . . . . . . . . . . . . . .
243
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
/ . . . . . . . . . . . . . . . . . . 247
/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
: - . . . . . . 254
/ . . . . . . . . . . . . . . . . . . 258
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
19. . . . . . . . . . . . . . . . . . . . . . . . . .
260
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
: . . . . . . . . . . . . . . . 263
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
LSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
20. . . . . . . . . . . . . . . . . . . .
275
. . . . . . . . . . . . . . . . . . . . . . . . . . . 276
SRP vs. ISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
. . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
ISP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
21. . . . . . . . . . . . . . . . . . . . .
284
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
. . . . . . . . . . . . . . . . . . . . . . . . . . . 291
DIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
vs. . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
. . . . . . . . . . . . . . . . . . . . . 300
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
13
14
22. . . . . . . . .
305
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
. . . . . . . . . . . . . . . . . . . . . 308
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
311
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
313
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
.
, (DevDiv) Microsoft.
, , Programming Stuff1,
. 2011 Microsoft C# MVP,
Microsoft 2014 .
,
, - .
Sergey.Teplyakov@gmail.com.
SergeyTeplyakov.blogspot.ru.
, . ,
C#,
- .
:
,
.
. , , , , .
.
, , , , .
.NET Framework C#.
. C++
Java, , , .
, . ,
.
.
.
,
.
, .
, , , . , . , ,
.
, - ,
,
Sergey.Teplyakov@gmail.com.
, ,
, . ,
.
. ,
.
, ,
.
, .
, , , , , , ,
.
. , -
, ,
.
, . ,
!
,
. , ,
, , , ,
. , !
, sivchenko@minsk.piter.com ( , ).
!
http://www.piter.com
.
GoF- .NET
:
, , . ,
, ,
.
1990-
, ,
- 1-
. , , . ,
-1.
IoC- DI- (IoC Inversion of Control (
), DI Dependency Injection ( ))
.
2 ,
1
. -. // ., ..
.: , 2007. 288 .
, C# Java.
22
56.
, .
, , . ,
, . , ,
, - ,
, ? ,
,
.
, , . ?
,
. ,
.
1. , , ! , ! !
?
2. ! 1
! !
3. . , ,
. - , .
4. , , , , . , !
1
.
. .
, ,
. , ,
,
.
Abstract
SingletonProxyFactoryBean1 Hello, World, .1?
.1.
public class HelloWorld
{
public static void Main(String[] args)
{
MessageBody mb = new MessageBody();
mb.Configure("Hello World!");
AbstractStrategyFactory asf = DefaultFactory.Instance;
MessageStrategy strategy = asf.CreateStrategy(mb);
mb.Send(strategy);
}
}
, : ,
,
Design Patterns2, ,
. ,
.
1
shashdot: http://deve
lopers.slashdot.org/comments.pl?sid=33602&cid=3636102.
. ,
, , .
23
24
Design Patterns,
. , ,
.
,
.
, ,
.
, , ,
.
.
, ,
1. , ? , . , , .
, ,
.
, Loki2 ,
. , , , ,
.
1
, , .
, , . ,
.
vs.
,
/ . , , ,
, . ,
, , ,
.
.
.
,
.
, .
, , . , ,
. , .
,
.
, - , -
. . , .NET-: , .
. .NET-
,
.
25
26
,
, 20, ,
.NET- .NET Framework.
-
(full text search).
, Application Insights,
Microsoft.
1. (Strategy)
2. (Template Method)
3. (Mediator)
4. (Iterator)
5. (Observer)
6. (Visitor)
7.
(Strategy)
: , . , .
: .
,
, ,
, - .
, , ;
, , , . ,
, , , , /, (policy).
,
, -
1. (Strategy)
. ;
; ;
..1
-
.
- (.1.1), - , Elasticsearch
SQL Server.
. 1.1.
29
30
I.
.1.2.
, .
, , . AlgorithmInterface,
.
,
. , ,
.
.NET
,
.
( Sort ISortable) (Encode/Decode
IMessageProcessor).
,
.NET- . , ILogReader LogProcessor
Func<List<LogEntry>>,
(1.1).
1.1. LogProcessor
class LogProcessor
{
private readonly Func<List<LogEntry>> _logImporter;
public LogProcessor(Func<List<LogEntry>> logImporter)
{
1. (Strategy)
_logImporter = logImporter;
}
public void ProcessLogs()
{
foreach(var logEntry in _logImporter.Invoke())
{
SaveLogEntry(logEntry);
}
}
// ...
}
.NET.
,
.
. IStrategy IContext, .
, : , , .
.
:
;
.
,
. , , !
31
32
I.
, : - ,
.
.
.
- : . ,
. , .
IValidator
? IFactory IAbstractFactory,
? ,
( ) .
?
.
ILogReader LogProcessor ,
. LogProcessor
, , .
, .
, LogFile
Importer, , .
vs.
,
1. (Strategy)
. ,
.
, IComparable<T> Comparison<T>
(1.2).
1.2.
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
returnstring.Format("Id = {0}, Name = {1}", Id, Name);
}
}
class EmployeeByIdComparer : IComparer<Employee>
{
public int Compare(Employee x, Employee y)
{
return x.Id.CompareTo(y.Id);
}
}
public static void SortLists()
{
var list = new List<Employee>();
// ""
list.Sort(new EmployeeByIdComparer());
//
list.Sort((x, y) => x.Name.CompareTo(y.Name));
}
33
34
I.
- . List.Sort ,
, SortedList SortedSet (
1.3).
1.3. SortedSet
var comparer = new EmployeeByIdComparer();
// IComparable
var set = new SortedSet<Employee>(comparer);
// , Comparison<T>
,
Comparison<T> IComparable<T>
(1.4).
1.4. IComparer
class ComparerFactory
{
public static IComparer<T> Create<T>(Comparison<T> comparer)
{
return new DelegateComparer<T>(comparer);
}
private class DelegateComparer<T> : IComparer<T>
{
private readonly Comparison<T> _comparer;
public DelegateComparer(Comparison<T> comparer)
{
_comparer = comparer;
}
1. (Strategy)
Comparison<T> , ,
Enumerable.OrderyBy:
.
: ,
.
.
, . , . ,
1
.
, ,
.
1
IV .
35
36
I.
.NET Framework
.NET Framework.
LINQ (Language Integrated Query) , , .. , , , IComparer<T> IEqualityComparer<T>,
.
WCF : IErrorHandler
; IChannelInitializer ; IDispatchMessageFormatter
; MessageFilter ..
Windows Forms, WPF, ASP.NET
.
,
.
(Template Method)
: , .
: ,
.
- () . ,
,
(tight coupling) .
,
, Base Derived,
, .
38
I.
.
, : , ,
.
. , . ,
.
. .
1. .
2. .
(2.1).
2.1. LogReader
public abstract class LogReader
{
private int _currentPosition;
// ReadLogEntry :
public IEnumerable<LogEntry> ReadLogEntry()
{
return ReadEntries(ref _currentPosition).Select(ParseLogEntry);
}
protected abstract IEnumerable<string> ReadEntries(ref int position);
protected abstract LogEntry ParseLogEntry(string stringEntry);
}
. LogFileReader
2. (Template Method)
ReadEntries ParseLogEntry .
(framework)
, ,
.
.2.1.
. 2.1.
:
AbstractClass (LogReader) Template
Method (ReadLogEntry),
PrimitiveOperation1(), PrimitiveOperation2() .. (ReadEntries
ParseLogEntry);
ConcreteClass (LogFileReader) .
,
.
.NET
,
,
39
40
I.
.
. , , .
.NET-.
WCF-,
(2.2).
2.2. WCF
//
interface ILogSaver
{
void UploadLogEntries(IEnumerable<LogEntry> logEntries);
void UploadExceptions(IEnumerable<ExceptionLogEntry> exceptions);
}
// -
// WCF-
class LogSaverProxy : ILogSaver
{
class LogSaverClient : ClientBase<ILogSaver>
{
public ILogSaver LogSaver
{
get { return Channel; }
}
}
public void UploadLogEntries(IEnumerable<LogEntry> logEntries)
{
UseProxyClient(c => c.UploadLogEntries(logEntries));
}
2. (Template Method)
, WCF- ,
Closing the proxy and using statement
Programming WCF Services.
,
.
, : , ,
41
42
I.
, 1.
C#
(Extension Methods).
, :
, , .
,
,
.
.
(.2.2).
. 2.2. LogEntry
ToString() (2.3).
2.3.
public abstract class LogEntryBase
{
public DateTime EntryDateTime { get; internal set; }
1
2. (Template Method)
.
,
(
/).
( /).
.
,
( ).
43
44
I.
. GetText
, .
- , .
-
LogFileReaderBase, .
(2.4).
2.4. LogFileReaderBase
public abstract class LogFileReaderBase : LogImporter, IDisposable
{
private readonly Lazy<Stream> _stream;
protected LogFileReaderBase(string fileName)
{
_stream = new Lazy<Stream>(
() => new FileStream(fileName, FileMode.Open));
}
public void Dispose()
{
if (_stream.IsValueCreated)
{
_stream.Value.Close();
}
}
2. (Template Method)
vs.
, .
,
. , . , ,
(2.5).
45
46
I.
, ,
.
LogParser,
. ,
ILogParser.
. , , , .
- ( , mock)
.
2. (Template Method)
(Extract and Override)1. , .
, LogFileReader .
MemoryStream
, Stream ( 2.6).
2.6.
public abstract class LogFileReaderBase : LogImporter, IDisposable
{
protected LogFileReaderBase(string fileName)
{
_stream = new Lazy<Stream>(() => OpenFileStream(fileName)));
}
protected virtual Stream OpenFileStream(string fileName)
{
return new FileStream(fileName, FileMode.Open);
}
}
//
class FakeLogFileReader : LogFileReaderBase
{
private readonly MemoryStream _mockStream;
public FakeLogFileReader(MemoryStream mockStream)
: base(string.Empty)
{
_mockStream = mockStream;
}
1
Working Effectively
With Legacy Code, The Art of Unit Testing.
47
48
I.
: , , . -
,
. , , , .
,
, . , , .
.
2. (Template Method)
.
Code Contracts (2.7).
2.7.
[ContractClass(typeof (LogImporterContract))]
public abstract class LogImporter
{
protected abstract IEnumerable<string> ReadEntries(ref int position);
protected abstract LogEntry ParseLogEntry(string stringEntry);
}
[ExcludeFromCodeCoverage, ContractClassFor(typeof (LogImporter))]
public abstract class LogImporterContract : LogImporter
{
protected override IEnumerable<string> ReadEntries(ref int position)
{
Contract.Ensures(Contract.Result<IEnumerable<string>>() != null);
Contract.Ensures(
Contract.ValueAtReturn(out position) >=
Contract.OldValue(position));
throw new System.NotImplementedException();
}
protected override LogEntry ParseLogEntry(string stringEntry)
{
Contract.Requires(stringEntry != null);
Contract.Ensures(Contract.Result<LogEntry>() != null);
throw new System.NotImplementedException();
}
}
49
50
I.
Code Contracts
Contract, Requires, Ensures, Assume . ,
, ContractClassFor.
, ReadEntries ParseLogEntry null.
position
ReadEntries.
.
- ,
- . .NET
http://bit.ly/DesignByContractArticles, Code Contracts.
, , , .
, :
, ,
, ? ? ,
?
. , ,
.
.NET Framework
.NET Framework
. , , , .
2. (Template Method)
WCF .
CommunicationObject, Open, Close, Abort .
(sealed), OnClosed,
OnAbort ..
WCF ChannelBase,
ChannelFactoryBase, MessageHeader, ServiceHostBase, BodyWriter,
.
:
SafeHandle ( ) ReleaseHandle;
TaskScheduler QueueTask Try
ExecuteTaskInline;
HashAlgorithm HashCore, DbCommandBuilder
.
(Dispose Pattern)
.NET
, .
++ , , C#,
Dispose IDisposable,
.
(Dispose Pattern) .NET
.
? , ,
,
, , ..
( ) .
: ,
.
,
. ,
(CLR, Common Language Runtime).
,
IntPtr. ,
.
.NET IDisposable,
Dispose ,
51
52
I.
(finalizers), .
Dispose ,
,
1. ,
.
(non-sealed) .
Dispose(bool),
(2.8).
2.8.
public class ComplexResourceHolder : IDisposable
{
// ( )
private IntPtr _buffer;
// ( )
private SafeHandle _handle;
public ComplexResourceHolder()
{
//
_buffer = AllocateBuffer();
_handle = new SafeWaitHandle(IntPtr.Zero, true);
}
protected virtual void Dispose(bool disposing)
{
//
ReleaseBuffer(_buffer);
// Dispose,
1
, . .
, ,
CriticalFinalizerObject.
Thread, ReaderWriterLock SafeHandle.
2. (Template Method)
if (disposing)
{
if (_handle != null)
_handle.Dispose();
}
}
~ComplexResourceHolder()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// AllocateBuffer ReleaseBuffer
}
,
.
Dispose(bool),
Dispose ,
, .
Dispose ,
.
, ,
,
,
.
. -,
, -, 99,999% .
, :
?
FileStream IntPtr?
53
54
I.
,
?
, ,
, , SmartHandle.
, SmartHandle
.
- ,
Dispose(bool)
.
:
DisposeNativeResources
DisposeManagedResources.
2.9.
public class ProperComplexResourceHolder : IDisposable
{
//
protected virtual void DisposeNativeResources()
{
ReleaseBuffer(_buffer);
}
protected virtual void DisposeManagedResources()
{
if (_handle != null)
_handle.Dispose();
}
~ProperComplexResourceHolder()
{
DisposeNativeResources();
}
public void Dispose()
{
2. (Template Method)
DisposeNativeResources();
DisposeManagedResources();
GC.SuppressFinalize(this);
}
// AllocateBuffer ReleaseBuffer
}
Dispose ,
, .
,
, .
SafeHandle
, .NET Framework,
.
SafeHandle.
, Dispose(bool), SafeHandle
ReleaseHandle,
,
IsInvalid, , .
, ,
SafeHandle ( 2.10)
.
2.10. SafeHandle
// HativeHelper
class CustomSafeHandler : SafeHandle
{
private readonly IntPtr _nativeHandle =
55
56
I.
NativeHelper.InvalidHandler;
[ReliabilityContract(
Consistency.WillNotCorruptState, Cer.MayFail)]
public CustomSafeHandler()
: base(NativeHelper.InvalidHandler, true)
{
_nativeHandle = NativeHelper.AcquireHandle();
}
public override bool IsInvalid
{
[SecurityCritical]
get
{
return
_nativeHandle == NativeHelper.InvalidHandler;
}
}
protected override bool ReleaseHandle()
{
NativeHelper.ReleaseHandle(DangerousGetHandle());
return true;
}
}
ReleaseHandle Dispose
, ,
( IsInvalid false).
.
.
.
(Mediator)
: , .
: ,
.
, .
. LogFile
Reader - LogSaver, - 1 (.3.1).
1
, , http://www.object
mentor.com/resources/articles/dip.pdf. ,
(Lamp) (Button). , ,
. ,
.
58
I.
. 3.1. -
3. (Mediator)
. 3.2. -
,
.
.3.3.
(
System.Object) -. .
:
Mediator (LogFileImporter) . , Mediator
;
59
60
I.
. 3.3.
,
. ( high
cohesion), ( low coupling).
.
,
. / ,
. / .
.
,
.
,
:
.
3. (Mediator)
, .
/ (Producer/Consumer), (Event
Aggregator) ,
.
.
, .
. LogFileReader LogFileSaver LogImporter. ,
.
( push-
1), .
(.3.4).
LogFileReader , .
IObservable .
. .
Windows Forms UI-. : -.
(CustomForm) TextBox
Button
TextBox ( 3.1).
1
Push- pull- 5.
61
62
I.
. 3.4.
. ,
.
3. (Mediator)
, , ,
. ,
, , , .
. , . , , . ,
, .
.
( LogImporter), LogFileReader LogSaver,
(Event Aggregator) (.3.5).
. 3.5.
LogFileReader / , . LogSaver
, , .
, ,
. , . ,
.
63
64
I.
, . , , . ,
, .
, A . , ,
, .
,
, .
,
.
? !
: -? TDD (TestDriven Development) , ?
, ,
, . .
, ,
.
. .
? , ,
. ,
, .
(mocks) ,
.
, ,
(CUT Class Under Test) .
, (, -
3. (Mediator)
), .
. -, -,
, .
: ,
.
, / - . , .
, (.3.6).
. 3.6.
65
66
I.
Main, ServiceMain
global.asax. (Composition Root)
.
IoC-
-.
. , ,
, , .
: . .
, , , .
, .
,
. , , , .
.
, , ,
. ,
, :
.
.NET Framework
, ,
3. (Mediator)
MVx- ,
21, .
67
(Iterator)
: , .
. , , -.
,
.
, . : ,
, .
,
: foreach C#,
range-for C++ 11, for Java 5+, Eiffel
4. (Iterator)
across. ,
foreach ,
(Iterator Block C# VB) (Sequence Comprehension),
F#, Scala, Phyton .
. ,
, LogFileReader
LogFileSource, IEnumerable<LogEntry>
(4.1).
4.1. LogFileSource
public class LogFileSource : IEnumerable<LogEntry>
{
private readonly string _logFileName;
public LogFileSource(string logFileName)
{
_logFileName = logFileName;
}
public IEnumerator<LogEntry> GetEnumerator()
{
foreach (var line in File.ReadAllLines(_logFileName))
{
yield return LogEntry.Parse(line);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
, .NET
Framework .
69
70
I.
. 4.1.
:
Iterator (IEnumerator<T>) ;
Aggregate (IEnumerable<T>) ,
;
ConcreteAggregate1 (List<T>) ;
ConcreteIterator (List.Enumerator<T>)
.
.NET .
GetEnumerator IEnumerable, .
IEnumerator :
MoveNext . false,
;
Current ;
Reset . .
4. (Iterator)
71
72
I.
1- ,
MoveNext .
.NET , ++. ++
: Input Forward Bidirectional RandomAccess. ++
OutputIterator, .
.NET : .
.NET,
(generics) (iterator
blocks) (.4.3).
. 4.3.
C#/.NET
. .
,
, Code Contracts. ,
, ,
, remarks,
.
4. (Iterator)
Code Contracts
BCL. IEnu
merable/IEnumerator , .
MoveNext Current
(4.2).
4.2. .NET
public T Current
{
get
{
Contract.Requires(!Disposed, "Iterator should not be disposed.");
Contract.Requires(IteratorPointsToCorrectValue,
"MoveNext() should be called and return 'true'.");
Contract.Ensures(true, "Returns current value from the
Aggregate.");
// ,
return default(T);
}
}
public bool MoveNext()
{
Contract.Requires(!Disposed, "Iterator should not be disposed.");
Contract.Requires(Valid, "Iterator should
be valid.");
// ,
//
Contract.Ensures(Finished() ||
InternalIndex == Contract.OldValue(InternalIndex) + 1);
Contract.Ensures(Contract.Result<bool>() ==
73
74
I.
, ,
, ! ,
mscorlib.Contracts.dll, .
Current
:
Dispose;
:
MoveNext, true.
: Current ,
. , Contract.Ensures(true, ""). ,
null .
MoveNext
:
Dispose;
(
).
: ,
true,
false.
. -,
Current MoveNext.
Current : Current
Dispose MoveNext !
,
Current .
, MoveNext:
MoveNext . MoveNext
4. (Iterator)
false! , , ( ).
.
, MoveNext.
1 (4.3).
4.3.
public static IEnumerator<int> CustomArrayIterator(this int[] array)
{
foreach (var n in array) { yield return n; }
}
,
, .
yield return. ,
, .
, Reset
. , ,
. Reset?
C# ,
( 1- ), (
) ,
. (corouting)2,
MoveNext.
1
C#. 1,
http://bit.ly/IteratorPartOne.
, https://ru.wikipedia.org/wi
ki/.
75
76
I.
, , :
,
MoveNext. ,
, , (4.4).
4.4.
public static IEnumerable<string> ReadFromFile(string path)
{
if (path == null) throw new ArgumentNullException("path");
foreach(string line in File.ReadLines(path))
{
yield return line;
}
}
// ?
var result = ReadFromFile(null); //1
foreach (var l in result)
{
Console.WriteLine(l); //2
}
LINQ (Language Integra
ted Query),
.
C#,
C#, http://bit.ly/IteratorsInCSharp.
.
foreach
foreach /
.
4. (Iterator)
(/) while.
(4.5).
4.5. foreach
public static void ForEachIEnumerable(IEnumerable sequence)
{
// foreach(var e in sequence) {Console.WriteLine(e);}
IEnumerator enumerator = sequence.GetEnumerator();
object current = null;
try
{
while (enumerator.MoveNext())
{
current = enumerator.Current;
Console.WriteLine(current);
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
foreach IEnumerable/
IEnumerable<T>. , GetEnu
merator, bool MoveNext()
Current.
Duck typing, foreach.
, foreach
C#5.0, current
77
78
I.
(
C# 5.01).
IDisposable,
IEnumerator<T> IDisposable. ,
, , , finally, Dispose . ,
,
IEnumerable/IEnumerator, IDisposable.
, () (
). , ,
.
4.6.
4.6.
public static IEnumerable<int> GenerateFibonacci()
{
int prev = 0;
int current = 1;
while (true)
{
yield return current;
int tmp = current;
current = prev + current;
prev = tmp;
}
}
1
http://bit.ly/ClosingOverLoopVariable.
4. (Iterator)
C# (list
compreh ension),
.
, ++, ( )
, , . , ,
:
, .
, ,
.NET Framework. , , : . , 4.7
InvalidOperationException.
4.7. .NET
var list = new List<int> { 42, 12 };
var listIter = list.GetEnumerator();
listIter.MoveNext();
list.RemoveAt(1); // 2-
Console.WriteLine(listIter.Current); // OK
listIter.MoveNext(); // InvalidOperationException
var linked = new LinkedList<int>();
linked.AddLast(42);
var linkedIter = linked.GetEnumerator();
linkedIter.MoveNext();
linked.AddLast(12);
Console.WriteLine(linkedIter.Current); // OK
linkedIter.MoveNext(); // InvalidOperationException
79
80
I.
++,
std::list .
.NET Framework .
, , , , .
(4.8), , .
4.8.
var x = new {Items = new List<int> {1, 2, 3}.GetEnumerator()};
while (x.Items.MoveNext())
{
Console.WriteLine(x.Items);
}
, ,
. , ,
-. Roslyn,
- ! (Roslyn. How to Contribute,
Coding Conventions.)
.
2. Observable.Generate 1.
Push-based-
,
, , , .
(pull-based) ,
Next .
1
http://bit.ly/ObservableGenerate.
4. (Iterator)
push-based-,
, .
, , .NET Reactive Extensions
IObserver<T>/IObservable<T>. ,
, , (4.9).
4.9. IObservable
var list = new List<int> {1, 2, 3};
IObservable<int> observable = list.ToObservable();
observable.Subscribe(
onNext: n => Console.WriteLine("Processing: {0}", n),
onCompleted: () => Console.WriteLine("Sequece finished"));
, , , SqlDataReader, IEnume
rable, 1.
, .
-?
: LogFileReader IEnume
rable<LogEntry Read() LogFileSource, IEnumerable<LogEntry>?
,
. LogFileSource ,
, , .
?
1
Introduction to Rx. 5, .
81
82
I.
, MoveNext?
LogFileReader.
.NET Framework
.NET Framework :
IEnumerable/IEnumerator
( );
IEnumerable<T>/IEnumerator<T> ( );
IObservable<T>/IObserver<T> ( pushbased) .
C# foreach,
.
(Observer)
:
,
.
: .
.
1 2 -
. 2
, .
2 ,
- .
2 1 .
pull-, push-
(.5.1).
84
I.
Push- . push-
(callbacks). , , push-
. push .
-
.
- LogFileReader.
. LogFileReader
- Read
(pull-). LogFileReader - (push-).
push-. LogFileReader
LogSaver, - . LogFileReader
, , .
LogFileReader
LogSaver, ,
.
5. (Observer)
:
.
.5.2.
. 5.2.
:
Observer ;
Subject ( ) ;
ConcreteObserver ;
ConcreteSubject .
.NET
.
, IObserver/IObservable
.
C# .NET Java,
-. Java :
object notify/notifyAll
(BaseSubject)
(BaseObserver).
85
86
I.
.NET:
( );
(events);
-;
IObserver/IObservable.
.NET
. ,
(5.1).
5.1. LogFileReader
public class LogFileReader : IDisposable
{
private readonly string _logFileName;
private readonly Action<string> _logEntrySubscriber;
private readonly static Timespan CheckFileInterval =
Timespan.FromSeconds(5);
private readonly Timer _timer;
public LogFileReader(string logFileName,
Action<string> logEntrySubscriber)
{
Contract.Requries(File.Exists(logFileName));
_logEntrySubscriber = logEntrySubscriber;
_timer = new Timer(() =>
CheckFile(), CheckFileInterval, CheckFileInterval);
}
public void Dispose()
{
5. (Observer)
_timer.Dispose();
}
private void CheckFile()
{
foreach(var logEntry in ReadNewLogEntries())
{
_logEntrySubscriber(logEntry);
}
}
private IEnumerable<string> ReadNewLogEntries()
{
// ...
// ,
//
}
}
.
.NET , 1:1 LogFileReader .
, , , .
,
. .NET ( )
.
,
,
(5.2).
87
88
I.
5.2. LogFileReader
public class LogEntryEventArgs : EventArgs
{
public string LogEntry {get; internal set;}
}
public class LogFileReader : IDisposable
{
private readonly string _logFileName;
public LogFileReader(string logFileName)
{
//...
}
public event EventHandler<LogEntryEventArgs> OnNewLogEntry;
private void CheckFile()
{
foreach(var logEntry in ReadNewLogEntries())
{
RaiseNewLogEntry(logEntry);
}
}
private void RaiseNewLogEntry(string logEntry)
{
var handler = OnNewLogEntry;
if (handler != null)
handler(this, new LogEntryEventArgs(logEntry));
}
}
.
LogFileReader
5. (Observer)
- . ,
.
. ,
, (
5.3).
5.3.
public interface ILogFileReaderObserver
{
void NewLogEntry(string logEntry);
void FileWasRolled(string oldLogFile, string newLogFile);
}
public class LogFileReader : IDisposable
{
private readonly ILogFileReaderObserver _observer;
private readonly string _logFileName;
public LogFileReader(string logFileName,
ILogFileReaderObserver observer)
{
_logFileName = logFileName;
_observer = observer;
}
// , ,
// -
// .
private void DetectThatNewFileWasCreated()
{
//
89
90
I.
if (NewLogFileWasCreated())
_observer.FileWasRolled(_logFileName, GetNewLogFileName());
}
}
, . , .
IObserver/IObservable
: (not composable).
, .
pull-based- LogFileReader LINQ (Language Integrated Query)
.
, LINQ
, :
//
var messages =
logFileReader.Read()
.Select(ParseLogMessage)
.Where(m => m.Severity == Critical);
foreach(var criticalMessages in messages.Buffer(10))
{
BulkSaveMessages(criticalMessages);
}
Buffer Enumerable,
.
4- .NET Framework IObserver/IObser
vable ,
5. (Observer)
91
92
I.
_logEntriesSubject.OnNext(logEntry);
}
}
}
LINQ-:
var messagesObservable =
logFileReader.NewMessages
.Select(ParseLogMessages)
.Where(m => m.Severity == Critical);
messagesObservable
.Buffer(10)
.Subscribe(IList<LogEntry> criticalMessages => BulkSaveMessages(critical
Messages));
1 . IObservable ,
, IEnumerable, .
pull-based,
,
push-based, .
4.
IObserver/IObservable
. IObservable ,
.
(OnNext), ,
(OnError), ,
(OnComplete). IObservable ,
.
1
. Introduction to Rx .
5. (Observer)
IObserver/IObservable. ,
pushbased-, LINQ-. ,
.
Subject<T> -
(Observable.FromEvent) . .
,
.
:
.
1:1
. :
, .
Task, ,
, .
, - .
?
.
, .
93
94
I.
?
. .
.
.
, IObservable.
.NET.
, ..
, -, , . , ( Form.OnClosing TaskScheduler.UnobservedException),
, .
?
.
, .
pull- .
?
.
. ,
5. (Observer)
, . , LogFileReader,
(ILogFileReaderObserver),
(, ILogFileProcessor).
?
.
?
API .
: push pull1.
push-
: EventArgs, . pull-
, .
push- pull-
.NET.
.NET Event
Handler<T>, : object sender TEventArgs
args:
public class LogEntryEventArgs : EventArgs
{
public string LogEntry {get; internal set;}
}
Push/pull- . push- ,
. .
push/pull- , .
95
96
I.
, EventHandler. .NET
EventHandler<T>.
(push)
, , ,
(pull) .
5. (Observer)
. push pull-
. Push- ,
, ,
. Pull- ,
, .
pull- , UI- , . - push-
,
.
.NET-. , , , :
public class Singleton
{
private static readonly Singleton _instance = new Singleton();
public static Singleton Instance { get { return _instance; } }
public event EventHandler Event;
}
class MemoryLeak
{
public MemoryLeak()
{
Singleton.Instance.Event +=
(s, e) => Console.WriteLine("Hello, Memory Leak!");
}
}
97
98
I.
MemoryLeak
, Singleton.MyEvent.
.
1. , .
3. IDisposable
Dispose.
4. (Weak Event Pattern). , (Weak
References) .
,
.
.
.
. .
/
. ,
(,
) .
. ,
,
.
:
,
.
5. (Observer)
. MVx (Model View Controller/Presenter View
Model)
. .
MVx 21.
.NET Framework
. .NET Framework
, .
.
(AppDomainSetup.AppDomainInitializer, HttpConfi
guration.Initializer) ( WPF/Windows Forms/WCF).
. API Event Hub . IEventProcessor Close
Async, OpenAsync ProcessEventsAsync.
99
(Visitor)
: ,
. ,
.
-
. , , .
.
, ,
. , .
, . , -,
, .
(.6.1).
6. (Visitor)
+DateTime
+Severity
+Message
ExceptionLogEntry
SimpleLogEntry
+Exception
+AdditionalInfo
. 6.1. LogEntry
-. ,
,
.. , . , LogEntry
. /
, , .
- . (6.1).
6.1. LogEntry
public class DatabaseLogSaver
{
public void SaveLogEntry(LogEntry logEntry)
{
var exception = logEntry as ExceptionLogEntry;
if (exception != null)
{
SaveException(exception);
}
101
102
I.
else
{
var simpleLogEntry = logEntry as SimpleLogEntry;
if (simpleLogEntry != null)
SaveSimpleLogEntry(simpleLogEntry);
throw new InvalidOperationException("Unknown log entry type");
}
}
private void SaveSimpleLogEntry(SimpleLogEntry logEntry) {...}
private void SaveException(ExcetpionLogEntry exceptionLogEntry) {...}
}
LogEntry ,
.
.
LogEntry Accept,
ILogEntryVisitor,
Visit (6.2).
6.2.
public interface ILogEntryVisitor
{
void Visit(ExceptionLogEntry exceptionLogEntry);
void Visit(SimpleLogEntry simpleLogEntry);
}
public abstract class LogEntry
{
public abstract void Accept(ILogEntryVisitor logEntryVisitor);
//
}
6. (Visitor)
103
104
I.
.
.6.2.
Client
ConcreteVisitor1
ConcreteVisitor2
+Visit(ConcreteElementA)
+Visit(ConcreteElementB)
+Visit(ConcreteElementA)
+Visit(ConcreteElementB)
ObjectStructure
v.VisitConcreteElementA(this)
ConcreteElementA
ConcreteElementB
+Accept(Visitor v)
+OperationA()
+Accept(Visitor v)
+OperationA()
v.VisitConcreteElementB(this)
. 6.2.
:
Visitor (ILogEntryVisitor) ;
Element (LogEntry) ,
;
Client (DatabaseLogSaver)
.
6. (Visitor)
, . Shape
,
. Rectangle
: , .. , .
.
. Draw
, GetArea
..
- ,
.
.
.
. IVisitor
. , .
18.
.
:
Accept. IVisitor, .
vs.
,
. Accept
105
106
I.
Match, .
Match1 LogEntry ,
c 6.4.
6.4.
public abstract class LogEntry
{
public void Match(
Action<ExceptionLogEntry> exceptionEntryMatch,
Action<SimpleLogEntry> simpleEntryMatch)
{
var exceptionLogEntry = this as ExceptionLogEntry;
if (exceptionLogEntry != null)
{
exceptionEntryMatch(exceptionLogEntry);
return;
}
var simpleLogEntry = this as SimpleLogEntry;
if (simpleLogEntry != null)
{
simpleEntryMatch(simpleLogEntry);
return;
}
throw new InvalidOperationException("Unknown LogEntry type");
}
}
Match (
6.5).
1
6. (Visitor)
6.5.
public class DatabaseLogSaver
{
public void SaveLogEntry(LogEntry logEntry)
{
logEntry.Match(
ex => SaveException(ex),
simple => SaveSimpleLogEntry(simple));
}
private void SaveSimpleLogEntry(SimpleLogEntry logEntry) {...}
private void SaveException(ExceptionLogEntry exceptionLogEntry) {...}
}
, Match
/.
,
/.
18.
1 (pattern matching).
-
, - .
, 1
,
, . switch .
C# .
, Pattern Matching in C#
Part0. C# .
, ( ) .
107
108
I.
, ,
- . :
.
, , - , .
Match,
,
. Match
, Log
EntryEx.
. . Accept
: .
,
: (6.6).
6.6.
LogEntry logEntry = new ExceptionLogEntry();
ILogEntryVisitor visitor = new Visitor1();
// Visitor1.Visit(ExcpetionLogEntry)
logEntry.Accept(visitor);
logEntry = new SimpleLogEntry();
visitor = new Visitor2();
// Visitor2.Visit(SimpleLogEntry)
logEntry.Accept(visitor);
6. (Visitor)
vs.
IVisitor.
, .
Visit(YetAnotherType).
VisitorBase
, Visit.
, Visit .
, .NET .
IVisitor VisitorBase.
( 6.7).
6.7.
public abstract class LogEntryVisitorBase : ILogEntryVisitor
{
public virtual void Visit(ExceptionLogEntry exceptionLogEntry)
{}
public virtual void Visit(SimpleLogEntry simpleLogEntry)
{}
}
public class DatabaseExceptionLogEntrySaver : LogSaverBase
{
public void SaveLogEntry(LogEntry logEntry)
{
logEntry.Accept(new ExceptionLogEntryVisitor(this));
}
private void SaveException(ExceptionLogEntry exceptionLogEntry) {...}
109
110
I.
,
.
.
,
, .
6. (Visitor)
,
.
, , .
. ,
, . .
.NET Framework
ExpressionTreeVisitor
(Expression Trees) .NET Framework.
LINQ-, .
Roslyn . CSharpSyntaxVisitor , SymbolVisitor<TResult>
.
DbExpressionVisitor Entity Framework SQL-.
111
.
.
.
.
.
, .
.
.
,
, , .
: , ,
, .
7.
.
. ,
, , .
ICommand Execute, (.7.1).
. 7.1.
113
114
I.
7.1.
public class LogExporterViewModel
{
public Action GetExportLogsCommand()
{
return () => _logSaver.Save(LogEntries);
}
public IEnumerable<LogEntry> LogEntries {get; private set;}
}
ICommand RelayCommand, Func<T> Action1.
.NET Framework:
ICommand WPF,
;
IDbCommand ADO.NET ,
;
Task<T> Func<T>,
,
.
:
. ,
.
. Socket
Connect, , (
1
WPF MVVM
WPF (MSDN Magazine, 2009. ).
7.
Thread) , .
.
(.7.2).
. 7.2.
(Socket)
State, ConcreteState1 (NotConnected)
ConcreteState2 (Connected) Handle
( Connect).
. . ,
, . , ,
, .
, Thread, Thread .
. .NET Framework
,
(public) .NET Framework .
CommunicationObject WCF : Created, Opening, Opened, Closing, Closed Faulted.
115
116
I.
Task :
Created, WaitingForActivation, WaitingToRun, Running, RunT o
Completion, Canceled, Faulted.
: ,
. - , .
.NET
Framework, , .
, ,
Handle()
Handled True.
Windows Forms Closing, (
7.2).
7.2.
public DialogForm()
{
this.Closing += HandleClosing;
}
private void HandleClosing(object sender, CancelEventArgs ea)
{
if (UserDontWantToCloseTheWindow())
{
ea.Cancel = true;
}
}
.NET ,
.
Invoke, (7.3).
7.
7.3.
// Form.cs
private void ClosingForm()
{
if (Closing != null)
{
var eventArgs = new CancelEventArgs(cancel: false);
var invocationList = Closing.GetInvocationList();
foreach (EventHandler<CancelEventArgs> handler in invocationList)
{
handler(this, eventArgs);
if (eventArgs.Cancel)
{
//
return;
}
}
}
CloseForm();
}
.7.3.
. 7.3.
117
118
I.
.NET Framework:
Closing Windows Forms
Cancel CancelEventArgs True;
TaskScheduler.UnobservedException, , , UnobservedTaskException
EventArgs.SetObserved.
Contract.ContractFailed Application.DispatcherUnhandled
Exception.
II
8. (Singleton)
9. (Abstract Factory)
10. (FactoryMethod)
11. (Builder)
120
II.
-
. , ,
. ,
.
.
,
. , ,
. - ,
.
, .
,
, .
,
.
,
.
.
. , . ,
.
, .
.
.
. , -
II.
. .
. . ,
, , . , , . ,
.
.
, .
121
(Singleton)
: , , .
: - .
.
, , .
,
.
,
. ,
.
- ,
.
8. (Singleton)
.8.1.
. 8.1.
.NET
, ( ,
.NET) :
;
1 .
,
.NET- .
.
, .
( )
. , ,
.
Lazy of T
(8.1),
( ).
1
,
.
123
124
II.
8.1. Lazy<T>
public sealed class LazySingleton
{
private static readonly Lazy<LazySingleton> _instance =
new Lazy<LazySingleton>(() => new LazySingleton());
LazySingleton() {}
public static LazySingleton Instance { get { return _instance.Value; } }
}
,
Singleton<T>, .
: + + !
: .NET 4.0+.
(8.2), .
8.2.
public sealed class DoubleCheckedLock
{
// volatile!
private static volatile DoubleCheckedLock _instance;
private static readonly object _syncRoot = new object();
DoubleCheckedLock()
{}
public static DoubleCheckedLock Instance
{
get
{
8. (Singleton)
if (_instance == null)
{
lock (_syncRoot)
{
if (_instance == null)
{
_instance = new DoubleCheckedLock();
}
}
}
return _instance;
}
}
}
, , _instance volatile!
, ,
Instance, ,
.
. _instance = new DoubleCheckedLock(); , () .
1. .
2. ( ).
3. _instance.
_instance volatile,
. 2- 3-
, ,
_instance , 1 (.8.2).
1
Publication
via Volatile Field The C# Memory Model in Theory and Practice
(MSDN Magazine, 2012. ).
125
126
II.
. 8.2.
:
+ ;
;
.NET Framework.
:
+ ;
.
8.3.
8.3.
public sealed class FieldInitSingleton
{
// ,
//
8. (Singleton)
127
128
II.
8.5.
(readonly field).
8.5.
class FieldBasedSingleton
{
public static readonly FieldBasedSingleton Instance =
new FieldBasedSingleton();
}
.
1. .
,
TypeInitializationException. ,
,
.
2. . ,
.
, beforeFieldInit,
(relaxed)
.
, 8.6 ( ) Main,
.
8.6.
static void Main(string[] args)
{
Console.WriteLine("Starting Main...");
if (args.Length == 1)
{
var s = SingletonWithoutStaticCtor.Instance;
}
Console.ReadLine();
}
8. (Singleton)
, .
, , , . ,
.
3. . .
,
,
.
: .
:
;
( );
.
? .8.3.
?
, , ,
, . , , ,
,
.
129
130
II.
. 8.3.
-
, , .
, . ,
,
Ambient Context1 (8.7).
,
Instance . setter , ,
-.
1
8. (Singleton)
,
.
8.7. Ambient Context
public interface ILogger
{
void Write();
}
internal class DefaultLogger : ILogger
{
public void Write() {}
}
public class GlobalLogger
{
private static ILogger _logger = new DefaultLogger();
// ( )
//
public static ILogger Logger
{
get { return _logger; }
internal set { _logger = value; }
}
}
, , .
Instance
(non-sealed) , .
SingletonBase , , .
:
.
131
132
II.
,
. Ambient Context
( ) , .
.
, ,
: ,
, . ,
.
1: ,
, , . (, Instance),
1
III.
8. (Singleton)
(AnotherInstance?) , GetInstance(name) .
-
. : , .
,
(.8.4).
. 8.4. ,
,
(DataUploader) Program.
2:
,
.
.
, ,
. , ,
, .
, .
. .
133
134
II.
/
( ?!), :
- . ,
, ? , ,
.
.
.
, . , ,
.
:
, ,
, . ,
, .
.
,
.
. Ambient Context, , ,
-.
.
/. ,
. , , .
, -, -
.
.
, -
8. (Singleton)
.
(
8.8).
8.8.
// ,
// , ,
private static IRepository _repository = Repository.Instance;
, , , -
.
.NET Framework
.
.NET Framework : Sy
stem.ServiceModel.Dispatcher.PeerValidationBehavior.Instan
ce, System.Net.NetworkingPerfCounters.Instance, System.Threa
ding.TimerQueue.Instance ..
SystemClock.Instance
NodaTime SqlClientFactory.Instance .NET Framework.
.
ThreadPool.QueueUserWorkItem, log4net.LogManager.GetLogger
..
( Ambient Context).
: AppDomain.Cur
rentDomain, Thread.CurrentThread, SynchronizationContext.Cur
rent, TaskSceduler.Defult, Form.ActiveForm, HttpContext.Current,
OperationContext.Current ..
: ASP.NET MVC
ControllerBuilder.Current, Entity Framework Database.SetInitia
lizer.
, .NET Framework
, .
,
135
136
II.
.
( ThreadPool.QueueUserWorkItem)
( Ambient Context)
.
Skeet Jon. Implementing the Singleton Pattern in C#. http://csharpindepth.com/
articles/general/singleton.aspx.
Programming Stuff: . http://bit.ly/Sing
letonsAndStaticCtor.
Programming Stuff: . http://bit.ly/Sta
ticCtors.
Programming Stuff: . http://bit.ly/De
pendencyManagement.
. The C# Memory Model in Theory and Practice. MSDN Magazine,
2012. .
(Abstract Factory)
. :
,
.
, .
,
.
: (dependent or related objects),
.
:
.
138
II.
.
, . - ,
.
, (Application Root). Main (
),
.
.
-
. , SQL Server, .
(), LogSaver DbProviderFactory
ADO.NET (9.1).
9.1.
public class LogSaver
{
private readonly DbProviderFactory _factory;
public LogSaver(DbProviderFactory factory)
{
_factory = factory;
}
public void Save(IEnumerable<LogEntry> logEntries)
{
using (var connection = _factory.CreateConnection())
{
9. (Abstract Factory)
SetConnectionString(connection);
using (var command = _factory.CreateCommand())
{
SetCommandArguments(logEntries);
command.ExecuteNonQuery();
}
}
}
private void SetConnectionString(DbConnection connection)
{}
private void SetCommandArguments(IEnumerable<LogEntry> logEntry)
{}
}
DbProviderFactory,
SqlClientFactory, SQL Server, Npgsql
ConnectionFactory, PostgreSql.
DbProviderFactory , (DbCon
nection), (DbCommand), (DbDataAdapter) .,
.
.9.1.
:
AbstractFactory (DbProviderFactory) ( ) ;
AbstractProductA, AbstractProductB (DbCommand, DbConnection) ,
;
ProductA1, ProductB1 (SqlConnection, NpgsqlConnection) ;
Client (LogSaver) , .
139
. 9.1.
140
II.
9. (Abstract Factory)
, , .
, : /, /, / ..
,
.
, .
1 .
: ? ?
.
. ,
SQL Server. SqlClient
Factory LogSaver (9.2).
9.2.
public static void Main(string[] args)
{
var saver = new LogSaver(SqlClientFactory.Instance);
var loader = new LogFileLoader(args[0]);
saver.Save(loader.Load());
}
. , .
.
1
I.
141
142
II.
DbProviderFactory : DbProviderFactories.Get
Factory1 (9.3).
9.3.
public static void Main(string[] args)
{
var saver = new LogSaver(GetDbProviderFactory());
var loader = new LogFileLoader(args[0]);
saver.Save(loader.Load());
}
private static DbProviderFactory GetDbProviderFactory()
{
const string factoryName = "System.Data.SqlClient";
return DbProviderFactories.GetFactory(factoryName);
}
.
.
, ADO.NET DbProviderFactory
.
, .
,
,
(9.4).
9.4.
class GenericAbstractFactory
{
public object Make(string id) { ... }
1
9. (Abstract Factory)
.
:
.
, , .
, .
.
1. ,
.
1
.
DI- Dependency Injection in .NET.
DI-. Service Locator (http://bit.ly/Service
LocatorPattern).
143
144
II.
2. . .
3. , .
.NET Framework
DbProviderFactory ADO.NET Create
Command(): DbCommand, CreateConnection(): DbConnection .
CodeDomProvider CreateGenerator():
ICodeGenerator, CreateCompiler(): ICodeCompiler, CreateParser():
ICodeParser.
SymetricAlgorithm CreateEncryptor():
ICryptoTransform CreateDecryptor(): ICryptoTransform.
10
(FactoryMethod)
, .
: ,
, .
.
,
, .
,
.
- LogFileReader , , LogEntry (ExceptionLogEntry SimpleLogEntry
) .
,
.
146
II.
, . LogReaderBase,
- ( Stream) ,
LogEntryParser,
LogEntry (10.1).
10.1.
public static class LogEntryParser
{
public static LogEntry Parse(string data)
{
// data
// : ExceptionLogEntry SimpleLogEntry
}
}
public abstract class LogReaderBase
{
public IEnumerable<LogEntry> Read()
{
using (var stream = OpenLogSource())
{
using (var reader = new StreamReader(stream))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
yield return LogEntryParser.Parse(line);
}
}
}
}
protected abstract Stream OpenLogSource();
}
10. (FactoryMethod)
LogReaderBase, LogImporter,
- .
-
MemoryStreamLogReader, ,
.
. OpenLog
Source ,
, . LogEntry
Parser ,
.
.
:
;
;
.
.10.1.
. 10.1.
147
148
II.
, .
:
Creator (LogReaderBase)
. ;
ConcreteCreator (LogFileReader) ,
ConcreteProduct (FileStream);
Product (Stream) , ;
ConcreteProduct (FileStream) .
,
(.10.2).
. 10.2.
,
, , Create.
,
(.10.3).
10. (FactoryMethod)
. 10.3.
.NET ,
.
switch,
. , (, ..), ,
.
, ,
, (10.2).
10.2.
static class ImporterFactory
{
private static readonly Dictionary<string, Func<Importer>> _map =
new Dictionary<string, Func<Importer>>();
static ImporterFactory()
{
_map[".json"] = () => new JsonImporter();
_map[".xls"] = () => new XlsImporter();
_map[".xlsx"] = () => new XlsImporter();
}
149
150
II.
,
:
? :
C# ,
, . - , ,
.
10. (FactoryMethod)
. Better Construction with Factories (Journal of Object
Technology, 2002. http://www.jot.fm/issues/issue_2007_07/article3.pdf).
C# (generics),
(reflection) (10.3).
10.3.
public abstract class Product
{
protected internal abstract void PostConstruction();
}
public class ConcreteProduct : Product
{
//
// .
internal ConcreteProduct() {}
protected internal override void PostConstruction()
{
Console.WriteLine("ConcreteProduct: post construction");
}
}
// Product
public static class ProductFactory
{
public static T Create<T>() where T : Product, new()
{
try
{
var t = new T();
151
152
II.
//
t.PostConstruction();
return t;
}
catch (TargetInvocationException e)
{
//
var edi = ExceptionDispatchInfo.Capture(e.InnerException);
edi.Throw();
// , !
return default(T);
}
}
}
10.4.
10.4.
var p1 = ProductFactory.Create<ConcreteProduct>();
var p2 = ProductFactory.Create<AnotherProduct>();
Create TargetInvocati
onException. new T()
T, T TargetInvocationExce
ption. , Create
ExceptionDispatchInfo1.
10. (FactoryMethod)
.
. ,
.
,
.
.
. . , , ,
.
.
, ,
.
LogReaderBase
LogFileReader.
. LogReaderBase
LogReader , FromFile
FromStream (.10.4).
LogReader
: OpenLogSource Stream FromStream From
File.
, ,
.
153
154
II.
. 10.4.
,
, . , ,
. , LogReader,
LogFileReader StreamLogReader, , OpenLogStream Func<Stream>
(10.5).
10.5. LogReader
public class LogReader
{
private readonly Func<Stream> _streamFactory;
private LogReader(Func<Stream> streamFactory)
{
_streamFactory = streamFactory;
}
10. (FactoryMethod)
155
156
II.
Func
Func<Stream> . Func<T> .
(internal)
. ,
Func<Stream>, , Func<int, string,
int, ValidationResult> factory . ,
.
vs.
-
.
, .
. C#
, . Timespan, .
, , ,
,
double, . Timespan
(10.6).
10.6.
10. (FactoryMethod)
. ,
. ,
1.
, .
,
.
,
.
. ,
, , .
.
.
, .
.
. , TaskFactory Task Parallel Library
1
, if
.
bloated constructor, , !
157
158
II.
, ..
,
.
.
, WebRequest.Create(string) LogReader,
.
. , , . , Timespan.FromSeconds, Timespan.From
Milliseconds ..
. ,
,
.
. , . ,
, .
. , ,
.
. , .
.NET Framework
.NET Framework .
: Stream.CreateWaitHandle, Security
Attribute.CreatePermission, ChannelFactory.CreateChannel,
XmlNode.CreateNavigator.
10. (FactoryMethod)
159
11
(Builder)
: ,
.
. , ,
.
,
. ,
, .
, ,
.
.
Email
. Email ,
11. (Builder)
, (attachment)
.. ,
, MailMessage .NET
Framework, Mail
MessageBuilder ( 11.1).
11.1.
public sealed class MailMessageBuilder
{
private readonly MailMessage _mailMessage = new MailMessage();
public MailMessageBuilder From(string address)
{
_mailMessage.From = new MailAddress(address);
return this;
}
public MailMessageBuilder To(string address)
{
_mailMessage.To.Add(address);
return this;
}
public MailMessageBuilder Cc(string address)
{
_mailMessage.CC.Add(address);
return this;
}
public MailMessageBuilder Subject(string subject)
{
_mailMessage.Subject = subject;
return this;
}
161
162
II.
11. (Builder)
. 11.1.
:
Builder ;
Director , ,
;
ConcreteBuilder ,
Product.
: , Product
(ConcreteBuilder). , ( Director) .
,
, Json.
. ?
? ,
Director, ?
, (.11.2).
,
. Director ( MailMessageBuilder) Build.
Builder (MailMessageBuilder)
(MailMessage).
163
164
II.
. 11.2.
.NET
.NET :
(fluent interface) .
(11.3).
, ,
.
11.3.
var result = Enumerable.Range(1, 10).Select(n => n + 1).Count();
Java
-DSL (Domain-Specific Language). ,
(11.4).
11.4. StringBuilder
public override string ToString()
{
return new StringBuilder()
.AppendFormat("Id: {0}", Id).AppendLine()
11. (Builder)
, .
, .
MailMessageBuilder
MailMessage ( 11.5).
11.5.
public static class MailMessageBuilderEx
{
public static MailMessage From(this MailMessage mailMessage,
string address)
{
mailMessage.From = new MailAddress(address);
return mailMessage;
}
public static MailMessage To(this MailMessage mailMessage,
string address)
{
mailMessage.To.Add(address);
return mailMessage;
}
public static MailMessage Cc(this MailMessage mailMessage,
string address)
{
mailMessage.CC.Add(address);
return mailMessage;
}
public static MailMessage Subject(
165
166
II.
.
:
, . Build,
.
11. (Builder)
,
. ,
.
.NET Framework, MailMessageBuilder , , ..
,
. Builder, . , IBuilder, , .
. , MailMessageBuilder
MailMessage . Build (, InvalidOperationException), To
( 11.7).
11.7. Build
public MailMessage Build()
{
if (_mailMessage.To.Count == 0)
{
throw new InvalidOperationException(
"Can't create a mail message with empty To. Please call
'To' method first");
}
return _mailMessage;
}
167
168
II.
, .
.
( 11.8).
11.8. MailMessageBuilder
public class MailMessageBuilder
{
public MailMessageBuilder(string address)
{
To(address);
}
//
, , 34. ,
.
.
. ,
. Build ,
.
( 11.9).
11.9.
public class MailMessageBuilder
{
private readonly MailMessage _mailMessage = new MailMessage();
internal MailMessageBuilder(MailMessage mailMessage)
{
_mailMessage = mailMessage;
}
public FinalMailMessageBuilder To(string address)
{
11. (Builder)
_mailMessage.To(address);
//
return new FinalMailMessageBuilder(_mailMessage);
}
//
}
public class FinalMailMessageBuilder
{
private readonly MailMessage _mailMessage;
internal FinalMailMessageBuilder(MailMessage mailMessage)
{
_mailMessage = mailMessage;
}
public MailMessage Build()
{
return _mailMessage;
}
}
Final
MailMessageBuilder, To
. , Build
.
,
.
Build InvalidOperationException
, , .
. .
169
170
II.
. , (immutable).
,
(, ) .
.NET , .NET Framework
StringBuilder, .
, 1. . 11.10
ImmutableList<int>.
11.10.
var list = ImmutableList<int>.Empty;
foreach (var element in Enumerable.Range(1, 10))
{
// list 10 !
list = list.Add(element);
}
,
,
( 11.11).
11.11.
ImmutableList<int>.Builder builder =
ImmutableList<int>.Empty.ToBuilder();
foreach (var element in Enumerable.Range(1, 10))
{
1
11. (Builder)
builder.Add(element);
}
ImmutableList<int> list = builder.ToImmutable();
.
ImmutableList<T>
. Immutable
List<T>.Builder,
ImmutableList<T>.
,
. . MailMessage
, ( 11.12).
11.12. MailMessage
public class MailMessage
{
private string _to;
private string _from;
private string _subject;
private string _body;
private MailMessage()
{}
public static MailMessageBuilder With()
{
return new MailMessageBuilder(new MailMessage());
}
public string To { get { return _to; } }
public string From { get { return _from; } }
171
172
II.
11. (Builder)
_mailMessage._subject = subject;
return this;
}
public MailMessageBuilder Body(string body)
{
_mailMessage._body = body;
return this;
}
public MailMessage Build()
{
return _mailMessage;
}
}
MailMessage
MailMessage, (
11.14).
11.14.
var mailMessage =
MailMessage.With()
.From("st@unknown.com")
.To("support@microsof.com")
.Subject("Msdn is down!")
.Body("Please fix!")
.Build();
Console.WriteLine(mailMessage.To);
, ,
, .
173
174
II.
, .
,
.
,
,
(, , , ), , JSON Xml,
Fluent API ..
.
. , .
.NET Framework
.NET Framework.
StringBuilder, UriBuilder, DbCommandBuilder DbConnectionStrin
gBuilder ADO.NET.
ImmutableList<T>.Builder, Immuta
bleDictionary<TKey, TValue>.Builder ..
Reflection.Emit: ModuleBuilder, TypeBuilder, EnumBuilder,
MethodBuilder ..
WCF : ChannelBuilder,
DispatcherBuilder, EndpointAddressBuilder ..
autofac, IoC-, .
-
, ,
- .
, .
(bit.ly/OnAutomatedTesting).
11. (Builder)
-
. , , ,
. , :
.
, ,
.
, .
, ,
. :
, (
AAA Arrange, Act, Assert).
, ,
, , .
,
LogEntryReader,
-.
-
LogEntryReader /
, -.
StreamReader ILogEntryParser (
11.5).
11.5. LogEntryReader
public interface ILogEntryParser
{
bool TryParse(string s, out LogEntry logEntry);
}
public class SimpleLogEntryParser : ILogEntryParser
{
// -
public bool TryParse(string s, out LogEntry logEntry)
{
// ...
}
}
public class LogEntryReader
{
175
176
II.
11. (Builder)
// Arrange
var memoryStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memoryStream);
sw.WriteLine("[2014/11/01][Info] This is message!");
sw.Flush();
memoryStream.Position = 0;
ILogEntryParser logEntryParser = new SimpleLogEntryParser();
var reader = new LogEntryReader(memoryStream, logEntryParser);
// Act
var entries = reader.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
LogEntry entry = entries.Single();
Assert.That(entry.EntryDateTime,
Is.EqualTo(new DateTime(2014, 11, 01)));
Assert.That(entry.Severity, Is.EqualTo(Severity.Info));
Assert.That(entry.Message, Is.EqualTo("This is message!"));
}
.
, , .
, .
, -:
, .
. Xunit
, NUnit , SetUp
(11.7).
11.7. SetUp
private LogEntryReader _classUnderTest;
[SetUp]
public void SetUp()
{
177
178
II.
SetUp
(coupling) ,
.
.
11. (Builder)
,
(11.8).
11.8.
public static LogEntryReader CreateLogEntryReader(string content)
{
var memoryStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memoryStream);
sw.WriteLine(content);
sw.Flush();
memoryStream.Position = 0;
ILogEntryParser logEntryParser = new SimpleLogEntryParser();
return new LogEntryReader(memoryStream, logEntryParser);
}
[Test]
public void Test_Stream_With_One_Entry()
{
// Arrange
var classUnderTest = CreateLogEntryReader(
"[2014/11/01][Info] This is message!");
// Act
var entries = classUnderTest.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
LogEntry entry = entries.Single();
Assert.That(entry.EntryDateTime,
Is.EqualTo(new DateTime(2014, 11, 01)));
Assert.That(entry.Severity, Is.EqualTo(Severity.Info));
Assert.That(entry.Message, Is.EqualTo("This is message!"));
}
179
180
II.
,
. CreateLogEntryReader
,
.
, .
SetUp
, ,
.
.
.
. . , , .
300 , 300 .
, ,
. ,
, .
Test Fixture
,
.
ILogEntryParser
,
.
.
,
.
Fixture ,
11.9.
11.9. LogEntryReaderFixture
// LogEntryReader
internal class LogEntryReaderFixture
{
private ILogEntryParser _parser = new SimpleLogEntryParser();
11. (Builder)
181
182
II.
// Arrange
var classUnderTest = new LogEntryReaderFixture()
.WithParser(new SimpleLogEntryParser())
.WithStreamContent("[2014/11/01][Info] This is message!")
.LogEntryReader;
// Act
var entries = classUnderTest.Read().ToList();
// Assert
Assert.That(entries.Count, Is.EqualTo(1));
}
LogEntryReaderFixture
. ,
.
Fixture , ,
AutoFixture,
. AutoFixture , . AutoFixture IoC-,
Unity, StructureMap ., .
github: github.com/AutoFixture.
-
, .
, - ,
LogEntry.
, .
-
-
.
, ,
11. (Builder)
. NUnit TestCaseSource,
, :
(11.11).
11.11.
[TestCaseSource("SimpleLogEntrySource")]
public LogEntry Test_SimpleLogEntry_Parse(string logEntry)
{
// Arrange
var parser = new SimpleLogEntryParser();
// Act
LogEntry result = parser.Parse(logEntry);
// Assert
return result;
}
, Simple
LogEntrySource (11.12).
11.12.
//
private static TestCaseData Entry(string entry)
{
return new TestCaseData(entry);
}
private static IEnumerable<TestCaseData> SimpleLogEntrySource()
{
yield return
Entry("[2014/01/12] [DEBUG] message")
.Returns(new SimpleLogEntry(DateTime.Parse("2014-01-12"),
Severity.Debug, "message"));
yield return
Entry("[2015/01/12] [Info] another message")
183
184
II.
.Returns(new SimpleLogEntry(DateTime.Parse("2015/01/12"),
Severity.Info, "another message"));
yield return
Entry("corrupted message")
.Throws(typeof(InvalidOperationException));
}
NUnit TestCaseData, ,
(
TestCaseData), ( Returns)
( Throws).
Entry,
.
,
. -
.
-
- http://bit.ly/Parametrized
UnitTests.
III
12. (Adapter)
13. (Facade)
14. (Decorator)
15. (Composite)
16. (Proxy)
186
III.
.
, Main,
, .
, , .
, ,
. , , ,
, . ,
, , . .
,
.
.
,
.
. ,
, ,
.
.
, c
.
, .
.
,
.
:
III.
.
.
.
,
TCP , 1. , WCF .NETRemoting,
-,
.
,
. WCF TCP- ,
-, .
187
12
(Adapter)
: ,
. .
. , .
.
-.
, , .
SqlServer,
SqlServerLogSaver. , , Elasticsearch. , ElasticsearchLogSaver,
, ,
(.12.1).
12. (Adapter)
( ), ( ).
ILogSaver. , , , (.12.2).
. 12.2. -
. , , ,
(12.1).
189
190
III.
12.1. SqlServerLogSaverAdapter
public class SqlServerLogSaverAdapter : ILogSaver
{
private readonlySqlServerLogSaver _sqlServerLogSaver =
new SqlServerLogSaver();
public void Save(LogEntrylogEntry)
{
var simpleEntry = logEntry as SimpleLogEntry;
if (simpleEntry != null)
{
_sqlServerLogSaver.Save(simpleEntry.EntryDateTime,
simpleEntry.Severity.ToString(),
simpleEntry.Message);
return;
}
varexceptionEntry = (ExceptionLogEntry) logEntry;
_sqlServerLogSaver.SaveException(
exceptionEntry.EntryDateTime, exceptionEntry.Message,
exceptionEntry.Exception);
}
}
,
.
.12.3.
Client
void Request() {
adaptee.SpecificRequest()
}
Target
Adaptee
+SpecificRequest()
Adapter
+Request()
. 12.3.
12. (Adapter)
:
Target (ILogSaver) ,
;
Adaptee (SqlServerLogSaver) , ;
Adapter (SqlServerLogSaverAdapter) -, ;
Client ( ILogSaver) , .
, , . ,
.
. .
,
, .
.
,
. ,
(.12.4).
, ,
.
C# , .
(.12.5).
191
192
III.
. 12.4.
. 12.5.
, . , ,
.
.
.
12. (Adapter)
, . ,
LogSaver, , .
, , , .
1. IAsyncLogSaver .
2. AsyncLogSaverAdapter,
IAsyncLogSaver, .
3. LogSaver ,
.
4. .
5. AsyncLogSaverAdapter .
(.12.6).
. 12.6.
193
194
III.
, ,
. AsyncLogSaverAdapter , (
12.2).
12.2. AsyncLogSaverAdapter
public interface IAsyncLogSaver
{
Task SaveAsync(LogEntrylogEntry);
}
public class AsyncLogSaverAdapter : IAsyncLogSaver
{
private readonlyLogSaver _logSaver;
public AsyncLogSaverAdapter(LogSaverlogSaver)
{
_logSaver = logSaver;
}
public Task SaveAsync(LogEntrylogEntry)
{
return Task.Run(() => _logSaver.Save(logEntry));
}
}
C# . , LINQ- fromsinobj
Select, Where, OrderBy ., .
foreach
GetEnumerator, boolMoveNext Current. async/await GetA waiter
12. (Adapter)
(ducktyping) .
195
196
III.
customCollection.Insert(value);
}
}
CustomCollectionExtensions
, CustomCollection ( 12.4).
12.4. CustomCollection
//
// !
varcc = newCustomCollection {42};
.
.
, , .
.
.
,
.
.NET Framework
TextReader/TextWriter Stream / /.
BinaryReader/BinaryWriter /.
ReadonlyCollection<T> (IList<T>)
(IReadonlyCollection<T>).
LINQ- ( IQueryProvider)
,
IQueryProvider.
13
(Facade)
: .
, .
.
ADO.NET , (output)
. ,
. ,
, , .
,
, ,
.
,
SQLServer (.13.1).
198
III.
. 13.1. SQLServer
, ,
. SqlServerFacade
, : ,
ADO.NET.
.13.2.
. 13.2.
13. (Facade)
:
Facade (SqlServerFacade) , ;
Client , ,
.
,
,
. , . ,
; ,
.
, .
. , . .
.
, ,
.
.
, . 1
.
,
. ,
1
12.
199
200
III.
, ,
.
, SqlServer SqlServer
Provider Configuration,
( 13.1).
13.1.
public static IDbCommandCreateCommand(Configuration config) {...}
. (coupling) , ,
, .
,
. ,
(log4net, NLog, .NETTraces)
. , ,
, .
.NET Framework
XmlSerializer , .
ThreadPool.QueueUserWorkItem .
Parallel TPL . ,
(partitioning) Task<T> .
System.Runtime.CompilerServices.RuntimeHelpers
, ..
System.Console -.
14
(Decorator)
: .
.
,
. , , 1, , ,
?
, .
.
1
.
, . , .
. ,
.
202
III.
.
Windows-,
,
1.
.
, , (throttling).
,
.
( 14.1).
14.1.
public interface ILogSaver
{
Task SaveLogEntry(string applicationId, LogEntrylogEntry);
}
public sealed class ElasticsearchLogSaver : ILogSaver
{
public Task SaveLogEntry(string applicationId, LogEntrylogEntry)
{
// Elasticsearch
return Task.FromResult<object>(null);
}
}
public abstract class LogSaverDecorator : ILogSaver
{
protected readonly ILogSaver _decoratee;
ApplicationInsights
Microsoft, , . ApplicationInsights API
- , , .
14. (Decorator)
203
204
III.
// ! !
throw new QuotaReachedException();
}
private boolQuotaReached(string applicationId)
{
// ,
}
private void IncrementUsedQuota()
{
//...
}
}
(ThrottlingLogSaverDecorator)
, , ( decoratee).
,
. QuotaReached
Exception, 1.
ILogSaver
. ,
, ( 14.3).
14.3.
ILogSaverlogSaver = new ThrottlingLogSaverDecorator(
new ElasticsearchLogSaver());
var controller = new LogSaverController(logSaver);
1
- , HTTP,
429 TooManyRequests,
.
14. (Decorator)
.14.1.
. 14.1.
:
Component (ILogSaver) ,
;
Client (LogSaverController) , ;
ConcreteComponent (ElasticsearchLogSaver)
;
Decorator (LogSaverDecorator) , ;
ConcreteDecoratorA (ThrottlingLogSaverDecorator) , .
vs.
-
.
205
206
III.
ElasticsearchLogSaver
(.14.2).
. 14.2.
, . ThrottleElasticsearchLog
Saver
ILogSaver.
ILogSaver,
.
, .
, .
, , ( 14.4).
14.4.
//
public class TraceLogSaverDecorator : LogSaverDecorator
{
publicTraceLogSaverDecorator(ILogSaver decoratee) : base(decoratee)
{}
14. (Decorator)
.
,
Main. IoC- .
, , ( 14.5).
14.5. ILogSaver
public static class LogSaverFactory
{
public static ILogSaverCreateLogSaver()
{
207
208
III.
return
new ThrottlingLogSaverDecorator(
new TraceLogSaverDecorator(
new ElasticsearchLogSaver()));
}
}
, .
.
, , .
. ,
.
. , , . , ,
.
. , ,
. , , , .
IoC-, Unity StructureMap, (Interceptors). IL- (IntermediateLanguage) ,
.
. ,
( ?)
Unityinterceptors .
14. (Decorator)
.
, . , .
, .
:
;
;
;
;
/, ..
,
, .
.
, ,
ApplicationInsights .
, . Task
(http://bit.ly/CachedDecorator).
.NET Framework
.NETFramework . /, .
209
210
III.
System.IO.BufferedStream /.
System.IO.Compression.GZipStream, System.IO.Compression.Def
lateStream /.
System.CodeDom.Compiler.IndentedTextWriter System.IO.TextWriter.
System.Reflection.TypeDelegator System.Type.
System.Collections.SortedList.SyncSortedList ,
SortedList
lock.
/ .NET
/ ,
.
TextReader, StreamReader, StringReader .
,
.
System.IO,
(.14.3).
/ .
/: System.IO.Stream
FileStream, MemoryStream, NetworkStream .
/ .
(BufferedStream, GZipStream .).
/, , ..
, WCF,
.
( TextReader/TextWriter Binary
Reader/BinaryWriter).
/,
.
. File ,
.
/ ,
(File.OpenRead, File.OpenWrite, File.Create, File.Append
Text, File.OpenText .).
+ReadByte(): int
+WriteBite(in b: byte)
Stream
DataStream
+Write(in c: char)
+WriteLine(in s: string)
TextWriter
. 14.3. System.IO
+BaseStream: Stream
StreamDecorator
+Read(): int
+ReadLine(): string
TextReader
14. (Decorator)
211
212
III.
/ ,
. TextReader/TextWriter
, , StreamReader/
StreamWriter, /,
StringReader/StringWriter, .
,
/, TextReader/TextWriter
1 ( 14.6).
14.6. LogEntryParser
public class LogEntryParser
{
private readonly TextReader _reader;
public LogEntryParser(TextReader reader)
{
_reader = reader;
}
public IEnumerable<LogEntry> Parse()
{
string line;
while ((line = _reader.ReadLine()) != null)
{
yield return ParseLine(line);
}
}
private LogEntry ParseLine(string line)
{
1
StreamReader
.
.
14. (Decorator)
213
15
(Composite)
:
. .
, ,
. ,
.
,
.
- -, , .
: Severity , DateTime
. ,
.
15. (Composite)
DDD1 ,
(.15.1).
-,
.
LogImportRule . (SingleLogImportRule)
Func<LogEntry, bool>, . CompositeLogImportRule
. AndCo
mpositeLogImportRule OrCompositeLogImportRule,
.
ImportRuleFactory
( 15.1).
15.1.
public static class LogRuleFactory
{
public static LogImportRule Import(Func<LogEntry, bool> predicate)
{
return new SingleLogImportRule(predicate);
}
public static LogImportRule Or(this LogImportRule left,
Func<LogEntry, bool> predicate)
{
return new OrLogImportRule(left, Import(predicate));
}
public static LogImportRule And(this LogImportRule left,
Func<Log
Entry, bool> predicate)
{
return new AndLogImportRule(left, Import(predicate));
}
215
. 15.1. -
+ShouldImport(LogEntry): bool
CompositeLogImportRule
+ShouldImport(LofEntry): bool
LogImportRule
216
III.
15. (Composite)
217
218
III.
EntryDateTime = DateTime.Now.AddDays(-5),
Severity = Severity.Debug
};
Assert.IsTrue(rule.ShouldImport(logEntry));
,
, .
.15.2.
. 15.2.
:
Component (LogImportRule) . (ShouldImport), / ;
Composite (CompositeLogImportRule) ,
;
Leaf (SingleLogImportRule) ,
;
Client , .
. , -
15. (Composite)
Component: /
.
, . ,
,
Add/Remove Component.
, Leaf, ,
1.
,
.
.
.
,
Add/Remove .
Add/Remove .
, ,
/ CompositeComponent.
CompositeComponent,
Component
.
Add/Remove .
, , Add/Remove .
Leaf InvalidOpera
tionException ,
Add .
, . , ,
.
1
IV.
219
220
III.
, .
,
.
.NET Framework
, . .
System.Win
dows.Forms.Control WindowsForms, FrameworkElement WPF,
CompositeControl ASP.NET.
Xml XmlNode XElement.
Expression.
16
(Proxy)
:
.
.
, ,
.
, . .
-
,
.
, WCF, ASP.NET WebAPI
.NET Remoting, .
222
III.
WCF ILogSaver , ,
(ServiceContract + OperationContract Data
Contract + DataMember). ,
(binding), (contracts)
(endpoint). - ( -) , ILogSaver
1 ( 16.1).
16.1. - WCF
class LogSaverClient : ClientBase<ILogSaver>, ILogSaver
{
public void SaveLogEntry(LogEntrylogEntry)
{
// Channel
// ILogSaver
Channel.SaveLogEntry(logEntry);
}
}
//...
publicvoidSaveLogEntryAtTheBackend(LogEntrylogEntry)
{
var proxy = newLogSaverClient();
proxy.SaveLogEntry(logEntry);
proxy.Close();
}
ClientBase<T> WCF, ,
. LogSaverClient , WCF- ,
ILogSaver .
1
, , . ,
.
16. (Proxy)
.16.1.
. 16.1.
:
Client , ,
;
Subject (ILogSaver) ;
Proxy (LogSaverClient) -, , ;
RealSubject ,
.
,
.
.
.
, .
, .
,
. -
223
224
III.
. - 15
.
, - ,
. 1990- 2000-,
.
, DCOM .NETRemoting.
,
. , , ,
1. , WCF ASP.NETWebAPI, - . ISomeInter
face, ,
.
, ChannelBase<T> WCF,
, , -!
vs.
.
.
.
1
, . ILogSaver
. .
ILogSaver .
16. (Proxy)
,
. -
, ,
.
Lazy<T>
Lazy<T> ,
- ( 16.2).
16.2. Lazy<T>
public interface IHeavyweight
{
void Foo();
}
//
public class Heavyweight : IHeavyweight
{
public void Foo()
{}
}
// ,
//
public class HeavyweightProxy : IHeavyweight
{
private readonly Lazy<Heavyweight> _lazy = new Lazy<Heavyweight>();
public void Foo()
{
_lazy.Value.Foo();
}
}
225
226
III.
- ,
: ,
.
.NET Framework
-. .NET
Framework -: ChannelBase<T> WCF,
RealProxy .NETRemoting.
- ORM-. ORM
(Object-RelationalMapping - ),
NHibernate EntityFramework,
-. ORM (dataentities),
SQL- .
IV
17.
18. /
19.
20.
21.
22.
228
IV.
. , ,
. (
?),
. ,
,
,
.
,
SOLID. 1990-
C++ Report .
, , - .
SOLID.
Agile Software Development, Principles, Patterns, and Practices,
C# , C#.
(SOLID) ,
.
20 , , ++. ,
,
++ .
-
. , SOLID-
,
C# Java.
SOLID- ,
, ( )
,
.
IV.
229
230
IV.
17
.
(Single-Responsibility Principle, SRP): ( . , . 2006).
.
, ,
. - , ,
.
,
.
, . ,
,
.
. ()
, ,
232
IV.
. , .
: (, , )
, . ? . , , .
-
(essential complexity)
(accidental complexity).
. , .
, , ,
- - , ,
- .
. , -
.
: , -
, Windows-
-. SRP : Windows
Forms-, WCF-, Windows-, . , SRP
, , .
SRP,
. ,
, ,
. ,
, ,
.
17.
SRP
.
200, . 57
. , .
.
. , , ,
.
,
.
- ,
. ,
, .
SRP ,
. ,
, ?
? ?
SRP ,
. SRP,
40 .
SRP,
. SRP,
, .
. , ,
. ,
233
234
IV.
. ,
, , ,
, .
- .
- Elasticsearch .
.
, (17.1).
17.1. -
public class LogImporter
{
public void ImportLogs()
{
string[] logFileNames = GetListOfFilesFromAppConfig();
foreach (var file in logFileNames)
{
var logEntries = ReadLogEntries(file);
SaveLogEntries(logEntries);
}
}
private string[] GetListOfFilesFromAppConfig()
{
//
}
private IEnumerable<string> ReadLogEntries(string fileName)
{
//
}
private void SaveLogEntries(IEnumerable<string> entries)
{
17.
235
236
IV.
,
. ILogFileListProvider
.
,
LogImporter .
,
!
2. -.
, .
LogImporter ?
! : /
17.
, , .. -
. LogEntryParser ( 17.3).
17.3. LogEntryParser
Class LogEntryParser
{
public bool TryParse(string line, out LogEntry logEntry)
{
// .
// true, .
// false,
//
//
}
}
public class LogImporter
{
private readonly LogEntryParser _parser = new LogEntryParser();
public void ImportLogs()
{
foreach (varfilein _logFileNames)
{
IEnumerable<LogEntry>logEntries = ReadLogEntries(file);
SaveLogEntries(logEntries);
}
}
private IEnumerable<LogEntry> ReadLogEntries(string fileName)
{
//
using (var file = File.OpenText(fileName))
{
237
238
IV.
LogImporter ,
.
3. . ,
-.
, . ,
-, .
LogEntryParser
( 17.4).
17.4. - LogEntryParser
[TestFixture]
public class LogEntryParserTests
{
[TestCase("2014-01-12 [DEBUG] message", Result = Severity.Debug)]
17.
{
LogEntry logEntry;
parser.TryParse(line, out logEntry);
return logEntry;
}
}
LogEntryParser
. NUnit1 , -
.
Parse LogEntryParser.
, . LogEntry
Parser ,
.
.
1
-: http://bit.ly/ParametrizedUnitTests.
239
240
IV.
. LogImporter : -. ,
-
(17.5).
17.5. LogImporter
[TestFixture]
public class LogImporterIntegrationTests
{
[Test]
public void ImportFileWithTenEntries()
{
string fileName = "10Entry.log";
// Cleanup
TryRemoveExistingEntries(fileName);
// Arrange
var importer = new LogImporter(new[] {fileName});
// Act
importer.ImportLogs();
// Assert
Assert.That(GetEntriesCountForLogFile(fileName), Is.EqualTo(10));
}
. : , ,
(Arrange, Act, Assert, AAA) .
- ,
.
, : LogImporter (.17.1).
17.
. 17.1. LogImporter
, ,
.
.
LogImporter :
- .
, . ,
.
SRP
SRP :
. - , , WCF Windows-.
-,
;
(lowcohesion). //
. ,
, ;
. / , (
). //
;
241
242
IV.
. /
. ,
, . .
,
.
, . , ,
.
.
. , ,
.
18
/
;
.
. 1
/ (Open-Closed Principle, OCP):
(, , ..) ,
( . ,
. 2006).
. ,
.
, ,
, .
. ,
1
. ! . .: , 2006.
244
IV.
, .
, .
.
, .
/ SOLID-. , . , ,
1, .
/
- 1988 2, .
: (, ,
..) , . , .
. ,
. , , . , .
.
.
, , DLL EXE-,
.
1
.NET- Fabulousa
dventuresincoding,
stackoverflow.com .
- (-, 2005).
18. /
, /
(pluggable architecture) .
,
. An Open and Closed
Case1 , ( /
1996 43).
, ,
, .
:
, . .
, . ,
.
,
. , (
) . ,
,
( ).
/?
, : ,
, . , ,
. ,
. .. , , ,
:
, .
1
245
246
IV.
, , , .
?
, ,
, . - , .
( ) , , ( ').
. 18.1.
,
. - 12 ,
:
, , , , .
18. /
, :
/,
, . - , ,
1.
/
OCP: .
, , ( , ),
. ,
. .
?
-, . ()
, ,
. ,
. String
, IString.
(information hiding) , /. (
implementation hiding)
,
( . 2004).
, . :
. , .
.
1
: !
247
248
IV.
: , ; ,
.
-, .
. ,
.
/
/
-.
:
-;
,
- .
,
.
pull-1 LogImporter.
push- ,
.
, LogImporter
.
LogFileReader, -
. - .
1
pull- push- 5, .
18. /
,
. C# .
IObservable<string>1, push-
( 18.1).
18.1. LogFileReader
public class LogFileReader : IObservable<string>
{
private readonly string _fileName;
public LogFileReader(string fileName)
{
_fileName = fileName;
}
public virtual IDisposable Subscribe(IObserver<string> observer)
{
using (var file = File.OpenText(_fileName))
{
string line = null;
while ((line = file.ReadLine()) != null)
{
observer.OnNext(line);
}
}
observer.OnCompleted(); return Disposable.Empty;
}
}
IObservable<T>
5.
249
250
IV.
LogFileReader ,
LogImporter
( 18.2).
18.2. LogImporter1 IObservable<string>
public class LogImporter
{
private readonly IObservable<string> _logFileReader;
private readonly LogEntryParser _parser = new LogEntryParser();
public LogImporter(string logFile)
{
_logFileReader = new LogFileReader(logFile);
}
public void ImportLogs()
{
_logFileReader.Subscribe(ProcessString);
}
private void ProcessString(string line)
{
LogEntry logEntry;
if (_parser.TryParse(line, out logEntry))
{
LogSaver.SaveEntry(logEntry);
}
}
}
LogImporter
_logFileReader. (Reactive Extensions, Rx)
IObserver<T>,
1
17 LogImporter - .
LogImporter .
18. /
LINQ-. push- , ProcessString,
, IObservable<T>1.
LogImporter
IObservable<string> .
. ,
.
LogFileReader
, (.18.2).
FileSystemWatcher2.
. 18.2. -
, /
, .
1
Reactive Extensions
- Introduction to Rx
introrx.com.
FilSystemWatcher
.
251
252
IV.
-
. LogEntryParser,
LogImporter.
, , . ,
.
,
. , ,
. -, .
LogEntryParser ,
, . LogImporter
( 18.3).
18.3. LogEntryParser
public class LogImporter
{
//
// private readonly LogEntryParser _parser
//
= new LogEntryParser();
18. /
. 18.3. LogEntryParser
. (supple)
, .
.
/ -
. LogEntryPar
ser.Create , /.
(, )
BackendLogEntryParser PostgreLogEntryParser
(18.4).
18.4. LogEntryParser.Create
public abstract class LogEntryParser
{
public static LogEntryParser Create(string fileName)
{
if (fileName.StartsWith("Server"))
{
return new BackendLogEntryParser(fileName);
}
if (fileName.StartsWith("Postgre"))
{
253
254
IV.
: -
/ -
(18.5).
18. /
18.5. DrawShape
public static void DrawShape(Shape shape)
{
switch(shape.ShapeType)
{
case ShapeType.Circle:
DrawCircle((Circle)shape);
break;
case ShapeType.Square:
DrawSquare((Square)shape);
break;
case ShapeType.Rectangle:
DrawRectangle((Rectangle)shape);
break;
default:
throw new InvalidOperationException(" ");
}
}
,
. - , Draw (18.5).
18.6. - DrawShape
public static void DrawShape(Shape shape)
{
shape.Draw();
}
, switch Draw
Shape . /, !
, , ,
, GetArea?
255
256
IV.
Shape
(breaking change) .
, ,
.
-
,
.
.
Shape Accept, IShapeVisitor,
Visit (18.7).
18.7.
public interface IShapeVisitor
{
void Visit(Circle circle);
void Visit(Square square);
void Visit(Rectangle rectangle);
}
public abstract class Shape
{
public abstract void Accept(IShapeVisitor visitor);
}
public class Circle : Shape
{
public override void Accept(IShapeVisitor visitor)
{
visitor.Visit(this);
}
}
GetArea IShapeVisitor ShapeEx (
18.8).
18. /
18.8.
public class ComputeAreaVisitor : IShapeVisitor
{
public double Area { get; private set; }
public void Visit(Circle circle)
{
Area = Math.PI * Math.Sqrt(circle.Radius);
}
public void Visit(Square square)
{
Area = Math.Sqrt(square.X);
}
public void Visit(Rectangle rectangle)
{
Area = rectangle.X * rectangle.Y;
}
}
public static class ShapeEx
{
public static double GetArea(this Shape shape)
{
var visitor = new ComputeAreaVisitor();
shape.Accept(visitor);
return visitor.Area;
}
}
// -
Shape shape = GetShape();
var area = shape.GetArea();
257
258
IV.
. ,
,
. ,
, 1.
.
.
.
,
.
/
/ .
. , , .
. (downcasting), .
.
OCP? /
/.
OCP:
.
OCP? , , , , .
1
,
, 6.
18. /
.
, .
Expression Problem1.
,
. ,
.
, (discriminate dunions)
.
: http://c2.com/cgi/
wiki?ExpressionProblem.
259
19
, .
, ?
(Liskov Substitution Principle, LSP):
( .
, . 2006).
... o1 S o2 T ,
P, T, P
o2 o1, S (subtype) T ( .
. 1988).
.
/ .
, .
-
19.
, ( 1). , .
1. ?
2. ?
(IS-A Relationship)
. , ,
, . (Subtype Inheritance),
. 12 (!) , ( ), IS-A, Can-Do ( ) ..
-
,
.
,
, .
,
. ,
,
.
c2.com2: .
, ,
.
1
(friendship relationship) ++ .
C# .
. .
Wiki,
. Liskov
Substitution Principle (http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple).
261
262
IV.
, , ,
.
- (Streams), (Enumerables),
, ..
, ,
: null,
,
( ), .
: ,
,
. , , ,
, ,
.
( )
, ,
.
?
:
. ,
-
;
- 1.
(http://c2.com/cgi/wiki?LiskovSubstitu
tionPrinciple).
19.
:
.
, . ,
, , ,
, , ,
?
, ,
. ( ) .
.
,
Rectangle Square (.19.1)?
. 19.1. ?
, ,
.
(): .
(): ,
.
263
264
IV.
, . ,
. , Width Height ! (
Width Height ,
,
.)
, .
,
! ,
(immutable), ,
. ,
!
C#. , IEnumerable<string> IEnumerable<object>.
, .
. -,
,
. -, - : , .
-, , ,
, (sealed)1
.
, /
,
.
, .
.
19.
,
, (.
- , 16.1).
,
. (
!), - ( , BCL?)
( !).
, ,
, , .
, ,
, , . , .
1. (
).
2. (
, ).
3. ( ).
4. , .
,
, .
,
. ,
265
266
IV.
InvalidOperationException NotSupportedException
, ,
. ,
.
, LSP , ImmutableList<T>
ReadOnlyCollection<T> IList<T>, NotSupportedException.
, .
IList<T> (, ICollection<T>) , Add
:
IsReadOnly False!
/, Read/Write , CanRead/CanWrite False.
. , ICollection<T>, ICollectionContract<T>.
Add IList<T> ICollection<T>
, .
Add .
ICollection<T> , .
, Add
1. (sets)
, , Add HashSet<int>
.
,
, ,
! InvalidOp
erationException, ,
,
.
,
T S , S
T (T S). ,
- ? ,
, , S T?
19.
,
. , ! ,
, .
, -,
.
(subtype inheritance)
, .
( ),
( ),
. (private inheritance),
-
!
. Eiffel, ,
, .NET-
.
C# (explicit interface implementation)
: ,
( 19.1).
19.1.
var list = new List<int> { 42 }.AsReadOnly();
//list.Add(42); // !
((IList<int>)list).Add(42); //
IList<int>list2 = list; // , !
list2.Add(42); //
, C#
.
:
,
.
, Eiffel
, .
267
268
IV.
Socket, IDis
posable Dispose
Close ( 19.2).
19.2.
Socket s = CreateSocket();
s.Dispose(); // .NET 4.0
((IDisposable)s).Dispose(); // OK
s.Close(); // OK
Framework Design Guidelines1
Dispose Pattern Guidelines:
.
++ ,
C#. , ++
, .. , ++
( ),
. ++ :
( ),
( / ).
++ .
-
.
- , .
/ :
, , ,
, .
, - .
1
Abrams B., Cwalina K. Framework Design Guidelines, 2nd Ed. Addison-Wesley Profes
sional, 2008.
19.
- , ,
, . LINQ (Language Integrated
Query) . LINQ
, IEnumerable<T>. , ,
yieldreturn, XML-,
.
, Enumerable , Count(), ElementAt(),
Last() ., , Collection<T>,
List<T> ..
Enumerable.Count()
19.3.
19.3. Count
public static int Count<TSource>(this IEnumerable<TSource> source)
{
var collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count;
var collection = source as ICollection;
if (collection != null) return collection.Count;
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (e.MoveNext()) count++;
}
return count;
}
Count() (,
269
270
IV.
, ICollection).
, ICollection,
, ,
ICollection.
.NETFramework Count,
ICollection, Lookup<T> ( 19.4).
19.4. Count Lookup
var lookup = Enumerable.Range(1, 10000).ToLookup(x => x);
Console.WriteLine(lookup.Count); // (1)1
Console.WriteLine(lookup.Count()); // (n)
lookup.Count , .
lookup.Count() , , .
, :
.
- ( 19.5).
19.5. LogEntryParser
public abstract class LogEntryParser
{
public abstract bool TryParse(string line, out LogEntry logEntry);
}
1
- .
, . (1) ,
. O(n)
: .
(http://ru.wikipedia.org/wiki/_) .
19.
,
. true
false .
logEntry .
.
, null line. ,
.
. ,
, (19.6).
19.6. LogEntryParser
public class LogEntryParserException : Exception
{}
[ContractClass(typeof (LogEntryParserContract))]
public abstract class LogEntryParser
{
/// <summary>
///
/// <paramref name="logEntry"/>
/// </summary>
/// <exception cref="LogEntryParserException">
/// ,
/// .
/// </exception>
public abstract bool TryParse(string line, out LogEntry logEntry);
}
[ContractClassFor(typeof (LogEntryParser))]
abstract class LogEntryParserContract : LogEntryParser
{
public override bool TryParse(string line, out LogEntry logEntry)
{
271
272
IV.
Contract.Requires(line != null);
Contract.Ensures(!Contract.Result<bool>() ||
Contract.ValueAtReturn(out logEntry) != null,
" True, logEntry
null");
throw new NotImplementedException();
}
}
,
, , .
LogEntryParser .
, LogEntryParserException
. ,
() - ( 19.7).
19.7. TryParse
public class IncorrectLogEntryParser : LogEntryParser
{
public override bool TryParse(string line, out LogEntry logEntry)
{
if (LineIsIncorrect(line))
{
// ! LSP!
throw new FormatException("Can't parse the line!");
}
// ...
}
}
TryParse false null
line. Argument
NullException ContractException ( 19.8).
19.8. TryParse
public override bool TryParse(string line, out LogEntry logEntry)
{
19.
logEntry = null;
// , line == null!
// LSP!
if (string.IsNullOrEmpty(line))
return false;
// ...
}
TryParse true, logEntry ( 19.9).
19.9. TryParse
public override bool TryParse(string line, out LogEntry logEntry)
{
logEntry = null;
// logEntry null! LSP!
return true;
// ...
}
.
, , .
LSP
LSP .
,
: , , , .
,
.
,
,
273
274
IV.
.
: , . , .
, ,
:
, .
,
.
,
, :
/ .
,
-,
. , , .
.
Barbara Liskov and Jannette Wing. A Behavioural Notion of Subtyping (http://web.
cse.ohio-state.edu/~neelam/courses/788/lwb.pdf). ,
, ,
, .
c2.com http://c2.com/cgi/wiki?Li
skovSubstitutionPrinciple. , ,
.
Programming Stuff. (
http://bit.ly/DbCBasics).
. , , , , .
20
,
; ,
.
(Interface Segregation Principle, ISP):
, (.
, . 2006).
. ,
, -
. ,
, ,
, ,
.
.
. ,
.
276
IV.
, .
, . , ,
.
,
, .
. , , ,
. ,
, .
,
.
, .
, .
.
. ,
, .
.
.
,
. , :
20.
;
- ( );
( ,
, );
( , , ,
: , , ..).
,
. , . Dependency Injectionin .NET
(http://bit.ly/DependencyManagement).
: , .
. ,
. ( ),
( 20.1).
20.1.
277
278
IV.
IEnumerable<T>,
, List<T>.
-, Stream, MemoryStream.
, Configuration (-), IConfi
gurationProvider, Read
Configuration.
. ,
IEnumerable<T>, ,
. ,
Count() , , . (implicit
coupling) ,
,
.
20.
, , . , , ,
?
, , CRUD-1.
ISP? ! , . ,
.
, 11
, ISP .
SRP ISP.
(cohesive)
, .
(coupling) , ,
.
. , ,
.
2
. ,
SqlServerLogSaver Elastic
searchLogSaver. -,
ILogSaver (.20.1).
1
12.
279
280
IV.
. 20.1.
SqlServerLogSaver ElasticsearchLogSaver
: .
(explicit interface implementation), ( 20.2).
20.2. ILogSaver
public class SqlServerLogSaver : ILogSaver
{
public void Save(DateTime dt, string severity, string message) {...}
public void SaveException(DateTime dt, Exception e) {...}
// !
ILogSaver.Save(LogEntry logEntry)
{
var exception = logEntry as ExceptionLogEntry;
if (exceptiony != null)
{
SaveException(exception.EntryDateTime, exception.Exception);
}
else
{
20.
Save(logEntry.EntryDateTime, logEntry.Severity.ToString(),
logEntry.Message);
}
}
}
. ,
SqlServerLogSaver Save(LogEntry),
( 20.3).
20.3.
var saver = new SqlServerLogSaver();
LogEntry logEntry = GetLogEntry();
saver.Save(logEntry); //
ILogSaver logSaver = saver;
logSaver.Save(logEntry); // OK
. , , , .
, .
17, . LogEntryParser
TryParse, .
Parse,
( 20.4).
20.4.
//
var parser = new LogEntryParser();
LogEntry logEntry;
if (parser.TryParse(stringEntry, outlogEntry))
{
281
282
IV.
SaveEntry(logEntry);
}
//
//
varparser = newLogEntryParser();
varlogEntry = parser.Parse(sampleStringEntry);
Assert.That(logEntry.Severity, Is.EqualTo(Severity.Debug));
.
, .
ISP
ISP .
,
.
.
, :
..
, ,
.
. , ,
, . ,
,
.
.
, ,
20.
,
/.
, .
:
, -, .
, , .
, .
.
283
21
,
!
(Dependency Inversion Principle, DIP):
.
. .
( . , . 2006).
, (Dependency Injection). ,
, , .
, , -
.
21.
1.
, ( 21.1).
21.1. DIP
interface IFileReader
{
string ReadLine();
}
class LogEntryParser
{
public LogEntryParser(IFileReader fileReader)
{}
public IEnumerable<LogEntry> ParseLogEntries()
{}
}
class FileReader : IFileReader {...}
(loosely couplied) ,
LogEntryParser IFileReader
. ,
/.
, , .
( ),
. GOTO ,
1
, interface.
,
.
285
286
IV.
.
,
.
LogEntryParser
, . , List<T> IList
GrowingPolicy, , String
IInterningPolicy,
! , ,
.
,
.
, ,
.
, ,
.
,
. , ( . 2006)
(.21.1).
. , , .
, , - .
.
,
, .
21.
. 21.1.
287
288
IV.
, , , ,
( . - . 2010).
.
LogImporter (.21.2). LogImporter LogEntryParser , . , .
, 1.
. 21.2. LogImporter
, . -
- .
, .
-, .
2. 1
1,
10.
5.
21.
,
.
, ,
, .
MVC (Model View Controller,
) (.21.3). : -,
,
.
. 21.3. 1
,
. , ? ,
UML , . ,
.
.
289
290
IV.
- .
,
. , ,
. MVC , , . , -,
, WPF
Windows Forms.
, MVP
(Model View Presenter, ) (.21.4).
. 21.4.
MVP MVC , , ,
. (IView),
21.
(, ), .
,
MVx MVVM (Model View View Model, ). MVVM MVP, IView
, (Data Binding).
(.21.5).
. 21.5.
:
,
.
, .
(21.2).
21.2. DIP
// Reporter.dll
public interface IReportFormatter
{
291
292
IV.
21.
DIP
,
.
IoC-1 , , .
, . : DIP
: . , ;
.
1
293
294
IV.
,
.
, .
, ,
.
:
, , , , .
, .
, , , .
. ,
.
DIP
.
,
, , .
vs.
-. , ,
?
, , 1
100%- !
1
-, -,
test doubles. (mocks) (stubs)
, . , ( Moq) (mocks),
.
Programming Stuff: (bit.ly/StubsVsMocks).
21.
, ! ,
.
, . -
.
,
IPartitioningStrategy
.
,
, .
,
.
,
.
( DIP).
,
, ( /).
,
, .
,
, .
.
,
.
LogEntryParser IFileReader
( 21.3).
21.3. LogEntryParser
class LogEntryParser
{
295
296
IV.
ISP. .
LogEntryParser ,
, , IFileReader.
21.
, .
LogEntryParser .
, ,
, LogEntryReader ( 21.4).
21.4. LogEntryReader
class LogEntryReader : IDisposable
{
private readonly Stream _stream;
private readonly LogEntryParser _parser;
public LogEntryReader(Stream stream, LogEntryParser parser)
{
_stream = stream;
_parser = parser;
}
public void Dispose()
{
_stream.Close();
}
public IEnumerable<LogEntry> Read()
{
using (var sr = new StreamReader(_stream))
{
string line = null;
while ((line = sr.ReadLine()) != null)
{
LogEntry logEntry;
if (_parser.TryParse(line, out logEntry))
{
yield return logEntry;
}
}
}
}
297
298
IV.
. LogEntryReader
,
LogEntryParser .
,
LogEntryReader (
21.5).
21.5. LogEntryReader.FromFile
public static LogEntryReader FromFile(string fileName)
{
var fs = new FileStream(fileName, FileMode.Open);
var parser = LogEntryParser.Create(fileName);
return new LogEntryReader(fs, parser);
}
-,
1. ,
.
ILogEntryReader?
. LogEntryReader LogImporter ( 21.6).
21.6. LogImporter
public class LogImporter : IDisposable
{
private readonly LogEntryReader _logEntryReader;
public LogImporter(string logFile)
{
_logEntryReader = LogEntryReader.FromFile(logFile);
}
1
LogEntryParser.Create 18. , , . .
21.
299
300
IV.
, ILogEntry
Reader ILogEntrySaver . LogImporter
, 21.7, ! LogImporter, LogSaver Log
EntryReader .
.
-.
, IFile
Stream,
.
, .
. DIP , . ,
. , -
21.
.
, .
Inversion of Control
(Inversion of Control, IoC) ,
.
, ,
.
: ,
.
. IoC,
, , IoC-, ,
(.21.6).
. 21.6.
Dependency Injection
(Dependency Injection, DI)
.
301
302
IV.
: (Constructor
Injection), (Method Injection) (Property Injection).
(21.8).
21.8.
class ReportProcessor
{
private readonly IReportSender _reportSender;
// Constuctor Injection:
public ReportProcessor(IReportSender reportSender)
{
_reportSender = reportSender;
Logger = LogManager.DefaultLogger;
}
// Method Injection:
public void SendReport(Report report, IReportFormatter formatter)
{
Logger.Info("Sending report...");
var formattedReport = formatter.Format(report);
_reportSender.SendReport(formattedReport);
Logger.Info("Report has been sent");
}
// Property Injection:
//
public ILogger Logger {get; set;}
}
. ,
( IReportSender
ReportProcessor). ,
, (IReportFormatter
21.
, ReportProcessor ).
(
), (
Logger ,
).
, DI- ,
, , ..
.
!
303
304
IV.
ReportProcessor
ISocket,
.
SendReport: IStringBuilder
, ,
. , .
(DI),
(DIP).
. (IoC)
,
. (DI)
,
. (DIP) ,
, .
DI-: Constructor Injection (http://bit.ly/CustructorInjection).
DI-: Method Injection (bit.ly/MethodInjection).
DI-: Property Injection (bit.ly/PropertyInjection).
DIP in the Wild (http://martinfowler.com/articles/dipInTheWild.html).
Inversion of Control Containers and the Dependency Injection pattern (http://mar
tinfowler.com/articles/injection.html).
, (http://bit.ly/FrameworkDependencies).
22
! ,
, , ,
.
- ,
?
? 1,
?
1
.
software design, . design , .
, design .
? ? ? ,
. , . , ,
. .
306
IV.
.
:
? , , .
, .
: , , . , , ,
,
.
, : , ,
, ,
. ,
, .
, , ,
.
,
(coupling) (cohesion)1. (low coupling) (high cohesion). ,
. , .
, .
, , .
, , .
1
, .
,
. , .
22.
, .
,
,
: ,
! ,
.
, : ,
, -! ,
!
,
.
, ,
, , .
( )
,
.
1
Meyer B., Agile!: The Good, The Hype, and The Ugly. Springer, 2014.
307
308
IV.
, ,
, ,
.
.
, .
,
: ,
, , !
, -, ,
!
: , (Shu, Ha,
Ri https://en.wikipedia.org/wiki/Shuhari). , .
, , .
,
. , , http://en.wikipedia.org/
wiki/Dreyfus_model_of_skill_acquisition.
. , , .
(lowcohesion) ,
.
/
. ,
.
- . .
, ,
. -
22.
. -
, .
. , , .
.
, ,
, : , .
. ,
.
. .
, , .
, . :
, ?
. , ,
: ,
, . . ,
,
. , , .
,
(overengineering): ? , ?
(premature generalization)?
,
.
309
310
IV.
. . , ,
,
.
Anti-SRP .
, /.
Anti-OCP . ,
,
.
Anti-LCP .
, .
Anti-ISP .
, .
Anti-DIP , DI .
.
, , .
,
.
,
.
. ,
: , ,
.
.
(SRP),
(OCP).
, LSP. ,
(ISP), (DIP).
.
. ,
. ,
, .
,
.
312
/
.
, . ,
. / . .
,
.
,
.
.
, : .
, .
.
, , .
1. . . - . .:
, 1994. ,
. , , .
2. . . .: , 2003. , . (Head-First Design Patterns),
: ,
, .
3. . -
. .: -, 2005. , -
- ( ) .
, -
.
, , , ,
314
, ( ).
4. . UML 2.0 . 3- . .:
, 2004. - : .
5. . - . .: ,
2003. - , , ,
. , ,
.
6. . - . .: , 2003. DDD (Domain-Driven Design) Event Sourcing, CQRS enterprise- Domain DataAccess.
, , , .
. .
7. . , C#.
.: -, 2011. , . , ,
. ,
.
,
C# http://sergeyteplyakov.blogspot.ru/2013/12/aboutagile-principles-patterns-and.html.
8. Beck K. Test-Driven Development: By Example. 2002. ,
, TDD , . ,
, , .
9. Freeman S., Pryce N. Growing Object-Oriented Software Guided by Tests. 2009.
TDD .
,
. .
10. . . . .: , 1999. , . : ,
, .
, .
11. Osherove R. The Art of Unit Testing: with examples in C#. 2014.
, .
: , , DI-, DDD-, , .
-.
. xUnit Test Patterns:
Refactoring Test Code,
.NET.
12. . . .: , 2004.
.
, - .
13. Cwalina K., Abrams B. Framework Design Guidelines. 2009. ,
( )
. ,
,
. , , ,
, . , , ,
,
C#.
, .
14. Seeman M. Dependency Injection in .NET, 2011. DI-.
315
316
.
.NET
.
.
.
.
. , .
.
, 192102, -, . (. ), 3, , . 7.
034-2014, 58.11.12
, .
25.03.15. 70100/16. . . . 25,800. 700. 0000.
. .
142300, , . , . , 1.
: www.chpk.ru. E-mail: marketing@chpk.ru
: 8(496) 726-54-10, : (495) 988-63-87
:
: www.piter.com
: postbook@piter.com
: (812) 7037374
: 197198, , / 127,
ICQ: 413763617
:
.
.
,
.
. : . Web-money USD
E-Gold, MoneyMail, INOCard, RBK Money (RuPay), USD Bets, Mobile Wallet
.
, ,
.
.
.
e-mail.
:
, , , , , e
mail;
, , , , , ,
, ;
, , .