├── .editorconfig
├── .gitattributes
├── .gitignore
├── HOME.md
├── LICENSE
├── README.md
├── _config.yml
└── design_patterns
├── behavioral
├── chain_of_responsibility.md
├── chain_of_responsibility_UML.gif
├── command.md
├── command_UML.gif
├── interpreter.md
├── interpreter_UML.gif
├── iterator.md
├── iterator_UML.gif
├── mediator.md
├── mediator_UML.gif
├── momento.md
├── momento_UML.gif
├── momento_UML_2.png
├── observer.md
├── observer_UML.gif
├── state.md
├── state_UML.gif
├── strategy.md
├── strategy_UML.gif
├── template_method.md
├── template_method_UML.gif
├── visitor.md
└── visitor_UML.gif
├── creational
├── abstract_factory.md
├── abstract_factory_UML.jpeg
├── builder.md
├── builder_UML.gif
├── factory_method.md
├── factory_method_UML.gif
├── prototype.md
├── prototype_UML.gif
├── singleton.md
└── singleton_UML.png
└── structural
├── adapter.md
├── adapter_UML.gif
├── bridge.md
├── bridge_UML.gif
├── composite.md
├── composite_UML.gif
├── decorator.md
├── decorator_UML.gif
├── facade.md
├── facade_UML.gif
├── flyweight.md
├── flyweight_UML.gif
├── proxy.md
└── proxy_UML.gif
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | indent_size = 4
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | #common settings that generally should always be used with your language specific settings
2 |
3 | # Auto detect text files and perform LF normalization
4 | # http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
5 | * text=auto
6 |
7 | #
8 | # The above will handle all files NOT found below
9 | #
10 |
11 | # Documents
12 | *.doc diff=astextplain
13 | *.DOC diff=astextplain
14 | *.docx diff=astextplain
15 | *.DOCX diff=astextplain
16 | *.dot diff=astextplain
17 | *.DOT diff=astextplain
18 | *.pdf diff=astextplain
19 | *.PDF diff=astextplain
20 | *.rtf diff=astextplain
21 | *.RTF diff=astextplain
22 | *.md text
23 | *.adoc text
24 | *.textile text
25 | *.mustache text
26 | *.csv text
27 | *.tab text
28 | *.tsv text
29 | *.sql text
30 |
31 | # Graphics
32 | *.png binary
33 | *.jpg binary
34 | *.jpeg binary
35 | *.gif binary
36 | *.tif binary
37 | *.tiff binary
38 | *.ico binary
39 | # SVG treated as an asset (binary) by default. If you want to treat it as text,
40 | # comment-out the following line and uncomment the line after.
41 | *.svg binary
42 | #*.svg text
43 | *.eps binary
44 | ## GITATTRIBUTES FOR WEB PROJECTS
45 | #
46 | # These settings are for any web project.
47 | #
48 | # Details per file setting:
49 | # text These files should be normalized (i.e. convert CRLF to LF).
50 | # binary These files are binary and should be left untouched.
51 | #
52 | # Note that binary is a macro for -text -diff.
53 | ######################################################################
54 |
55 | ## AUTO-DETECT
56 | ## Handle line endings automatically for files detected as
57 | ## text and leave all files detected as binary untouched.
58 | ## This will handle all files NOT defined below.
59 | * text=auto
60 |
61 | ## SOURCE CODE
62 | *.bat text eol=crlf
63 | *.coffee text
64 | *.css text
65 | *.htm text
66 | *.html text
67 | *.inc text
68 | *.ini text
69 | *.js text
70 | *.json text
71 | *.jsx text
72 | *.less text
73 | *.od text
74 | *.onlydata text
75 | *.php text
76 | *.pl text
77 | *.py text
78 | *.rb text
79 | *.sass text
80 | *.scm text
81 | *.scss text
82 | *.sh text eol=lf
83 | *.sql text
84 | *.styl text
85 | *.tag text
86 | *.ts text
87 | *.tsx text
88 | *.xml text
89 | *.xhtml text
90 |
91 | ## DOCKER
92 | *.dockerignore text
93 | Dockerfile text
94 |
95 | ## DOCUMENTATION
96 | *.markdown text
97 | *.md text
98 | *.mdwn text
99 | *.mdown text
100 | *.mkd text
101 | *.mkdn text
102 | *.mdtxt text
103 | *.mdtext text
104 | *.txt text
105 | AUTHORS text
106 | CHANGELOG text
107 | CHANGES text
108 | CONTRIBUTING text
109 | COPYING text
110 | copyright text
111 | *COPYRIGHT* text
112 | INSTALL text
113 | license text
114 | LICENSE text
115 | NEWS text
116 | readme text
117 | *README* text
118 | TODO text
119 |
120 | ## TEMPLATES
121 | *.dot text
122 | *.ejs text
123 | *.haml text
124 | *.handlebars text
125 | *.hbs text
126 | *.hbt text
127 | *.jade text
128 | *.latte text
129 | *.mustache text
130 | *.njk text
131 | *.phtml text
132 | *.tmpl text
133 | *.tpl text
134 | *.twig text
135 |
136 | ## LINTERS
137 | .csslintrc text
138 | .eslintrc text
139 | .htmlhintrc text
140 | .jscsrc text
141 | .jshintrc text
142 | .jshintignore text
143 | .stylelintrc text
144 |
145 | ## CONFIGS
146 | *.bowerrc text
147 | *.cnf text
148 | *.conf text
149 | *.config text
150 | .browserslistrc text
151 | .editorconfig text
152 | .gitattributes text
153 | .gitconfig text
154 | .htaccess text
155 | *.npmignore text
156 | *.yaml text
157 | *.yml text
158 | browserslist text
159 | Makefile text
160 | makefile text
161 |
162 | ## HEROKU
163 | Procfile text
164 | .slugignore text
165 |
166 | ## GRAPHICS
167 | *.ai binary
168 | *.bmp binary
169 | *.eps binary
170 | *.gif binary
171 | *.ico binary
172 | *.jng binary
173 | *.jp2 binary
174 | *.jpg binary
175 | *.jpeg binary
176 | *.jpx binary
177 | *.jxr binary
178 | *.pdf binary
179 | *.png binary
180 | *.psb binary
181 | *.psd binary
182 | *.svg text
183 | *.svgz binary
184 | *.tif binary
185 | *.tiff binary
186 | *.wbmp binary
187 | *.webp binary
188 |
189 | ## AUDIO
190 | *.kar binary
191 | *.m4a binary
192 | *.mid binary
193 | *.midi binary
194 | *.mp3 binary
195 | *.ogg binary
196 | *.ra binary
197 |
198 | ## VIDEO
199 | *.3gpp binary
200 | *.3gp binary
201 | *.as binary
202 | *.asf binary
203 | *.asx binary
204 | *.fla binary
205 | *.flv binary
206 | *.m4v binary
207 | *.mng binary
208 | *.mov binary
209 | *.mp4 binary
210 | *.mpeg binary
211 | *.mpg binary
212 | *.ogv binary
213 | *.swc binary
214 | *.swf binary
215 | *.webm binary
216 |
217 | ## ARCHIVES
218 | *.7z binary
219 | *.gz binary
220 | *.jar binary
221 | *.rar binary
222 | *.tar binary
223 | *.zip binary
224 |
225 | ## FONTS
226 | *.ttf binary
227 | *.eot binary
228 | *.otf binary
229 | *.woff binary
230 | *.woff2 binary
231 |
232 | ## EXECUTABLES
233 | *.exe binary
234 | *.pyc binary
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/intellij+all
3 | # Edit at https://www.gitignore.io/?templates=intellij+all
4 |
5 | ### Intellij+all ###
6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
8 |
9 | # User-specific stuff
10 | .idea/**/workspace.xml
11 | .idea/**/tasks.xml
12 | .idea/**/usage.statistics.xml
13 | .idea/**/dictionaries
14 | .idea/**/shelf
15 |
16 | # Generated files
17 | .idea/**/contentModel.xml
18 |
19 | # Sensitive or high-churn files
20 | .idea/**/dataSources/
21 | .idea/**/dataSources.ids
22 | .idea/**/dataSources.local.xml
23 | .idea/**/sqlDataSources.xml
24 | .idea/**/dynamic.xml
25 | .idea/**/uiDesigner.xml
26 | .idea/**/dbnavigator.xml
27 |
28 | # Gradle
29 | .idea/**/gradle.xml
30 | .idea/**/libraries
31 |
32 | # Gradle and Maven with auto-import
33 | # When using Gradle or Maven with auto-import, you should exclude module files,
34 | # since they will be recreated, and may cause churn. Uncomment if using
35 | # auto-import.
36 | # .idea/modules.xml
37 | # .idea/*.iml
38 | # .idea/modules
39 |
40 | # CMake
41 | cmake-build-*/
42 |
43 | # Mongo Explorer plugin
44 | .idea/**/mongoSettings.xml
45 |
46 | # File-based project format
47 | *.iws
48 |
49 | # IntelliJ
50 | out/
51 |
52 | # mpeltonen/sbt-idea plugin
53 | .idea_modules/
54 |
55 | # JIRA plugin
56 | atlassian-ide-plugin.xml
57 |
58 | # Cursive Clojure plugin
59 | .idea/replstate.xml
60 |
61 | # Crashlytics plugin (for Android Studio and IntelliJ)
62 | com_crashlytics_export_strings.xml
63 | crashlytics.properties
64 | crashlytics-build.properties
65 | fabric.properties
66 |
67 | # Editor-based Rest Client
68 | .idea/httpRequests
69 |
70 | # Android studio 3.1+ serialized cache file
71 | .idea/caches/build_file_checksums.ser
72 |
73 | ### Intellij+all Patch ###
74 | # Ignores the whole .idea folder and all .iml files
75 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
76 |
77 | .idea/
78 |
79 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
80 |
81 | *.iml
82 | modules.xml
83 | .idea/misc.xml
84 | *.ipr
85 |
86 | # End of https://www.gitignore.io/api/intellij+all
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Ivan Muratov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # База знаний разработчика
2 |
3 | [📚 Главная страница 📚](/HOME.md)
4 |
5 | Данный проект не содержит подробной информации о чем бы то ни было.
6 | В первую очередь это мой личный справочник с множеством ссылок на различные ресурсы.
7 | Просто, чтобы не забыть. А также посмотреть через N лет, как я докатился до жизни такой.
8 |
9 | Идея была в составлении некой технической автобиографии
10 | и базы знаний о различных языках, подходах и технологиях,
11 | с которыми мне приходилось работать или, как минимум, сталкиваться в своей практике.
12 |
13 | Внимание! Я старался максимально использовать русский язык. 🇷🇺
14 |
15 | [](https://forthebadge.com)
16 |
17 | [](https://forthebadge.com)
18 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-slate
--------------------------------------------------------------------------------
/design_patterns/behavioral/chain_of_responsibility.md:
--------------------------------------------------------------------------------
1 | # Цепочка обязанностей (Chain of responsibility) #
2 |
3 | Паттерн Цепочка Обязанностей используется, когда необходимо предоставить нескольким объектам возможность обработать запрос.
4 |
5 | 
6 |
7 | * Handler - абстрактный обработчик
8 |
9 | * ConcreteHandler - конкретный обработчик
10 |
11 | * Client - клиент
12 |
13 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Цепочка_обязанностей)
14 |
15 | ## Абстрактная реализация на C# (GoF) ##
16 |
17 | ```csharp
18 | ///
19 | /// MainApp startup class for Structural
20 | /// Chain of Responsibility Design Pattern.
21 | ///
22 | internal class MainApp
23 | {
24 | ///
25 | /// Entry point into console application.
26 | ///
27 | private static void Main()
28 | {
29 | // Setup Chain of Responsibility
30 | Handler h1 = new ConcreteHandler1();
31 | Handler h2 = new ConcreteHandler2();
32 | Handler h3 = new ConcreteHandler3();
33 | h1.SetSuccessor(h2);
34 | h2.SetSuccessor(h3);
35 |
36 | // Generate and process request
37 | int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
38 |
39 | foreach (int request in requests)
40 | {
41 | h1.HandleRequest(request);
42 | }
43 |
44 | // Wait for user
45 | Console.ReadKey();
46 | }
47 | }
48 |
49 | ///
50 | /// The 'Handler' abstract class
51 | ///
52 | internal abstract class Handler
53 | {
54 | protected Handler successor;
55 |
56 | public void SetSuccessor(Handler successor)
57 | {
58 | this.successor = successor;
59 | }
60 |
61 | public abstract void HandleRequest(int request);
62 | }
63 |
64 | ///
65 | /// The 'ConcreteHandler1' class
66 | ///
67 | internal class ConcreteHandler1 : Handler
68 | {
69 | public override void HandleRequest(int request)
70 | {
71 | if (request >= 0 && request < 10)
72 | {
73 | Console.WriteLine("{0} handled request {1}",
74 | this.GetType().Name, request);
75 | }
76 | else if (successor != null)
77 | {
78 | successor.HandleRequest(request);
79 | }
80 | }
81 | }
82 |
83 | ///
84 | /// The 'ConcreteHandler2' class
85 | ///
86 | internal class ConcreteHandler2 : Handler
87 | {
88 | public override void HandleRequest(int request)
89 | {
90 | if (request >= 10 && request < 20)
91 | {
92 | Console.WriteLine("{0} handled request {1}",
93 | this.GetType().Name, request);
94 | }
95 | else if (successor != null)
96 | {
97 | successor.HandleRequest(request);
98 | }
99 | }
100 | }
101 |
102 | ///
103 | /// The 'ConcreteHandler3' class
104 | ///
105 | internal class ConcreteHandler3 : Handler
106 | {
107 | public override void HandleRequest(int request)
108 | {
109 | if (request >= 20 && request < 30)
110 | {
111 | Console.WriteLine("{0} handled request {1}",
112 | this.GetType().Name, request);
113 | }
114 | else if (successor != null)
115 | {
116 | successor.HandleRequest(request);
117 | }
118 | }
119 | }
120 | ```
121 |
122 | ## Реальная реализация на C# (GoF) ##
123 |
124 | ```charp
125 | ///
126 | /// MainApp startup class for Real-World
127 | /// Chain of Responsibility Design Pattern.
128 | ///
129 | internal class MainApp
130 | {
131 | ///
132 | /// Entry point into console application.
133 | ///
134 | private static void Main()
135 | {
136 | // Setup Chain of Responsibility
137 | Approver larry = new Director();
138 | Approver sam = new VicePresident();
139 | Approver tammy = new President();
140 |
141 | larry.SetSuccessor(sam);
142 | sam.SetSuccessor(tammy);
143 |
144 | // Generate and process purchase requests
145 | Purchase p = new Purchase(2034, 350.00, "Supplies");
146 | larry.ProcessRequest(p);
147 |
148 | p = new Purchase(2035, 32590.10, "Project X");
149 | larry.ProcessRequest(p);
150 |
151 | p = new Purchase(2036, 122100.00, "Project Y");
152 | larry.ProcessRequest(p);
153 |
154 | // Wait for user
155 | Console.ReadKey();
156 | }
157 | }
158 |
159 | ///
160 | /// The 'Handler' abstract class
161 | ///
162 | internal abstract class Approver
163 | {
164 | protected Approver successor;
165 |
166 | public void SetSuccessor(Approver successor)
167 | {
168 | this.successor = successor;
169 | }
170 |
171 | public abstract void ProcessRequest(Purchase purchase);
172 | }
173 |
174 | ///
175 | /// The 'ConcreteHandler' class
176 | ///
177 | internal class Director : Approver
178 | {
179 | public override void ProcessRequest(Purchase purchase)
180 | {
181 | if (purchase.Amount < 10000.0)
182 | {
183 | Console.WriteLine("{0} approved request# {1}",
184 | this.GetType().Name, purchase.Number);
185 | }
186 | else if (successor != null)
187 | {
188 | successor.ProcessRequest(purchase);
189 | }
190 | }
191 | }
192 |
193 | ///
194 | /// The 'ConcreteHandler' class
195 | ///
196 | internal class VicePresident : Approver
197 | {
198 | public override void ProcessRequest(Purchase purchase)
199 | {
200 | if (purchase.Amount < 25000.0)
201 | {
202 | Console.WriteLine("{0} approved request# {1}",
203 | this.GetType().Name, purchase.Number);
204 | }
205 | else if (successor != null)
206 | {
207 | successor.ProcessRequest(purchase);
208 | }
209 | }
210 | }
211 |
212 | ///
213 | /// The 'ConcreteHandler' class
214 | ///
215 | internal class President : Approver
216 | {
217 | public override void ProcessRequest(Purchase purchase)
218 | {
219 | if (purchase.Amount < 100000.0)
220 | {
221 | Console.WriteLine("{0} approved request# {1}",
222 | this.GetType().Name, purchase.Number);
223 | }
224 | else
225 | {
226 | Console.WriteLine(
227 | "Request# {0} requires an executive meeting!",
228 | purchase.Number);
229 | }
230 | }
231 | }
232 |
233 | ///
234 | /// Class holding request details
235 | ///
236 | internal class Purchase
237 | {
238 | private int number;
239 | private double amount;
240 | private string purpose;
241 |
242 | // Constructor
243 | public Purchase(int number, double amount, string purpose)
244 | {
245 | this.number = number;
246 | this.amount = amount;
247 | this.purpose = purpose;
248 | }
249 |
250 | // Gets or sets purchase number
251 | public int Number
252 | {
253 | get { return number; }
254 | set { number = value; }
255 | }
256 |
257 | // Gets or sets purchase amount
258 | public double Amount
259 | {
260 | get { return amount; }
261 | set { amount = value; }
262 | }
263 |
264 | // Gets or sets purchase purpose
265 | public string Purpose
266 | {
267 | get { return purpose; }
268 | set { purpose = value; }
269 | }
270 | }
271 | ```
272 |
273 | ## Улучшенная реальная реализация на C# (GoF) ##
274 |
275 | ```csharp
276 | ///
277 | /// MainApp startup class for .NET optimized
278 | /// Chain of Responsibility Design Pattern.
279 | ///
280 | internal class MainApp
281 | {
282 | ///
283 | /// Entry point into console application.
284 | ///
285 | private static void Main()
286 | {
287 | // Setup Chain of Responsibility
288 | Approver larry = new Director();
289 | Approver sam = new VicePresident();
290 | Approver tammy = new President();
291 |
292 | larry.Successor = sam;
293 | sam.Successor = tammy;
294 |
295 | // Generate and process purchase requests
296 | var purchase = new Purchase { Number = 2034, Amount = 350.00, Purpose = "Supplies" };
297 | larry.ProcessRequest(purchase);
298 |
299 | purchase = new Purchase { Number = 2035, Amount = 32590.10, Purpose = "Project X" };
300 | larry.ProcessRequest(purchase);
301 |
302 | purchase = new Purchase { Number = 2036, Amount = 122100.00, Purpose = "Project Y" };
303 | larry.ProcessRequest(purchase);
304 |
305 | // Wait for user
306 | Console.ReadKey();
307 | }
308 | }
309 |
310 | // Purchase event argument holds purchase info
311 | public class PurchaseEventArgs : EventArgs
312 | {
313 | internal Purchase Purchase { get; set; }
314 | }
315 |
316 | ///
317 | /// The 'Handler' abstract class
318 | ///
319 | internal abstract class Approver
320 | {
321 | // Purchase event
322 | public EventHandler Purchase;
323 |
324 | // Purchase event handler
325 | public abstract void PurchaseHandler(object sender, PurchaseEventArgs e);
326 |
327 | // Constructor
328 | public Approver()
329 | {
330 | Purchase += PurchaseHandler;
331 | }
332 |
333 | public void ProcessRequest(Purchase purchase)
334 | {
335 | OnPurchase(new PurchaseEventArgs { Purchase = purchase });
336 | }
337 |
338 | // Invoke the Purchase event
339 | public virtual void OnPurchase(PurchaseEventArgs e)
340 | {
341 | if (Purchase != null)
342 | {
343 | Purchase(this, e);
344 | }
345 | }
346 |
347 | // Sets or gets the next approver
348 | public Approver Successor { get; set; }
349 | }
350 |
351 | ///
352 | /// The 'ConcreteHandler' class
353 | ///
354 | internal class Director : Approver
355 | {
356 | public override void PurchaseHandler(object sender, PurchaseEventArgs e)
357 | {
358 | if (e.Purchase.Amount < 10000.0)
359 | {
360 | Console.WriteLine("{0} approved request# {1}",
361 | this.GetType().Name, e.Purchase.Number);
362 | }
363 | else if (Successor != null)
364 | {
365 | Successor.PurchaseHandler(this, e);
366 | }
367 | }
368 | }
369 |
370 | ///
371 | /// The 'ConcreteHandler' class
372 | ///
373 | internal class VicePresident : Approver
374 | {
375 | public override void PurchaseHandler(object sender, PurchaseEventArgs e)
376 | {
377 | if (e.Purchase.Amount < 25000.0)
378 | {
379 | Console.WriteLine("{0} approved request# {1}",
380 | this.GetType().Name, e.Purchase.Number);
381 | }
382 | else if (Successor != null)
383 | {
384 | Successor.PurchaseHandler(this, e);
385 | }
386 | }
387 | }
388 |
389 | ///
390 | /// The 'ConcreteHandler' clas
391 | ///
392 | internal class President : Approver
393 | {
394 | public override void PurchaseHandler(object sender, PurchaseEventArgs e)
395 | {
396 | if (e.Purchase.Amount < 100000.0)
397 | {
398 | Console.WriteLine("{0} approved request# {1}",
399 | sender.GetType().Name, e.Purchase.Number);
400 | }
401 | else if (Successor != null)
402 | {
403 | Successor.PurchaseHandler(this, e);
404 | }
405 | else
406 | {
407 | Console.WriteLine(
408 | "Request# {0} requires an executive meeting!",
409 | e.Purchase.Number);
410 | }
411 | }
412 | }
413 |
414 | ///
415 | /// Class that holds request details
416 | ///
417 | internal class Purchase
418 | {
419 | public double Amount { get; set; }
420 | public string Purpose { get; set; }
421 | public int Number { get; set; }
422 | }
423 | ```
424 |
425 | ## Реализация на JAVA ##
426 |
427 | ```java
428 | TODO
429 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/chain_of_responsibility_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/chain_of_responsibility_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/command_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/command_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/interpreter.md:
--------------------------------------------------------------------------------
1 | # Интерпретатор (Interpreter) #
2 |
3 | Паттерн Интерпретатор используется для создания языковых интерпретаторов.
4 |
5 | 
6 |
7 | * AbstractExpression - абстрактное выражение
8 |
9 | * TerminalExpression - терминальное выражение
10 |
11 | * NonterminalExpression - нетерминальное выражение
12 |
13 | * Context - контекст
14 |
15 | * Client - клиент
16 |
17 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Интерпретатор_(шаблон_проектирования))
18 |
19 | ## Абстрактная реализация на C# (GoF) ##
20 |
21 | ```csharp
22 | ///
23 | /// MainApp startup class for Structural
24 | /// Interpreter Design Pattern.
25 | ///
26 | internal class MainApp
27 | {
28 | ///
29 | /// Entry point into console application.
30 | ///
31 | private static void Main()
32 | {
33 | Context context = new Context();
34 |
35 | // Usually a tree
36 | ArrayList list = new ArrayList();
37 |
38 | // Populate 'abstract syntax tree'
39 | list.Add(new TerminalExpression());
40 | list.Add(new NonterminalExpression());
41 | list.Add(new TerminalExpression());
42 | list.Add(new TerminalExpression());
43 |
44 | // Interpret
45 | foreach (AbstractExpression exp in list)
46 | {
47 | exp.Interpret(context);
48 | }
49 |
50 | // Wait for user
51 | Console.ReadKey();
52 | }
53 | }
54 |
55 | ///
56 | /// The 'Context' class
57 | ///
58 | internal class Context
59 | {
60 | }
61 |
62 | ///
63 | /// The 'AbstractExpression' abstract class
64 | ///
65 | internal abstract class AbstractExpression
66 | {
67 | public abstract void Interpret(Context context);
68 | }
69 |
70 | ///
71 | /// The 'TerminalExpression' class
72 | ///
73 | internal class TerminalExpression : AbstractExpression
74 | {
75 | public override void Interpret(Context context)
76 | {
77 | Console.WriteLine("Called Terminal.Interpret()");
78 | }
79 | }
80 |
81 | ///
82 | /// The 'NonterminalExpression' class
83 | ///
84 | internal class NonterminalExpression : AbstractExpression
85 | {
86 | public override void Interpret(Context context)
87 | {
88 | Console.WriteLine("Called Nonterminal.Interpret()");
89 | }
90 | }
91 | ```
92 |
93 | ## Реальная реализация на C# (GoF) ##
94 |
95 | ```charp
96 | ///
97 | /// MainApp startup class for Real-World
98 | /// Interpreter Design Pattern.
99 | ///
100 | internal class MainApp
101 | {
102 | ///
103 | /// Entry point into console application.
104 | ///
105 | private static void Main()
106 | {
107 | string roman = "MCMXXVIII";
108 | Context context = new Context(roman);
109 |
110 | // Build the 'parse tree'
111 | List tree = new List();
112 | tree.Add(new ThousandExpression());
113 | tree.Add(new HundredExpression());
114 | tree.Add(new TenExpression());
115 | tree.Add(new OneExpression());
116 |
117 | // Interpret
118 | foreach (Expression exp in tree)
119 | {
120 | exp.Interpret(context);
121 | }
122 |
123 | Console.WriteLine("{0} = {1}",
124 | roman, context.Output);
125 |
126 | // Wait for user
127 | Console.ReadKey();
128 | }
129 | }
130 |
131 | ///
132 | /// The 'Context' class
133 | ///
134 | internal class Context
135 | {
136 | private string input;
137 | private int output;
138 |
139 | // Constructor
140 | public Context(string input)
141 | {
142 | this.input = input;
143 | }
144 |
145 | // Gets or sets input
146 | public string Input
147 | {
148 | get { return input; }
149 | set { input = value; }
150 | }
151 |
152 | // Gets or sets output
153 | public int Output
154 | {
155 | get { return output; }
156 | set { output = value; }
157 | }
158 | }
159 |
160 | ///
161 | /// The 'AbstractExpression' class
162 | ///
163 | internal abstract class Expression
164 | {
165 | public void Interpret(Context context)
166 | {
167 | if (context.Input.Length == 0)
168 | return;
169 |
170 | if (context.Input.StartsWith(Nine()))
171 | {
172 | context.Output += (9 * Multiplier());
173 | context.Input = context.Input.Substring(2);
174 | }
175 | else if (context.Input.StartsWith(Four()))
176 | {
177 | context.Output += (4 * Multiplier());
178 | context.Input = context.Input.Substring(2);
179 | }
180 | else if (context.Input.StartsWith(Five()))
181 | {
182 | context.Output += (5 * Multiplier());
183 | context.Input = context.Input.Substring(1);
184 | }
185 |
186 | while (context.Input.StartsWith(One()))
187 | {
188 | context.Output += (1 * Multiplier());
189 | context.Input = context.Input.Substring(1);
190 | }
191 | }
192 |
193 | public abstract string One();
194 |
195 | public abstract string Four();
196 |
197 | public abstract string Five();
198 |
199 | public abstract string Nine();
200 |
201 | public abstract int Multiplier();
202 | }
203 |
204 | ///
205 | /// A 'TerminalExpression' class
206 | ///
207 | /// Thousand checks for the Roman Numeral M
208 | ///
209 | ///
210 | internal class ThousandExpression : Expression
211 | {
212 | public override string One()
213 | {
214 | return "M";
215 | }
216 |
217 | public override string Four()
218 | {
219 | return " ";
220 | }
221 |
222 | public override string Five()
223 | {
224 | return " ";
225 | }
226 |
227 | public override string Nine()
228 | {
229 | return " ";
230 | }
231 |
232 | public override int Multiplier()
233 | {
234 | return 1000;
235 | }
236 | }
237 |
238 | ///
239 | /// A 'TerminalExpression' class
240 | ///
241 | /// Hundred checks C, CD, D or CM
242 | ///
243 | ///
244 | internal class HundredExpression : Expression
245 | {
246 | public override string One()
247 | {
248 | return "C";
249 | }
250 |
251 | public override string Four()
252 | {
253 | return "CD";
254 | }
255 |
256 | public override string Five()
257 | {
258 | return "D";
259 | }
260 |
261 | public override string Nine()
262 | {
263 | return "CM";
264 | }
265 |
266 | public override int Multiplier()
267 | {
268 | return 100;
269 | }
270 | }
271 |
272 | ///
273 | /// A 'TerminalExpression' class
274 | ///
275 | /// Ten checks for X, XL, L and XC
276 | ///
277 | ///
278 | internal class TenExpression : Expression
279 | {
280 | public override string One()
281 | {
282 | return "X";
283 | }
284 |
285 | public override string Four()
286 | {
287 | return "XL";
288 | }
289 |
290 | public override string Five()
291 | {
292 | return "L";
293 | }
294 |
295 | public override string Nine()
296 | {
297 | return "XC";
298 | }
299 |
300 | public override int Multiplier()
301 | {
302 | return 10;
303 | }
304 | }
305 |
306 | ///
307 | /// A 'TerminalExpression' class
308 | ///
309 | /// One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
310 | ///
311 | ///
312 | internal class OneExpression : Expression
313 | {
314 | public override string One()
315 | {
316 | return "I";
317 | }
318 |
319 | public override string Four()
320 | {
321 | return "IV";
322 | }
323 |
324 | public override string Five()
325 | {
326 | return "V";
327 | }
328 |
329 | public override string Nine()
330 | {
331 | return "IX";
332 | }
333 |
334 | public override int Multiplier()
335 | {
336 | return 1;
337 | }
338 | }
339 | ```
340 |
341 | ## Улучшенная реальная реализация на C# (GoF) ##
342 |
343 | ```csharp
344 | ///
345 | /// MainApp startup class for .NET optimized
346 | /// Interpreter Design Pattern.
347 | ///
348 | internal class MainApp
349 | {
350 | ///
351 | /// Entry point into console application.
352 | ///
353 | private static void Main()
354 | {
355 | // Construct the 'parse tree'
356 | var tree = new List
357 | {
358 | new ThousandExpression(),
359 | new HundredExpression(),
360 | new TenExpression(),
361 | new OneExpression()
362 | };
363 |
364 | // Create the context (i.e. roman value)
365 | string roman = "MCMXXVIII";
366 | var context = new Context { Input = roman };
367 |
368 | // Interpret
369 | tree.ForEach(e => e.Interpret(context));
370 |
371 | Console.WriteLine("{0} = {1}", roman, context.Output);
372 |
373 | // Wait for user
374 | Console.ReadKey();
375 | }
376 | }
377 |
378 | ///
379 | /// The 'Context' class
380 | ///
381 | internal class Context
382 | {
383 | public string Input { get; set; }
384 | public int Output { get; set; }
385 | }
386 |
387 | ///
388 | /// The 'AbstractExpression' abstract class
389 | ///
390 | internal abstract class Expression
391 | {
392 | public void Interpret(Context context)
393 | {
394 | if (context.Input.Length == 0)
395 | return;
396 |
397 | if (context.Input.StartsWith(Nine()))
398 | {
399 | context.Output += (9 * Multiplier());
400 | context.Input = context.Input.Substring(2);
401 | }
402 | else if (context.Input.StartsWith(Four()))
403 | {
404 | context.Output += (4 * Multiplier());
405 | context.Input = context.Input.Substring(2);
406 | }
407 | else if (context.Input.StartsWith(Five()))
408 | {
409 | context.Output += (5 * Multiplier());
410 | context.Input = context.Input.Substring(1);
411 | }
412 |
413 | while (context.Input.StartsWith(One()))
414 | {
415 | context.Output += (1 * Multiplier());
416 | context.Input = context.Input.Substring(1);
417 | }
418 | }
419 |
420 | public abstract string One();
421 |
422 | public abstract string Four();
423 |
424 | public abstract string Five();
425 |
426 | public abstract string Nine();
427 |
428 | public abstract int Multiplier();
429 | }
430 |
431 | ///
432 | /// A 'TerminalExpression' class
433 | ///
434 | /// Thousand checks for the Roman Numeral M
435 | ///
436 | ///
437 | internal class ThousandExpression : Expression
438 | {
439 | public override string One()
440 | {
441 | return "M";
442 | }
443 |
444 | public override string Four()
445 | {
446 | return " ";
447 | }
448 |
449 | public override string Five()
450 | {
451 | return " ";
452 | }
453 |
454 | public override string Nine()
455 | {
456 | return " ";
457 | }
458 |
459 | public override int Multiplier()
460 | {
461 | return 1000;
462 | }
463 | }
464 |
465 | ///
466 | /// A 'TerminalExpression' class
467 | ///
468 | /// Hundred checks C, CD, D or CM
469 | ///
470 | ///
471 | internal class HundredExpression : Expression
472 | {
473 | public override string One()
474 | {
475 | return "C";
476 | }
477 |
478 | public override string Four()
479 | {
480 | return "CD";
481 | }
482 |
483 | public override string Five()
484 | {
485 | return "D";
486 | }
487 |
488 | public override string Nine()
489 | {
490 | return "CM";
491 | }
492 |
493 | public override int Multiplier()
494 | {
495 | return 100;
496 | }
497 | }
498 |
499 | ///
500 | /// A 'TerminalExpression' class
501 | ///
502 | /// Ten checks for X, XL, L and XC
503 | ///
504 | ///
505 | internal class TenExpression : Expression
506 | {
507 | public override string One()
508 | {
509 | return "X";
510 | }
511 |
512 | public override string Four()
513 | {
514 | return "XL";
515 | }
516 |
517 | public override string Five()
518 | {
519 | return "L";
520 | }
521 |
522 | public override string Nine()
523 | {
524 | return "XC";
525 | }
526 |
527 | public override int Multiplier()
528 | {
529 | return 10;
530 | }
531 | }
532 |
533 | ///
534 | /// A 'TerminalExpression' class
535 | ///
536 | /// One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
537 | ///
538 | ///
539 | internal class OneExpression : Expression
540 | {
541 | public override string One()
542 | {
543 | return "I";
544 | }
545 |
546 | public override string Four()
547 | {
548 | return "IV";
549 | }
550 |
551 | public override string Five()
552 | {
553 | return "V";
554 | }
555 |
556 | public override string Nine()
557 | {
558 | return "IX";
559 | }
560 |
561 | public override int Multiplier()
562 | {
563 | return 1;
564 | }
565 | }
566 | ```
567 |
568 | ## Реализация на JAVA ##
569 |
570 | ```java
571 | TODO
572 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/interpreter_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/interpreter_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/iterator_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/iterator_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/mediator.md:
--------------------------------------------------------------------------------
1 | # Посредник (Mediator) #
2 |
3 | Паттерн Посредник используется для централизации сложных взаимодействий и управляющих операций между объектами.
4 |
5 | 
6 |
7 | * Mediator - абстрактный посредник
8 |
9 | * ConcreteMediator - конкретный посредник
10 |
11 | * Colleague - абстрактный коллега
12 |
13 | * ConcreteColleagues - конкртеный коллеги
14 |
15 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Посредник_(шаблон_проектирования))
16 |
17 | ## Абстрактная реализация на C# (GoF) ##
18 |
19 | ```csharp
20 | ///
21 | /// MainApp startup class for Structural
22 | /// Mediator Design Pattern.
23 | ///
24 | internal class MainApp
25 | {
26 | ///
27 | /// Entry point into console application.
28 | ///
29 | private static void Main()
30 | {
31 | ConcreteMediator m = new ConcreteMediator();
32 |
33 | ConcreteColleague1 c1 = new ConcreteColleague1(m);
34 | ConcreteColleague2 c2 = new ConcreteColleague2(m);
35 |
36 | m.Colleague1 = c1;
37 | m.Colleague2 = c2;
38 |
39 | c1.Send("How are you?");
40 | c2.Send("Fine, thanks");
41 |
42 | // Wait for user
43 | Console.ReadKey();
44 | }
45 | }
46 |
47 | ///
48 | /// The 'Mediator' abstract class
49 | ///
50 | internal abstract class Mediator
51 | {
52 | public abstract void Send(string message,
53 | Colleague colleague);
54 | }
55 |
56 | ///
57 | /// The 'ConcreteMediator' class
58 | ///
59 | internal class ConcreteMediator : Mediator
60 | {
61 | private ConcreteColleague1 colleague1;
62 | private ConcreteColleague2 colleague2;
63 |
64 | public ConcreteColleague1 Colleague1
65 | {
66 | set { colleague1 = value; }
67 | }
68 |
69 | public ConcreteColleague2 Colleague2
70 | {
71 | set { colleague2 = value; }
72 | }
73 |
74 | public override void Send(string message, Colleague colleague)
75 | {
76 | if (colleague == colleague1)
77 | {
78 | colleague2.Notify(message);
79 | }
80 | else
81 | {
82 | colleague1.Notify(message);
83 | }
84 | }
85 | }
86 |
87 | ///
88 | /// The 'Colleague' abstract class
89 | ///
90 | internal abstract class Colleague
91 | {
92 | protected Mediator mediator;
93 |
94 | // Constructor
95 | public Colleague(Mediator mediator)
96 | {
97 | this.mediator = mediator;
98 | }
99 | }
100 |
101 | ///
102 | /// A 'ConcreteColleague' class
103 | ///
104 | internal class ConcreteColleague1 : Colleague
105 | {
106 | // Constructor
107 | public ConcreteColleague1(Mediator mediator)
108 | : base(mediator)
109 | {
110 | }
111 |
112 | public void Send(string message)
113 | {
114 | mediator.Send(message, this);
115 | }
116 |
117 | public void Notify(string message)
118 | {
119 | Console.WriteLine("Colleague1 gets message: "
120 | + message);
121 | }
122 | }
123 |
124 | ///
125 | /// A 'ConcreteColleague' class
126 | ///
127 | internal class ConcreteColleague2 : Colleague
128 | {
129 | // Constructor
130 | public ConcreteColleague2(Mediator mediator)
131 | : base(mediator)
132 | {
133 | }
134 |
135 | public void Send(string message)
136 | {
137 | mediator.Send(message, this);
138 | }
139 |
140 | public void Notify(string message)
141 | {
142 | Console.WriteLine("Colleague2 gets message: "
143 | + message);
144 | }
145 | }
146 | ```
147 |
148 | ## Реальная реализация на C# (GoF) ##
149 |
150 | ```charp
151 | ///
152 | /// MainApp startup class for Real-World
153 | /// Mediator Design Pattern.
154 | ///
155 | internal class MainApp
156 | {
157 | ///
158 | /// Entry point into console application.
159 | ///
160 | private static void Main()
161 | {
162 | // Create chatroom
163 | Chatroom chatroom = new Chatroom();
164 |
165 | // Create participants and register them
166 | Participant George = new Beatle("George");
167 | Participant Paul = new Beatle("Paul");
168 | Participant Ringo = new Beatle("Ringo");
169 | Participant John = new Beatle("John");
170 | Participant Yoko = new NonBeatle("Yoko");
171 |
172 | chatroom.Register(George);
173 | chatroom.Register(Paul);
174 | chatroom.Register(Ringo);
175 | chatroom.Register(John);
176 | chatroom.Register(Yoko);
177 |
178 | // Chatting participants
179 | Yoko.Send("John", "Hi John!");
180 | Paul.Send("Ringo", "All you need is love");
181 | Ringo.Send("George", "My sweet Lord");
182 | Paul.Send("John", "Can't buy me love");
183 | John.Send("Yoko", "My sweet love");
184 |
185 | // Wait for user
186 | Console.ReadKey();
187 | }
188 | }
189 |
190 | ///
191 | /// The 'Mediator' abstract class
192 | ///
193 | internal abstract class AbstractChatroom
194 | {
195 | public abstract void Register(Participant participant);
196 |
197 | public abstract void Send(
198 | string from, string to, string message);
199 | }
200 |
201 | ///
202 | /// The 'ConcreteMediator' class
203 | ///
204 | internal class Chatroom : AbstractChatroom
205 | {
206 | private Dictionary participants = new Dictionary();
207 |
208 | public override void Register(Participant participant)
209 | {
210 | if (!participants.ContainsValue(participant))
211 | {
212 | participants[participant.Name] = participant;
213 | }
214 |
215 | participant.Chatroom = this;
216 | }
217 |
218 | public override void Send(string from, string to, string message)
219 | {
220 | Participant participant = participants[to];
221 |
222 | if (participant != null)
223 | {
224 | participant.Receive(from, message);
225 | }
226 | }
227 | }
228 |
229 | ///
230 | /// The 'AbstractColleague' class
231 | ///
232 | internal class Participant
233 | {
234 | private Chatroom chatroom;
235 | private string name;
236 |
237 | // Constructor
238 | public Participant(string name)
239 | {
240 | this.name = name;
241 | }
242 |
243 | // Gets participant name
244 | public string Name
245 | {
246 | get { return name; }
247 | }
248 |
249 | // Gets chatroom
250 | public Chatroom Chatroom
251 | {
252 | set { chatroom = value; }
253 | get { return chatroom; }
254 | }
255 |
256 | // Sends message to given participant
257 | public void Send(string to, string message)
258 | {
259 | chatroom.Send(name, to, message);
260 | }
261 |
262 | // Receives message from given participant
263 | public virtual void Receive(
264 | string from, string message)
265 | {
266 | Console.WriteLine("{0} to {1}: '{2}'",
267 | from, Name, message);
268 | }
269 | }
270 |
271 | ///
272 | /// A 'ConcreteColleague' class
273 | ///
274 | internal class Beatle : Participant
275 | {
276 | // Constructor
277 | public Beatle(string name)
278 | : base(name)
279 | {
280 | }
281 |
282 | public override void Receive(string from, string message)
283 | {
284 | Console.Write("To a Beatle: ");
285 | base.Receive(from, message);
286 | }
287 | }
288 |
289 | ///
290 | /// A 'ConcreteColleague' class
291 | ///
292 | internal class NonBeatle : Participant
293 | {
294 | // Constructor
295 | public NonBeatle(string name)
296 | : base(name)
297 | {
298 | }
299 |
300 | public override void Receive(string from, string message)
301 | {
302 | Console.Write("To a non-Beatle: ");
303 | base.Receive(from, message);
304 | }
305 | }
306 | ```
307 |
308 | ## Улучшенная реальная реализация на C# (GoF) ##
309 |
310 | ```csharp
311 | ///
312 | /// MainApp startup class for .NET optimized
313 | /// Mediator Design Pattern.
314 | ///
315 | internal class MainApp
316 | {
317 | ///
318 | /// Entry point into console application.
319 | ///
320 | private static void Main()
321 | {
322 | // Create chatroom participants
323 | var George = new Beatle { Name = "George" };
324 | var Paul = new Beatle { Name = "Paul" };
325 | var Ringo = new Beatle { Name = "Ringo" };
326 | var John = new Beatle { Name = "John" };
327 | var Yoko = new NonBeatle { Name = "Yoko" };
328 |
329 | // Create chatroom and register participants
330 | var chatroom = new Chatroom();
331 | chatroom.Register(George);
332 | chatroom.Register(Paul);
333 | chatroom.Register(Ringo);
334 | chatroom.Register(John);
335 | chatroom.Register(Yoko);
336 |
337 | // Chatting participants
338 | Yoko.Send("John", "Hi John!");
339 | Paul.Send("Ringo", "All you need is love");
340 | Ringo.Send("George", "My sweet Lord");
341 | Paul.Send("John", "Can't buy me love");
342 | John.Send("Yoko", "My sweet love");
343 |
344 | // Wait for user
345 | Console.ReadKey();
346 | }
347 | }
348 |
349 | ///
350 | /// The 'Mediator' interface
351 | ///
352 | internal interface IChatroom
353 | {
354 | void Register(Participant participant);
355 |
356 | void Send(string from, string to, string message);
357 | }
358 |
359 | ///
360 | /// The 'ConcreteMediator' class
361 | ///
362 | internal class Chatroom : IChatroom
363 | {
364 | private Dictionary participants = new Dictionary();
365 |
366 | public void Register(Participant participant)
367 | {
368 | if (!participants.ContainsKey(participant.Name))
369 | {
370 | participants.Add(participant.Name, participant);
371 | }
372 |
373 | participant.Chatroom = this;
374 | }
375 |
376 | public void Send(string from, string to, string message)
377 | {
378 | var participant = participants[to];
379 | if (participant != null)
380 | {
381 | participant.Receive(from, message);
382 | }
383 | }
384 | }
385 |
386 | ///
387 | /// The 'AbstractColleague' class
388 | ///
389 | internal class Participant
390 | {
391 | // Gets or sets participant name
392 | public string Name { get; set; }
393 |
394 | // Gets or sets chatroom
395 | public Chatroom Chatroom { get; set; }
396 |
397 | // Send a message to given participant
398 | public void Send(string to, string message)
399 | {
400 | Chatroom.Send(Name, to, message);
401 | }
402 |
403 | // Receive message from participant
404 | public virtual void Receive(
405 | string from, string message)
406 | {
407 | Console.WriteLine("{0} to {1}: '{2}'",
408 | from, Name, message);
409 | }
410 | }
411 |
412 | ///
413 | /// A 'ConcreteColleague' class
414 | ///
415 | internal class Beatle : Participant
416 | {
417 | public override void Receive(string from, string message)
418 | {
419 | Console.Write("To a Beatle: ");
420 | base.Receive(from, message);
421 | }
422 | }
423 |
424 | ///
425 | /// A 'ConcreteColleague' class
426 | ///
427 | internal class NonBeatle : Participant
428 | {
429 | public override void Receive(string from, string message)
430 | {
431 | Console.Write("To a non-Beatle: ");
432 | base.Receive(from, message);
433 | }
434 | }
435 | ```
436 |
437 | ## Реализация на JAVA ##
438 |
439 | ```java
440 | TODO
441 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/mediator_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/mediator_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/momento.md:
--------------------------------------------------------------------------------
1 | # Хранитель (Memento) #
2 |
3 | Также известен как Лексема (Token).
4 |
5 | Паттерн Хранитель используется для реализации возврата к одному из предыдущих состояний.
6 |
7 | Классическая структура паттерна Хранитель:
8 |
9 | 
10 |
11 | Нестандартная структура паттерна Хранитель:
12 |
13 | 
14 |
15 | * Memento - Хранитель
16 |
17 | * Originator - Хозяин, Создатель
18 |
19 | * Caretaker - Посыльный, Опекун
20 |
21 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Хранитель_(шаблон_проектирования))
22 |
23 | ## Абстрактная реализация на C# (GoF) ##
24 |
25 | ```csharp
26 | ///
27 | /// MainApp startup class for Structural
28 | /// Memento Design Pattern.
29 | ///
30 | internal class MainApp
31 | {
32 | ///
33 | /// Entry point into console application.
34 | ///
35 | private static void Main()
36 | {
37 | Originator o = new Originator();
38 | o.State = "On";
39 |
40 | // Store internal state
41 | Caretaker c = new Caretaker();
42 | c.Memento = o.CreateMemento();
43 |
44 | // Continue changing originator
45 | o.State = "Off";
46 |
47 | // Restore saved state
48 | o.SetMemento(c.Memento);
49 |
50 | // Wait for user
51 | Console.ReadKey();
52 | }
53 | }
54 |
55 | ///
56 | /// The 'Originator' class
57 | ///
58 | internal class Originator
59 | {
60 | private string state;
61 |
62 | // Property
63 | public string State
64 | {
65 | get { return state; }
66 | set
67 | {
68 | state = value;
69 | Console.WriteLine("State = " + state);
70 | }
71 | }
72 |
73 | // Creates memento
74 | public Memento CreateMemento()
75 | {
76 | return (new Memento(state));
77 | }
78 |
79 | // Restores original state
80 | public void SetMemento(Memento memento)
81 | {
82 | Console.WriteLine("Restoring state...");
83 | State = memento.State;
84 | }
85 | }
86 |
87 | ///
88 | /// The 'Memento' class
89 | ///
90 | internal class Memento
91 | {
92 | private string state;
93 |
94 | // Constructor
95 | public Memento(string state)
96 | {
97 | this.state = state;
98 | }
99 |
100 | // Gets or sets state
101 | public string State
102 | {
103 | get { return state; }
104 | }
105 | }
106 |
107 | ///
108 | /// The 'Caretaker' class
109 | ///
110 | internal class Caretaker
111 | {
112 | private Memento memento;
113 |
114 | // Gets or sets memento
115 | public Memento Memento
116 | {
117 | set { memento = value; }
118 | get { return memento; }
119 | }
120 | }
121 | ```
122 |
123 | ## Реальная реализация на C# (GoF) ##
124 |
125 | ```charp
126 | ///
127 | /// MainApp startup class for Real-World
128 | /// Memento Design Pattern.
129 | ///
130 | internal class MainApp
131 | {
132 | ///
133 | /// Entry point into console application.
134 | ///
135 | private static void Main()
136 | {
137 | SalesProspect s = new SalesProspect();
138 | s.Name = "Noel van Halen";
139 | s.Phone = "(412) 256-0990";
140 | s.Budget = 25000.0;
141 |
142 | // Store internal state
143 | ProspectMemory m = new ProspectMemory();
144 | m.Memento = s.SaveMemento();
145 |
146 | // Continue changing originator
147 | s.Name = "Leo Welch";
148 | s.Phone = "(310) 209-7111";
149 | s.Budget = 1000000.0;
150 |
151 | // Restore saved state
152 | s.RestoreMemento(m.Memento);
153 |
154 | // Wait for user
155 | Console.ReadKey();
156 | }
157 | }
158 |
159 | ///
160 | /// The 'Originator' class
161 | ///
162 | internal class SalesProspect
163 | {
164 | private string name;
165 | private string phone;
166 | private double budget;
167 |
168 | // Gets or sets name
169 | public string Name
170 | {
171 | get { return name; }
172 | set
173 | {
174 | name = value;
175 | Console.WriteLine("Name: " + name);
176 | }
177 | }
178 |
179 | // Gets or sets phone
180 | public string Phone
181 | {
182 | get { return phone; }
183 | set
184 | {
185 | phone = value;
186 | Console.WriteLine("Phone: " + phone);
187 | }
188 | }
189 |
190 | // Gets or sets budget
191 | public double Budget
192 | {
193 | get { return budget; }
194 | set
195 | {
196 | budget = value;
197 | Console.WriteLine("Budget: " + budget);
198 | }
199 | }
200 |
201 | // Stores memento
202 | public Memento SaveMemento()
203 | {
204 | Console.WriteLine("\nSaving state --\n");
205 | return new Memento(name, phone, budget);
206 | }
207 |
208 | // Restores memento
209 | public void RestoreMemento(Memento memento)
210 | {
211 | Console.WriteLine("\nRestoring state --\n");
212 | this.Name = memento.Name;
213 | this.Phone = memento.Phone;
214 | this.Budget = memento.Budget;
215 | }
216 | }
217 |
218 | ///
219 | /// The 'Memento' class
220 | ///
221 | internal class Memento
222 | {
223 | private string name;
224 | private string phone;
225 | private double budget;
226 |
227 | // Constructor
228 | public Memento(string name, string phone, double budget)
229 | {
230 | this.name = name;
231 | this.phone = phone;
232 | this.budget = budget;
233 | }
234 |
235 | // Gets or sets name
236 | public string Name
237 | {
238 | get { return name; }
239 | set { name = value; }
240 | }
241 |
242 | // Gets or set phone
243 | public string Phone
244 | {
245 | get { return phone; }
246 | set { phone = value; }
247 | }
248 |
249 | // Gets or sets budget
250 | public double Budget
251 | {
252 | get { return budget; }
253 | set { budget = value; }
254 | }
255 | }
256 |
257 | ///
258 | /// The 'Caretaker' class
259 | ///
260 | internal class ProspectMemory
261 | {
262 | private Memento memento;
263 |
264 | // Property
265 | public Memento Memento
266 | {
267 | set { memento = value; }
268 | get { return memento; }
269 | }
270 | }
271 | ```
272 |
273 | ## Улучшенная реальная реализация на C# (GoF) ##
274 |
275 | ```csharp
276 | ///
277 | /// MainApp startup class for .NET optimized
278 | /// Memento Design Pattern.
279 | ///
280 | internal class MainApp
281 | {
282 | ///
283 | /// Entry point into console application.
284 | ///
285 | private static void Main()
286 | {
287 | // Init sales prospect through object initialization
288 | var s = new SalesProspect
289 | {
290 | Name = "Joel van Halen",
291 | Phone = "(412) 256-0990",
292 | Budget = 25000.0
293 | };
294 |
295 | // Store internal state
296 | var m = new ProspectMemory();
297 | m.Memento = s.SaveMemento();
298 |
299 | // Change originator
300 | s.Name = "Leo Welch";
301 | s.Phone = "(310) 209-7111";
302 | s.Budget = 1000000.0;
303 |
304 | // Restore saved state
305 | s.RestoreMemento(m.Memento);
306 |
307 | // Wait for user
308 | Console.ReadKey();
309 | }
310 | }
311 |
312 | ///
313 | /// The 'Originator' class
314 | ///
315 | [Serializable]
316 | internal class SalesProspect
317 | {
318 | private string name;
319 | private string phone;
320 | private double budget;
321 |
322 | // Gets or sets name
323 | public string Name
324 | {
325 | get { return name; }
326 | set
327 | {
328 | name = value;
329 | Console.WriteLine("Name: " + name);
330 | }
331 | }
332 |
333 | // Gets or sets phone
334 | public string Phone
335 | {
336 | get { return phone; }
337 | set
338 | {
339 | phone = value;
340 | Console.WriteLine("Phone: " + phone);
341 | }
342 | }
343 |
344 | // Gets or sets budget
345 | public double Budget
346 | {
347 | get { return budget; }
348 | set
349 | {
350 | budget = value;
351 | Console.WriteLine("Budget: " + budget);
352 | }
353 | }
354 |
355 | // Stores (serializes) memento
356 | public Memento SaveMemento()
357 | {
358 | Console.WriteLine("\nSaving state --\n");
359 |
360 | var memento = new Memento();
361 | return memento.Serialize(this);
362 | }
363 |
364 | // Restores (deserializes) memento
365 | public void RestoreMemento(Memento memento)
366 | {
367 | Console.WriteLine("\nRestoring state --\n");
368 |
369 | var s = (SalesProspect)memento.Deserialize();
370 | this.Name = s.Name;
371 | this.Phone = s.Phone;
372 | this.Budget = s.Budget;
373 | }
374 | }
375 |
376 | ///
377 | /// The 'Memento' class
378 | ///
379 | internal class Memento
380 | {
381 | private MemoryStream stream = new MemoryStream();
382 | private SoapFormatter formatter = new SoapFormatter();
383 |
384 | public Memento Serialize(object o)
385 | {
386 | formatter.Serialize(stream, o);
387 | return this;
388 | }
389 |
390 | public object Deserialize()
391 | {
392 | stream.Seek(0, SeekOrigin.Begin);
393 | object o = formatter.Deserialize(stream);
394 | stream.Close();
395 |
396 | return o;
397 | }
398 | }
399 |
400 | ///
401 | /// The 'Caretaker' class
402 | ///
403 | internal class ProspectMemory
404 | {
405 | public Memento Memento { get; set; }
406 | }
407 | ```
408 |
409 | ## Реализация на JAVA ##
410 |
411 | ```java
412 | TODO
413 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/momento_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/momento_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/momento_UML_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/momento_UML_2.png
--------------------------------------------------------------------------------
/design_patterns/behavioral/observer.md:
--------------------------------------------------------------------------------
1 | # Наблюдатель (Observer) #
2 |
3 | Также известен как Подчиненные (Dependents) или Издатель-подписчик (Publish-Subscribe).
4 |
5 | Паттерн Наблюдатель определяет отношение "один-ко-многим" между объектами таким образом,
6 | что при изменении состояния субъекта наблюдения происходит автоматическое оповещение и обновление всех зависимых объектов-наблюдателей.
7 |
8 | 
9 |
10 | * Subject - абстрактный наблюдаемый субъект
11 |
12 | * ConcreteSubject - конкретный наблюдаемый субъект
13 |
14 | * Observer - абстрактный наблюдатель
15 |
16 | * ConcreteObserver - конкретный наблюдатель
17 |
18 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Наблюдатель_(шаблон_проектирования))
19 |
20 | Встроенная в JDK реализация паттерна в _java.util.Observable_ и _java.util.Observer_
21 | (Observable - является классом, а не интерфейсом, что значительно снижает его полезность).
22 |
23 | В SWING (и других GUI фреймворках) наблюдателями выступают Listener'ы, которые ожидают событий от UI
24 | (нажатие на кнопку, прокрутка и другое).
25 |
26 | ## Абстрактная реализация на C# (GoF) ##
27 |
28 | ```csharp
29 | ///
30 | /// MainApp startup class for Structural
31 | /// Observer Design Pattern.
32 | ///
33 | internal class MainApp
34 | {
35 | ///
36 | /// Entry point into console application.
37 | ///
38 | private static void Main()
39 | {
40 | // Configure Observer pattern
41 | ConcreteSubject s = new ConcreteSubject();
42 |
43 | s.Attach(new ConcreteObserver(s, "X"));
44 | s.Attach(new ConcreteObserver(s, "Y"));
45 | s.Attach(new ConcreteObserver(s, "Z"));
46 |
47 | // Change subject and notify observers
48 | s.SubjectState = "ABC";
49 | s.Notify();
50 |
51 | // Wait for user
52 | Console.ReadKey();
53 | }
54 | }
55 |
56 | ///
57 | /// The 'Subject' abstract class
58 | ///
59 | internal abstract class Subject
60 | {
61 | private List observers = new List();
62 |
63 | public void Attach(Observer observer)
64 | {
65 | observers.Add(observer);
66 | }
67 |
68 | public void Detach(Observer observer)
69 | {
70 | observers.Remove(observer);
71 | }
72 |
73 | public void Notify()
74 | {
75 | foreach (Observer o in observers)
76 | {
77 | o.Update();
78 | }
79 | }
80 | }
81 |
82 | ///
83 | /// The 'ConcreteSubject' class
84 | ///
85 | internal class ConcreteSubject : Subject
86 | {
87 | private string subjectState;
88 |
89 | // Gets or sets subject state
90 | public string SubjectState
91 | {
92 | get { return subjectState; }
93 | set { subjectState = value; }
94 | }
95 | }
96 |
97 | ///
98 | /// The 'Observer' abstract class
99 | ///
100 | internal abstract class Observer
101 | {
102 | public abstract void Update();
103 | }
104 |
105 | ///
106 | /// The 'ConcreteObserver' class
107 | ///
108 | internal class ConcreteObserver : Observer
109 | {
110 | private string name;
111 | private string observerState;
112 | private ConcreteSubject subject;
113 |
114 | // Constructor
115 | public ConcreteObserver(
116 | ConcreteSubject subject, string name)
117 | {
118 | this.subject = subject;
119 | this.name = name;
120 | }
121 |
122 | public override void Update()
123 | {
124 | observerState = subject.SubjectState;
125 | Console.WriteLine("Observer {0}'s new state is {1}",
126 | name, observerState);
127 | }
128 |
129 | // Gets or sets subject
130 | public ConcreteSubject Subject
131 | {
132 | get { return subject; }
133 | set { subject = value; }
134 | }
135 | }
136 | ```
137 |
138 | ## Реальная реализация на C# (GoF) ##
139 |
140 | ```charp
141 | ///
142 | /// MainApp startup class for Real-World
143 | /// Observer Design Pattern.
144 | ///
145 | internal class MainApp
146 | {
147 | ///
148 | /// Entry point into console application.
149 | ///
150 | private static void Main()
151 | {
152 | // Create IBM stock and attach investors
153 | IBM ibm = new IBM("IBM", 120.00);
154 | ibm.Attach(new Investor("Sorros"));
155 | ibm.Attach(new Investor("Berkshire"));
156 |
157 | // Fluctuating prices will notify investors
158 | ibm.Price = 120.10;
159 | ibm.Price = 121.00;
160 | ibm.Price = 120.50;
161 | ibm.Price = 120.75;
162 |
163 | // Wait for user
164 | Console.ReadKey();
165 | }
166 | }
167 |
168 | ///
169 | /// The 'Subject' abstract class
170 | ///
171 | internal abstract class Stock
172 | {
173 | private string symbol;
174 | private double price;
175 | private List investors = new List();
176 |
177 | // Constructor
178 | public Stock(string symbol, double price)
179 | {
180 | this.symbol = symbol;
181 | this.price = price;
182 | }
183 |
184 | public void Attach(IInvestor investor)
185 | {
186 | investors.Add(investor);
187 | }
188 |
189 | public void Detach(IInvestor investor)
190 | {
191 | investors.Remove(investor);
192 | }
193 |
194 | public void Notify()
195 | {
196 | foreach (IInvestor investor in investors)
197 | {
198 | investor.Update(this);
199 | }
200 |
201 | Console.WriteLine("");
202 | }
203 |
204 | // Gets or sets the price
205 | public double Price
206 | {
207 | get { return price; }
208 | set
209 | {
210 | if (price != value)
211 | {
212 | price = value;
213 | Notify();
214 | }
215 | }
216 | }
217 |
218 | // Gets the symbol
219 | public string Symbol
220 | {
221 | get { return symbol; }
222 | }
223 | }
224 |
225 | ///
226 | /// The 'ConcreteSubject' class
227 | ///
228 | internal class IBM : Stock
229 | {
230 | // Constructor
231 | public IBM(string symbol, double price)
232 | : base(symbol, price)
233 | {
234 | }
235 | }
236 |
237 | ///
238 | /// The 'Observer' interface
239 | ///
240 | internal interface IInvestor
241 | {
242 | void Update(Stock stock);
243 | }
244 |
245 | ///
246 | /// The 'ConcreteObserver' class
247 | ///
248 | internal class Investor : IInvestor
249 | {
250 | private string name;
251 | private Stock stock;
252 |
253 | // Constructor
254 | public Investor(string name)
255 | {
256 | this.name = name;
257 | }
258 |
259 | public void Update(Stock stock)
260 | {
261 | Console.WriteLine("Notified {0} of {1}'s " +
262 | "change to {2:C}", name, stock.Symbol, stock.Price);
263 | }
264 |
265 | // Gets or sets the stock
266 | public Stock Stock
267 | {
268 | get { return stock; }
269 | set { stock = value; }
270 | }
271 | }
272 | ```
273 |
274 | ## Улучшенная реальная реализация на C# (GoF) ##
275 |
276 | ```csharp
277 | ///
278 | /// MainApp startup class for .NET optimized
279 | /// Observer Design Pattern.
280 | ///
281 | internal class MainApp
282 | {
283 | ///
284 | /// Entry point into console application.
285 | ///
286 | private static void Main()
287 | {
288 | // Create IBM stock and attach investors
289 | var ibm = new IBM(120.00);
290 |
291 | // Attach 'listeners', i.e. Investors
292 | ibm.Attach(new Investor { Name = "Sorros" });
293 | ibm.Attach(new Investor { Name = "Berkshire" });
294 |
295 | // Fluctuating prices will notify listening investors
296 | ibm.Price = 120.10;
297 | ibm.Price = 121.00;
298 | ibm.Price = 120.50;
299 | ibm.Price = 120.75;
300 |
301 | // Wait for user
302 | Console.ReadKey();
303 | }
304 | }
305 |
306 | // Custom event arguments
307 | public class ChangeEventArgs : EventArgs
308 | {
309 | // Gets or sets symbol
310 | public string Symbol { get; set; }
311 |
312 | // Gets or sets price
313 | public double Price { get; set; }
314 | }
315 |
316 | ///
317 | /// The 'Subject' abstract class
318 | ///
319 | internal abstract class Stock
320 | {
321 | protected string symbol;
322 | protected double price;
323 |
324 | // Constructor
325 | public Stock(string symbol, double price)
326 | {
327 | this.symbol = symbol;
328 | this.price = price;
329 | }
330 |
331 | // Event
332 | public event EventHandler Change;
333 |
334 | // Invoke the Change event
335 | public virtual void OnChange(ChangeEventArgs e)
336 | {
337 | if (Change != null)
338 | {
339 | Change(this, e);
340 | }
341 | }
342 |
343 | public void Attach(IInvestor investor)
344 | {
345 | Change += investor.Update;
346 | }
347 |
348 | public void Detach(IInvestor investor)
349 | {
350 | Change -= investor.Update;
351 | }
352 |
353 | // Gets or sets the price
354 | public double Price
355 | {
356 | get { return price; }
357 | set
358 | {
359 | if (price != value)
360 | {
361 | price = value;
362 | OnChange(new ChangeEventArgs { Symbol = symbol, Price = price });
363 | Console.WriteLine("");
364 | }
365 | }
366 | }
367 | }
368 |
369 | ///
370 | /// The 'ConcreteSubject' class
371 | ///
372 | internal class IBM : Stock
373 | {
374 | // Constructor - symbol for IBM is always same
375 | public IBM(double price)
376 | : base("IBM", price)
377 | {
378 | }
379 | }
380 |
381 | ///
382 | /// The 'Observer' interface
383 | ///
384 | internal interface IInvestor
385 | {
386 | void Update(object sender, ChangeEventArgs e);
387 | }
388 |
389 | ///
390 | /// The 'ConcreteObserver' class
391 | ///
392 | internal class Investor : IInvestor
393 | {
394 | // Gets or sets the investor name
395 | public string Name { get; set; }
396 |
397 | // Gets or sets the stock
398 | public Stock Stock { get; set; }
399 |
400 | public void Update(object sender, ChangeEventArgs e)
401 | {
402 | Console.WriteLine("Notified {0} of {1}'s " +
403 | "change to {2:C}", Name, e.Symbol, e.Price);
404 | }
405 | }
406 | ```
407 |
408 | ## Реализация на C# (Head First) ##
409 |
410 | ```csharp
411 | internal class DotNetObserverExample
412 | {
413 | private static void Main()
414 | {
415 | // Create listeners
416 | var angel = new ActionListener("Angel");
417 | var devil = new ActionListener("Devil");
418 |
419 | // Create Button and attach listeners
420 | var button = new Button("Click Me");
421 | button.Attach(angel);
422 | button.Attach(devil);
423 |
424 | // Simulate clicks on button
425 | button.Push(1, 3);
426 | button.Push(5, 4);
427 | button.Push(8, 5);
428 |
429 | // Wait for user
430 | Console.ReadKey();
431 | }
432 | }
433 |
434 | #region EventArgs
435 |
436 | // Custom event arguments
437 | public class ClickEventArgs : EventArgs
438 | {
439 | public int X { get; private set; }
440 | public int Y { get; private set; }
441 |
442 | // Constructor
443 | public ClickEventArgs(int x, int y)
444 | {
445 | this.X = x;
446 | this.Y = y;
447 | }
448 | }
449 |
450 | #endregion EventArgs
451 |
452 | #region Controls
453 |
454 | // Base class for UI controls
455 |
456 | internal abstract class Control
457 | {
458 | protected string text;
459 |
460 | // Constructor
461 | public Control(string text)
462 | {
463 | this.text = text;
464 | }
465 |
466 | // Event
467 | public event EventHandler Click;
468 |
469 | // Invoke the Click event
470 | public virtual void OnClick(ClickEventArgs e)
471 | {
472 | if (Click != null)
473 | {
474 | Click(this, e);
475 | }
476 | }
477 |
478 | public void Attach(ActionListener listener)
479 | {
480 | Click += listener.Update;
481 | }
482 |
483 | public void Detach(ActionListener listener)
484 | {
485 | Click -= listener.Update;
486 | }
487 |
488 | // Use this method to simulate push (click) events
489 | public void Push(int x, int y)
490 | {
491 | OnClick(new ClickEventArgs(x, y));
492 | Console.WriteLine("");
493 | }
494 | }
495 |
496 | // Button control
497 |
498 | internal class Button : Control
499 | {
500 | // Constructor
501 | public Button(string text)
502 | : base(text)
503 | {
504 | }
505 | }
506 |
507 | #endregion Controls
508 |
509 | #region ActionListener
510 |
511 | internal interface IActionListener
512 | {
513 | void Update(object sender, ClickEventArgs e);
514 | }
515 |
516 | internal class ActionListener : IActionListener
517 | {
518 | private string _name;
519 |
520 | // Constructor
521 | public ActionListener(string name)
522 | {
523 | this._name = name;
524 | }
525 |
526 | public void Update(object sender, ClickEventArgs e)
527 | {
528 | Console.WriteLine("Notified {0} of click at ({1},{2})",
529 | _name, e.X, e.Y);
530 | }
531 | }
532 |
533 | #endregion ActionListener
534 | ```
535 |
536 | ## Реализация на JAVA ##
537 |
538 | ```java
539 | TODO
540 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/observer_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/observer_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/state_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/state_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/strategy.md:
--------------------------------------------------------------------------------
1 | # Стратегия (Strategy) #
2 |
3 | Также известен как Политика (Policy).
4 |
5 | Паттерн Стратегия определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает взаимозаменяемость.
6 | Он позволяет модифицировать алгоритмы независимо от их использования на стороне клиента.
7 |
8 | 
9 |
10 | * Strategy - абстрактная стратегия
11 |
12 | * ConcreteStrategies - конкретные стратегии
13 |
14 | * Context - контекст
15 |
16 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Стратегия_(шаблон_проектирования))
17 |
18 | ## Абстрактная реализация на C# (GoF) ##
19 |
20 | ```csharp
21 | ///
22 | /// MainApp startup class for Structural
23 | /// Strategy Design Pattern.
24 | ///
25 | internal class MainApp
26 | {
27 | ///
28 | /// Entry point into console application.
29 | ///
30 | private static void Main()
31 | {
32 | Context context;
33 |
34 | // Three contexts following different strategies
35 | context = new Context(new ConcreteStrategyA());
36 | context.ContextInterface();
37 |
38 | context = new Context(new ConcreteStrategyB());
39 | context.ContextInterface();
40 |
41 | context = new Context(new ConcreteStrategyC());
42 | context.ContextInterface();
43 |
44 | // Wait for user
45 | Console.ReadKey();
46 | }
47 | }
48 |
49 | ///
50 | /// The 'Strategy' abstract class
51 | ///
52 | internal abstract class Strategy
53 | {
54 | public abstract void AlgorithmInterface();
55 | }
56 |
57 | ///
58 | /// A 'ConcreteStrategy' class
59 | ///
60 | internal class ConcreteStrategyA : Strategy
61 | {
62 | public override void AlgorithmInterface()
63 | {
64 | Console.WriteLine(
65 | "Called ConcreteStrategyA.AlgorithmInterface()");
66 | }
67 | }
68 |
69 | ///
70 | /// A 'ConcreteStrategy' class
71 | ///
72 | internal class ConcreteStrategyB : Strategy
73 | {
74 | public override void AlgorithmInterface()
75 | {
76 | Console.WriteLine(
77 | "Called ConcreteStrategyB.AlgorithmInterface()");
78 | }
79 | }
80 |
81 | ///
82 | /// A 'ConcreteStrategy' class
83 | ///
84 | internal class ConcreteStrategyC : Strategy
85 | {
86 | public override void AlgorithmInterface()
87 | {
88 | Console.WriteLine(
89 | "Called ConcreteStrategyC.AlgorithmInterface()");
90 | }
91 | }
92 |
93 | ///
94 | /// The 'Context' class
95 | ///
96 | internal class Context
97 | {
98 | private Strategy strategy;
99 |
100 | // Constructor
101 | public Context(Strategy strategy)
102 | {
103 | this.strategy = strategy;
104 | }
105 |
106 | public void ContextInterface()
107 | {
108 | strategy.AlgorithmInterface();
109 | }
110 | }
111 | ```
112 |
113 | ## Реальная реализация на C# (GoF) ##
114 |
115 | ```charp
116 | ///
117 | /// MainApp startup class for Real-World
118 | /// Strategy Design Pattern.
119 | ///
120 | internal class MainApp
121 | {
122 | ///
123 | /// Entry point into console application.
124 | ///
125 | private static void Main()
126 | {
127 | // Two contexts following different strategies
128 | SortedList studentRecords = new SortedList();
129 |
130 | studentRecords.Add("Samual");
131 | studentRecords.Add("Jimmy");
132 | studentRecords.Add("Sandra");
133 | studentRecords.Add("Vivek");
134 | studentRecords.Add("Anna");
135 |
136 | studentRecords.SetSortStrategy(new QuickSort());
137 | studentRecords.Sort();
138 |
139 | studentRecords.SetSortStrategy(new ShellSort());
140 | studentRecords.Sort();
141 |
142 | studentRecords.SetSortStrategy(new MergeSort());
143 | studentRecords.Sort();
144 |
145 | // Wait for user
146 | Console.ReadKey();
147 | }
148 | }
149 |
150 | ///
151 | /// The 'Strategy' abstract class
152 | ///
153 | internal abstract class SortStrategy
154 | {
155 | public abstract void Sort(List list);
156 | }
157 |
158 | ///
159 | /// A 'ConcreteStrategy' class
160 | ///
161 | internal class QuickSort : SortStrategy
162 | {
163 | public override void Sort(List list)
164 | {
165 | list.Sort(); // Default is Quicksort
166 | Console.WriteLine("QuickSorted list ");
167 | }
168 | }
169 |
170 | ///
171 | /// A 'ConcreteStrategy' class
172 | ///
173 | internal class ShellSort : SortStrategy
174 | {
175 | public override void Sort(List list)
176 | {
177 | //list.ShellSort(); not-implemented
178 | Console.WriteLine("ShellSorted list ");
179 | }
180 | }
181 |
182 | ///
183 | /// A 'ConcreteStrategy' class
184 | ///
185 | internal class MergeSort : SortStrategy
186 | {
187 | public override void Sort(List list)
188 | {
189 | //list.MergeSort(); not-implemented
190 | Console.WriteLine("MergeSorted list ");
191 | }
192 | }
193 |
194 | ///
195 | /// The 'Context' class
196 | ///
197 | internal class SortedList
198 | {
199 | private List list = new List();
200 | private SortStrategy sortstrategy;
201 |
202 | public void SetSortStrategy(SortStrategy sortstrategy)
203 | {
204 | this.sortstrategy = sortstrategy;
205 | }
206 |
207 | public void Add(string name)
208 | {
209 | list.Add(name);
210 | }
211 |
212 | public void Sort()
213 | {
214 | sortstrategy.Sort(list);
215 |
216 | // Iterate over list and display results
217 | foreach (string name in list)
218 | {
219 | Console.WriteLine(" " + name);
220 | }
221 | Console.WriteLine();
222 | }
223 | }
224 | ```
225 |
226 | ## Улучшенная реальная реализация на C# (GoF) ##
227 |
228 | ```csharp
229 | ///
230 | /// MainApp startup class for .NET optimized
231 | /// Strategy Design Pattern.
232 | ///
233 | internal class MainApp
234 | {
235 | ///
236 | /// Entry point into console application.
237 | ///
238 | private static void Main()
239 | {
240 | // Two contexts following different strategies
241 | var studentRecords = new SortedList()
242 | {
243 | new Student{ Name = "Samual", Ssn = "154-33-2009" },
244 | new Student{ Name = "Jimmy", Ssn = "487-43-1665" },
245 | new Student{ Name = "Sandra", Ssn = "655-00-2944" },
246 | new Student{ Name = "Vivek", Ssn = "133-98-8399" },
247 | new Student{ Name = "Anna", Ssn = "760-94-9844" },
248 | };
249 |
250 | studentRecords.SortStrategy = new QuickSort();
251 | studentRecords.SortStudents();
252 |
253 | studentRecords.SortStrategy = new ShellSort();
254 | studentRecords.SortStudents();
255 |
256 | studentRecords.SortStrategy = new MergeSort();
257 | studentRecords.SortStudents();
258 |
259 | // Wait for user
260 | Console.ReadKey();
261 | }
262 | }
263 |
264 | ///
265 | /// The 'Strategy' interface
266 | ///
267 | internal interface ISortStrategy
268 | {
269 | void Sort(List list);
270 | }
271 |
272 | ///
273 | /// A 'ConcreteStrategy' class
274 | ///
275 | internal class QuickSort : ISortStrategy
276 | {
277 | public void Sort(List list)
278 | {
279 | // Call overloaded Sort
280 | Sort(list, 0, list.Count - 1);
281 | Console.WriteLine("QuickSorted list ");
282 | }
283 |
284 | // Recursively sort
285 | private void Sort(List list, int left, int right)
286 | {
287 | int lhold = left;
288 | int rhold = right;
289 |
290 | // Use a random pivot
291 | var random = new Random();
292 | int pivot = random.Next(left, right);
293 | Swap(list, pivot, left);
294 | pivot = left;
295 | left++;
296 |
297 | while (right >= left)
298 | {
299 | int compareleft = list[left].Name.CompareTo(list[pivot].Name);
300 | int compareright = list[right].Name.CompareTo(list[pivot].Name);
301 |
302 | if ((compareleft >= 0) && (compareright < 0))
303 | {
304 | Swap(list, left, right);
305 | }
306 | else
307 | {
308 | if (compareleft >= 0)
309 | {
310 | right--;
311 | }
312 | else
313 | {
314 | if (compareright < 0)
315 | {
316 | left++;
317 | }
318 | else
319 | {
320 | right--;
321 | left++;
322 | }
323 | }
324 | }
325 | }
326 | Swap(list, pivot, right);
327 | pivot = right;
328 |
329 | if (pivot > lhold) Sort(list, lhold, pivot);
330 | if (rhold > pivot + 1) Sort(list, pivot + 1, rhold);
331 | }
332 |
333 | // Swap helper function
334 | private void Swap(List list, int left, int right)
335 | {
336 | var temp = list[right];
337 | list[right] = list[left];
338 | list[left] = temp;
339 | }
340 | }
341 |
342 | ///
343 | /// A 'ConcreteStrategy' class
344 | ///
345 | internal class ShellSort : ISortStrategy
346 | {
347 | public void Sort(List list)
348 | {
349 | // ShellSort(); not-implemented
350 | Console.WriteLine("ShellSorted list ");
351 | }
352 | }
353 |
354 | ///
355 | /// A 'ConcreteStrategy' class
356 | ///
357 | internal class MergeSort : ISortStrategy
358 | {
359 | public void Sort(List list)
360 | {
361 | // MergeSort(); not-implemented
362 | Console.WriteLine("MergeSorted list ");
363 | }
364 | }
365 |
366 | ///
367 | /// The 'Context' class
368 | ///
369 | internal class SortedList : List
370 | {
371 | // Sets sort strategy
372 | public ISortStrategy SortStrategy { get; set; }
373 |
374 | // Perform sort
375 | public void SortStudents()
376 | {
377 | SortStrategy.Sort(this);
378 |
379 | // Display sort results
380 | foreach (var student in this)
381 | {
382 | Console.WriteLine(" " + student.Name);
383 | }
384 | Console.WriteLine();
385 | }
386 | }
387 |
388 | ///
389 | /// Represents a student
390 | ///
391 | internal class Student
392 | {
393 | // Gets or sets student name
394 | public string Name { get; set; }
395 |
396 | // Gets or sets student social security number
397 | public string Ssn { get; set; }
398 | }
399 | ```
400 |
401 | ## Реализация на C# (Head First) ##
402 |
403 | ```csharp
404 | public class MiniDuckSimulator
405 | {
406 | private static void Main(string[] args)
407 | {
408 | Duck mallard = new MallardDuck();
409 | mallard.Display();
410 | mallard.PerformQuack();
411 | mallard.PerformFly();
412 |
413 | Console.WriteLine("");
414 |
415 | Duck model = new ModelDuck();
416 | model.Display();
417 | model.PerformFly();
418 |
419 | model.FlyBehavior = new FlyRocketPowered();
420 | model.PerformFly();
421 |
422 | // Wait for user input
423 | Console.ReadKey();
424 | }
425 | }
426 |
427 | #region Duck
428 |
429 | public abstract class Duck
430 | {
431 | public IFlyBehavior FlyBehavior { get; set; }
432 | public IQuackBehavior QuackBehavior { get; set; }
433 |
434 | public abstract void Display();
435 |
436 | public void PerformFly()
437 | {
438 | FlyBehavior.Fly();
439 | }
440 |
441 | public void PerformQuack()
442 | {
443 | QuackBehavior.Quack();
444 | }
445 |
446 | public void Swim()
447 | {
448 | Console.WriteLine("All ducks float, even decoys!");
449 | }
450 | }
451 |
452 | public class MallardDuck : Duck
453 | {
454 | public MallardDuck()
455 | {
456 | QuackBehavior = new LoudQuack();
457 | FlyBehavior = new FlyWithWings();
458 | }
459 |
460 | override public void Display()
461 | {
462 | Console.WriteLine("I'm a real Mallard duck");
463 | }
464 | }
465 |
466 | public class ModelDuck : Duck
467 | {
468 | public ModelDuck()
469 | {
470 | QuackBehavior = new LoudQuack();
471 | FlyBehavior = new FlyNoWay();
472 | }
473 |
474 | override public void Display()
475 | {
476 | Console.WriteLine("I'm a model duck");
477 | }
478 | }
479 |
480 | #endregion Duck
481 |
482 | #region FlyBehavior
483 |
484 | public interface IFlyBehavior
485 | {
486 | void Fly();
487 | }
488 |
489 | public class FlyWithWings : IFlyBehavior
490 | {
491 | public void Fly()
492 | {
493 | Console.WriteLine("I'm flying!!");
494 | }
495 | }
496 |
497 | public class FlyNoWay : IFlyBehavior
498 | {
499 | public void Fly()
500 | {
501 | Console.WriteLine("I can't fly");
502 | }
503 | }
504 |
505 | public class FlyRocketPowered : IFlyBehavior
506 | {
507 | public void Fly()
508 | {
509 | Console.WriteLine("I'm flying with a rocket!");
510 | }
511 | }
512 |
513 | #endregion FlyBehavior
514 |
515 | #region QuackBehavior
516 |
517 | public interface IQuackBehavior
518 | {
519 | void Quack();
520 | }
521 |
522 | // Name it LoadQuack to avoid conflict with method name
523 | public class LoudQuack : IQuackBehavior
524 | {
525 | public void Quack()
526 | {
527 | Console.WriteLine("LoudQuack");
528 | }
529 | }
530 |
531 | public class MuteQuack : IQuackBehavior
532 | {
533 | public void Quack()
534 | {
535 | Console.WriteLine("<< Silence >>");
536 | }
537 | }
538 |
539 | public class Squeak : IQuackBehavior
540 | {
541 | public void Quack()
542 | {
543 | Console.WriteLine("Squeak");
544 | }
545 | }
546 |
547 | #endregion QuackBehavior
548 | ```
549 |
550 | ## Реализация на JAVA ##
551 |
552 | ```java
553 | TODO
554 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/strategy_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/strategy_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/template_method.md:
--------------------------------------------------------------------------------
1 | # Шаблонный метод (Template method) #
2 |
3 | Паттерн Шаблонный Метод задает "скелет" алгоритма в методе, оставляя определение реализации некоторых шагов субклассам.
4 | Субклассы могут переопределять некоторые части алгоритма без изменения его структуры.
5 |
6 | 
7 |
8 | * AbstractClass - абстрактный класс
9 |
10 | * ConcreteClass - конкретный класс
11 |
12 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Шаблонный_метод_(шаблон_проектирования))
13 |
14 | ## Абстрактная реализация на C# (GoF) ##
15 |
16 | ```csharp
17 | ///
18 | /// MainApp startup class for Real-World
19 | /// Template Design Pattern.
20 | ///
21 | internal class MainApp
22 | {
23 | ///
24 | /// Entry point into console application.
25 | ///
26 | private static void Main()
27 | {
28 | AbstractClass aA = new ConcreteClassA();
29 | aA.TemplateMethod();
30 |
31 | AbstractClass aB = new ConcreteClassB();
32 | aB.TemplateMethod();
33 |
34 | // Wait for user
35 | Console.ReadKey();
36 | }
37 | }
38 |
39 | ///
40 | /// The 'AbstractClass' abstract class
41 | ///
42 | internal abstract class AbstractClass
43 | {
44 | public abstract void PrimitiveOperation1();
45 |
46 | public abstract void PrimitiveOperation2();
47 |
48 | // The "Template method"
49 | public void TemplateMethod()
50 | {
51 | PrimitiveOperation1();
52 | PrimitiveOperation2();
53 | Console.WriteLine("");
54 | }
55 | }
56 |
57 | ///
58 | /// A 'ConcreteClass' class
59 | ///
60 | internal class ConcreteClassA : AbstractClass
61 | {
62 | public override void PrimitiveOperation1()
63 | {
64 | Console.WriteLine("ConcreteClassA.PrimitiveOperation1()");
65 | }
66 |
67 | public override void PrimitiveOperation2()
68 | {
69 | Console.WriteLine("ConcreteClassA.PrimitiveOperation2()");
70 | }
71 | }
72 |
73 | ///
74 | /// A 'ConcreteClass' class
75 | ///
76 | internal class ConcreteClassB : AbstractClass
77 | {
78 | public override void PrimitiveOperation1()
79 | {
80 | Console.WriteLine("ConcreteClassB.PrimitiveOperation1()");
81 | }
82 |
83 | public override void PrimitiveOperation2()
84 | {
85 | Console.WriteLine("ConcreteClassB.PrimitiveOperation2()");
86 | }
87 | }
88 | ```
89 |
90 | ## Реальная реализация на C# (GoF) ##
91 |
92 | ```charp
93 | ///
94 | /// MainApp startup class for Real-World
95 | /// Template Design Pattern.
96 | ///
97 | internal class MainApp
98 | {
99 | ///
100 | /// Entry point into console application.
101 | ///
102 | private static void Main()
103 | {
104 | DataAccessObject daoCategories = new Categories();
105 | daoCategories.Run();
106 |
107 | DataAccessObject daoProducts = new Products();
108 | daoProducts.Run();
109 |
110 | // Wait for user
111 | Console.ReadKey();
112 | }
113 | }
114 |
115 | ///
116 | /// The 'AbstractClass' abstract class
117 | ///
118 | internal abstract class DataAccessObject
119 | {
120 | protected string connectionString;
121 | protected DataSet dataSet;
122 |
123 | public virtual void Connect()
124 | {
125 | // Make sure mdb is available to app
126 | connectionString =
127 | "provider=Microsoft.JET.OLEDB.4.0; " +
128 | "data source=..\\..\\..\\db1.mdb";
129 | }
130 |
131 | public abstract void Select();
132 |
133 | public abstract void Process();
134 |
135 | public virtual void Disconnect()
136 | {
137 | connectionString = "";
138 | }
139 |
140 | // The 'Template Method'
141 | public void Run()
142 | {
143 | Connect();
144 | Select();
145 | Process();
146 | Disconnect();
147 | }
148 | }
149 |
150 | ///
151 | /// A 'ConcreteClass' class
152 | ///
153 | internal class Categories : DataAccessObject
154 | {
155 | public override void Select()
156 | {
157 | string sql = "SELECT CategoryName FROM Categories";
158 | OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
159 | sql, connectionString);
160 |
161 | dataSet = new DataSet();
162 | dataAdapter.Fill(dataSet, "Categories");
163 | }
164 |
165 | public override void Process()
166 | {
167 | Console.WriteLine("Categories ---- ");
168 |
169 | DataTable dataTable = dataSet.Tables["Categories"];
170 | foreach (DataRow row in dataTable.Rows)
171 | {
172 | Console.WriteLine(row["CategoryName"]);
173 | }
174 | Console.WriteLine();
175 | }
176 | }
177 |
178 | ///
179 | /// A 'ConcreteClass' class
180 | ///
181 | internal class Products : DataAccessObject
182 | {
183 | public override void Select()
184 | {
185 | string sql = "SELECT ProductName FROM Products";
186 | OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
187 | sql, connectionString);
188 |
189 | dataSet = new DataSet();
190 | dataAdapter.Fill(dataSet, "Products");
191 | }
192 |
193 | public override void Process()
194 | {
195 | Console.WriteLine("Products ---- ");
196 | DataTable dataTable = dataSet.Tables["Products"];
197 | foreach (DataRow row in dataTable.Rows)
198 | {
199 | Console.WriteLine(row["ProductName"]);
200 | }
201 | Console.WriteLine();
202 | }
203 | }
204 | ```
205 |
206 | ## Улучшенная реальная реализация на C# (GoF) ##
207 |
208 | ```csharp
209 | ///
210 | /// MainApp startup class for .NET optimized
211 | /// Template Design Pattern.
212 | ///
213 | internal class MainApp
214 | {
215 | ///
216 | /// Entry point into console application.
217 | ///
218 | private static void Main()
219 | {
220 | var daoCategories = new Categories();
221 | daoCategories.Run();
222 |
223 | var daoProducts = new Products();
224 | daoProducts.Run();
225 |
226 | // Wait for user
227 | Console.ReadKey();
228 | }
229 | }
230 |
231 | ///
232 | /// The 'AbstractClass' abstract class
233 | ///
234 | internal abstract class DataAccessObject
235 | {
236 | protected string connectionString;
237 | protected DataSet dataSet;
238 |
239 | public virtual void Connect()
240 | {
241 | // Make sure mdb is available to app
242 | connectionString =
243 | "provider=Microsoft.JET.OLEDB.4.0; " +
244 | "data source=..\\..\\..\\db1.mdb";
245 | }
246 |
247 | public abstract void Select();
248 |
249 | public abstract void Process();
250 |
251 | virtual public void Disconnect()
252 | {
253 | connectionString = "";
254 | }
255 |
256 | // The 'Template Method'
257 | public void Run()
258 | {
259 | Connect();
260 | Select();
261 | Process();
262 | Disconnect();
263 | }
264 | }
265 |
266 | ///
267 | /// A 'ConcreteClass' class
268 | ///
269 | internal class Categories : DataAccessObject
270 | {
271 | public override void Select()
272 | {
273 | string sql = "SELECT CategoryName FROM Categories";
274 | var dataAdapter = new OleDbDataAdapter(sql, connectionString);
275 |
276 | dataSet = new DataSet();
277 | dataAdapter.Fill(dataSet, "Categories");
278 | }
279 |
280 | public override void Process()
281 | {
282 | Console.WriteLine("Categories ---- ");
283 |
284 | var dataTable = dataSet.Tables["Categories"];
285 | foreach (DataRow row in dataTable.Rows)
286 | {
287 | Console.WriteLine(row["CategoryName"]);
288 | }
289 | Console.WriteLine();
290 | }
291 | }
292 |
293 | ///
294 | /// A 'ConcreteClass' class
295 | ///
296 | internal class Products : DataAccessObject
297 | {
298 | public override void Select()
299 | {
300 | string sql = "SELECT ProductName FROM Products";
301 | var dataAdapter = new OleDbDataAdapter(
302 | sql, connectionString);
303 |
304 | dataSet = new DataSet();
305 | dataAdapter.Fill(dataSet, "Products");
306 | }
307 |
308 | public override void Process()
309 | {
310 | Console.WriteLine("Products ---- ");
311 | var dataTable = dataSet.Tables["Products"];
312 | foreach (DataRow row in dataTable.Rows)
313 | {
314 | Console.WriteLine(row["ProductName"]);
315 | }
316 | Console.WriteLine();
317 | }
318 | }
319 | ```
320 |
321 | ## Реализация на C# (Head First) ##
322 |
323 | ```csharp
324 | internal class BeverageTestDrive
325 | {
326 | private static void Main(string[] args)
327 | {
328 | Console.WriteLine("\nMaking tea...");
329 | var tea = new Tea();
330 | tea.PrepareRecipe();
331 |
332 | Console.WriteLine("\nMaking coffee...");
333 | var coffee = new Coffee();
334 | coffee.PrepareRecipe();
335 |
336 | // Hooked on Template (page 292)
337 |
338 | Console.WriteLine("\nMaking tea...");
339 | var teaHook = new TeaWithHook();
340 | teaHook.PrepareRecipe();
341 |
342 | Console.WriteLine("\nMaking coffee...");
343 | var coffeeHook = new CoffeeWithHook();
344 | coffeeHook.PrepareRecipe();
345 |
346 | // Wait for user
347 | Console.ReadKey();
348 | }
349 | }
350 |
351 | #region Coffee and Tea
352 |
353 | public abstract class CaffeineBeverage
354 | {
355 | public void PrepareRecipe()
356 | {
357 | BoilWater();
358 | Brew();
359 | PourInCup();
360 | AddCondiments();
361 | }
362 |
363 | public abstract void Brew();
364 |
365 | public abstract void AddCondiments();
366 |
367 | private void BoilWater()
368 | {
369 | Console.WriteLine("Boiling water");
370 | }
371 |
372 | private void PourInCup()
373 | {
374 | Console.WriteLine("Pouring into cup");
375 | }
376 | }
377 |
378 | public class Coffee : CaffeineBeverage
379 | {
380 | public override void Brew()
381 | {
382 | Console.WriteLine("Dripping Coffee through filter");
383 | }
384 |
385 | public override void AddCondiments()
386 | {
387 | Console.WriteLine("Adding Sugar and Milk");
388 | }
389 | }
390 |
391 | public class Tea : CaffeineBeverage
392 | {
393 | public override void Brew()
394 | {
395 | Console.WriteLine("Steeping the tea");
396 | }
397 |
398 | public override void AddCondiments()
399 | {
400 | Console.WriteLine("Adding Lemon");
401 | }
402 | }
403 |
404 | #endregion Coffee and Tea
405 |
406 | #region Coffee and Tea with Hook
407 |
408 | public abstract class CaffeineBeverageWithHook
409 | {
410 | public void PrepareRecipe()
411 | {
412 | BoilWater();
413 | Brew();
414 | PourInCup();
415 | if (CustomerWantsCondiments())
416 | {
417 | AddCondiments();
418 | }
419 | }
420 |
421 | public abstract void Brew();
422 |
423 | public abstract void AddCondiments();
424 |
425 | public void BoilWater()
426 | {
427 | Console.WriteLine("Boiling water");
428 | }
429 |
430 | public void PourInCup()
431 | {
432 | Console.WriteLine("Pouring into cup");
433 | }
434 |
435 | public virtual bool CustomerWantsCondiments()
436 | {
437 | return true;
438 | }
439 | }
440 |
441 | public class CoffeeWithHook : CaffeineBeverageWithHook
442 | {
443 | public override void Brew()
444 | {
445 | Console.WriteLine("Dripping Coffee through filter");
446 | }
447 |
448 | public override void AddCondiments()
449 | {
450 | Console.WriteLine("Adding Sugar and Milk");
451 | }
452 |
453 | public override bool CustomerWantsCondiments()
454 | {
455 | string answer = GetUserInput();
456 |
457 | if (answer.ToLower().StartsWith("y"))
458 | {
459 | return true;
460 | }
461 | else
462 | {
463 | return false;
464 | }
465 | }
466 |
467 | public string GetUserInput()
468 | {
469 | string answer = null;
470 | Console.WriteLine("Would you like milk and sugar with your coffee (y/n)? ");
471 |
472 | try
473 | {
474 | answer = Console.ReadLine();
475 | }
476 | catch
477 | {
478 | Console.WriteLine("IO error trying to read your answer");
479 | }
480 |
481 | if (answer == null)
482 | {
483 | return "no";
484 | }
485 | return answer;
486 | }
487 | }
488 |
489 | public class TeaWithHook : CaffeineBeverageWithHook
490 | {
491 | public override void Brew()
492 | {
493 | Console.WriteLine("Steeping the tea");
494 | }
495 |
496 | public override void AddCondiments()
497 | {
498 | Console.WriteLine("Adding Lemon");
499 | }
500 |
501 | public override bool CustomerWantsCondiments()
502 | {
503 | string answer = GetUserInput();
504 |
505 | if (answer.ToLower().StartsWith("y"))
506 | {
507 | return true;
508 | }
509 | else
510 | {
511 | return false;
512 | }
513 | }
514 |
515 | private string GetUserInput()
516 | {
517 | // get the user's response
518 | string answer = null;
519 |
520 | Console.WriteLine("Would you like lemon with your tea (y/n)? ");
521 |
522 | try
523 | {
524 | answer = Console.ReadLine();
525 | }
526 | catch
527 | {
528 | Console.WriteLine("IO error trying to read your answer");
529 | }
530 |
531 | if (answer == null)
532 | {
533 | return "no";
534 | }
535 | return answer;
536 | }
537 | }
538 |
539 | #endregion Coffee and Tea with Hook
540 | ```
541 |
542 | ## Реализация на JAVA ##
543 |
544 | ```java
545 | TODO
546 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/template_method_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/template_method_UML.gif
--------------------------------------------------------------------------------
/design_patterns/behavioral/visitor.md:
--------------------------------------------------------------------------------
1 | # Посетитель (Visitor) #
2 |
3 | Паттерн Посетитель используется для расширения возможностей комбинации объектов в том случае, если инкапсуляция не существенна.
4 |
5 | 
6 |
7 | * Visitor - абстрактный посетитель
8 |
9 | * ConcreteVisitor - конкртеный посетитель
10 |
11 | * Element - абстрактный элемент
12 |
13 | * ConcreteElement - конкретный элемент
14 |
15 | * ObjectStructure - структура объектов
16 |
17 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Посетитель_(шаблон_проектирования))
18 |
19 | ## Абстрактная реализация на C# (GoF) ##
20 |
21 | ```csharp
22 | ///
23 | /// MainApp startup class for Structural
24 | /// Visitor Design Pattern.
25 | ///
26 | internal class MainApp
27 | {
28 | private static void Main()
29 | {
30 | // Setup structure
31 | ObjectStructure o = new ObjectStructure();
32 | o.Attach(new ConcreteElementA());
33 | o.Attach(new ConcreteElementB());
34 |
35 | // Create visitor objects
36 | ConcreteVisitor1 v1 = new ConcreteVisitor1();
37 | ConcreteVisitor2 v2 = new ConcreteVisitor2();
38 |
39 | // Structure accepting visitors
40 | o.Accept(v1);
41 | o.Accept(v2);
42 |
43 | // Wait for user
44 | Console.ReadKey();
45 | }
46 | }
47 |
48 | ///
49 | /// The 'Visitor' abstract class
50 | ///
51 | internal abstract class Visitor
52 | {
53 | public abstract void VisitConcreteElementA(
54 | ConcreteElementA concreteElementA);
55 |
56 | public abstract void VisitConcreteElementB(
57 | ConcreteElementB concreteElementB);
58 | }
59 |
60 | ///
61 | /// A 'ConcreteVisitor' class
62 | ///
63 | internal class ConcreteVisitor1 : Visitor
64 | {
65 | public override void VisitConcreteElementA(
66 | ConcreteElementA concreteElementA)
67 | {
68 | Console.WriteLine("{0} visited by {1}",
69 | concreteElementA.GetType().Name, this.GetType().Name);
70 | }
71 |
72 | public override void VisitConcreteElementB(
73 | ConcreteElementB concreteElementB)
74 | {
75 | Console.WriteLine("{0} visited by {1}",
76 | concreteElementB.GetType().Name, this.GetType().Name);
77 | }
78 | }
79 |
80 | ///
81 | /// A 'ConcreteVisitor' class
82 | ///
83 | internal class ConcreteVisitor2 : Visitor
84 | {
85 | public override void VisitConcreteElementA(
86 | ConcreteElementA concreteElementA)
87 | {
88 | Console.WriteLine("{0} visited by {1}",
89 | concreteElementA.GetType().Name, this.GetType().Name);
90 | }
91 |
92 | public override void VisitConcreteElementB(
93 | ConcreteElementB concreteElementB)
94 | {
95 | Console.WriteLine("{0} visited by {1}",
96 | concreteElementB.GetType().Name, this.GetType().Name);
97 | }
98 | }
99 |
100 | ///
101 | /// The 'Element' abstract class
102 | ///
103 | internal abstract class Element
104 | {
105 | public abstract void Accept(Visitor visitor);
106 | }
107 |
108 | ///
109 | /// A 'ConcreteElement' class
110 | ///
111 | internal class ConcreteElementA : Element
112 | {
113 | public override void Accept(Visitor visitor)
114 | {
115 | visitor.VisitConcreteElementA(this);
116 | }
117 |
118 | public void OperationA()
119 | {
120 | }
121 | }
122 |
123 | ///
124 | /// A 'ConcreteElement' class
125 | ///
126 | internal class ConcreteElementB : Element
127 | {
128 | public override void Accept(Visitor visitor)
129 | {
130 | visitor.VisitConcreteElementB(this);
131 | }
132 |
133 | public void OperationB()
134 | {
135 | }
136 | }
137 |
138 | ///
139 | /// The 'ObjectStructure' class
140 | ///
141 | internal class ObjectStructure
142 | {
143 | private List elements = new List();
144 |
145 | public void Attach(Element element)
146 | {
147 | elements.Add(element);
148 | }
149 |
150 | public void Detach(Element element)
151 | {
152 | elements.Remove(element);
153 | }
154 |
155 | public void Accept(Visitor visitor)
156 | {
157 | foreach (Element element in elements)
158 | {
159 | element.Accept(visitor);
160 | }
161 | }
162 | }
163 | ```
164 |
165 | ## Реальная реализация на C# (GoF) ##
166 |
167 | ```charp
168 | ///
169 | /// MainApp startup class for Real-World
170 | /// Visitor Design Pattern.
171 | ///
172 | internal class MainApp
173 | {
174 | ///
175 | /// Entry point into console application.
176 | ///
177 | private static void Main()
178 | {
179 | // Setup employee collection
180 | Employees employee = new Employees();
181 | employee.Attach(new Clerk());
182 | employee.Attach(new Director());
183 | employee.Attach(new President());
184 |
185 | // Employees are 'visited'
186 | employee.Accept(new IncomeVisitor());
187 | employee.Accept(new VacationVisitor());
188 |
189 | // Wait for user
190 | Console.ReadKey();
191 | }
192 | }
193 |
194 | ///
195 | /// The 'Visitor' interface
196 | ///
197 | internal interface IVisitor
198 | {
199 | void Visit(Element element);
200 | }
201 |
202 | ///
203 | /// A 'ConcreteVisitor' class
204 | ///
205 | internal class IncomeVisitor : IVisitor
206 | {
207 | public void Visit(Element element)
208 | {
209 | Employee employee = element as Employee;
210 |
211 | // Provide 10% pay raise
212 | employee.Income *= 1.10;
213 | Console.WriteLine("{0} {1}'s new income: {2:C}",
214 | employee.GetType().Name, employee.Name,
215 | employee.Income);
216 | }
217 | }
218 |
219 | ///
220 | /// A 'ConcreteVisitor' class
221 | ///
222 | internal class VacationVisitor : IVisitor
223 | {
224 | public void Visit(Element element)
225 | {
226 | Employee employee = element as Employee;
227 |
228 | // Provide 3 extra vacation days
229 | Console.WriteLine("{0} {1}'s new vacation days: {2}",
230 | employee.GetType().Name, employee.Name,
231 | employee.VacationDays);
232 | }
233 | }
234 |
235 | ///
236 | /// The 'Element' abstract class
237 | ///
238 | internal abstract class Element
239 | {
240 | public abstract void Accept(IVisitor visitor);
241 | }
242 |
243 | ///
244 | /// The 'ConcreteElement' class
245 | ///
246 | internal class Employee : Element
247 | {
248 | private string name;
249 | private double income;
250 | private int vacationDays;
251 |
252 | // Constructor
253 | public Employee(string name, double income,
254 | int vacationDays)
255 | {
256 | this.name = name;
257 | this.income = income;
258 | this.vacationDays = vacationDays;
259 | }
260 |
261 | // Gets or sets the name
262 | public string Name
263 | {
264 | get { return name; }
265 | set { name = value; }
266 | }
267 |
268 | // Gets or sets income
269 | public double Income
270 | {
271 | get { return income; }
272 | set { income = value; }
273 | }
274 |
275 | // Gets or sets number of vacation days
276 | public int VacationDays
277 | {
278 | get { return vacationDays; }
279 | set { vacationDays = value; }
280 | }
281 |
282 | public override void Accept(IVisitor visitor)
283 | {
284 | visitor.Visit(this);
285 | }
286 | }
287 |
288 | ///
289 | /// The 'ObjectStructure' class
290 | ///
291 | internal class Employees
292 | {
293 | private List employees = new List();
294 |
295 | public void Attach(Employee employee)
296 | {
297 | employees.Add(employee);
298 | }
299 |
300 | public void Detach(Employee employee)
301 | {
302 | employees.Remove(employee);
303 | }
304 |
305 | public void Accept(IVisitor visitor)
306 | {
307 | foreach (Employee employee in employees)
308 | {
309 | employee.Accept(visitor);
310 | }
311 | Console.WriteLine();
312 | }
313 | }
314 |
315 | // Three employee types
316 |
317 | internal class Clerk : Employee
318 | {
319 | // Constructor
320 | public Clerk()
321 | : base("Hank", 25000.0, 14)
322 | {
323 | }
324 | }
325 |
326 | internal class Director : Employee
327 | {
328 | // Constructor
329 | public Director()
330 | : base("Elly", 35000.0, 16)
331 | {
332 | }
333 | }
334 |
335 | internal class President : Employee
336 | {
337 | // Constructor
338 | public President()
339 | : base("Dick", 45000.0, 21)
340 | {
341 | }
342 | }
343 | ```
344 |
345 | ## Улучшенная реальная реализация на C# (GoF) ##
346 |
347 | ```csharp
348 | ///
349 | /// MainApp startup class for .NET optimized
350 | /// Visitor Design Pattern.
351 | ///
352 | internal class MainApp
353 | {
354 | ///
355 | /// Entry point into console application.
356 | ///
357 | private static void Main()
358 | {
359 | // Setup employee collection
360 | var employee = new Employees();
361 | employee.Attach(new Clerk());
362 | employee.Attach(new Director());
363 | employee.Attach(new President());
364 |
365 | // Employees are 'visited'
366 | employee.Accept(new IncomeVisitor());
367 | employee.Accept(new VacationVisitor());
368 |
369 | // Wait for user
370 | Console.ReadKey();
371 | }
372 | }
373 |
374 | ///
375 | /// The 'Visitor' abstract class
376 | ///
377 | public abstract class Visitor
378 | {
379 | // Use reflection to see if the Visitor has a method
380 | // named Visit with the appropriate parameter type
381 | // (i.e. a specific Employee). If so, invoke it.
382 | public void ReflectiveVisit(IElement element)
383 | {
384 | var types = new Type[] { element.GetType() };
385 | var mi = this.GetType().GetMethod("Visit", types);
386 |
387 | if (mi != null)
388 | {
389 | mi.Invoke(this, new object[] { element });
390 | }
391 | }
392 | }
393 |
394 | ///
395 | /// A 'ConcreteVisitor' class
396 | ///
397 | internal class IncomeVisitor : Visitor
398 | {
399 | // Visit clerk
400 | public void Visit(Clerk clerk)
401 | {
402 | DoVisit(clerk);
403 | }
404 |
405 | // Visit director
406 | public void Visit(Director director)
407 | {
408 | DoVisit(director);
409 | }
410 |
411 | private void DoVisit(IElement element)
412 | {
413 | var employee = element as Employee;
414 |
415 | // Provide 10% pay raise
416 | employee.Income *= 1.10;
417 | Console.WriteLine("{0} {1}'s new income: {2:C}",
418 | employee.GetType().Name, employee.Name,
419 | employee.Income);
420 | }
421 | }
422 |
423 | ///
424 | /// A 'ConcreteVisitor' class
425 | ///
426 | internal class VacationVisitor : Visitor
427 | {
428 | // Visit director
429 | public void Visit(Director director)
430 | {
431 | DoVisit(director);
432 | }
433 |
434 | private void DoVisit(IElement element)
435 | {
436 | var employee = element as Employee;
437 |
438 | // Provide 3 extra vacation days
439 | employee.VacationDays += 3;
440 | Console.WriteLine("{0} {1}'s new vacation days: {2}",
441 | employee.GetType().Name, employee.Name,
442 | employee.VacationDays);
443 | }
444 | }
445 |
446 | ///
447 | /// The 'Element' interface
448 | ///
449 | public interface IElement
450 | {
451 | void Accept(Visitor visitor);
452 | }
453 |
454 | ///
455 | /// The 'ConcreteElement' class
456 | ///
457 | internal class Employee : IElement
458 | {
459 | // Constructor
460 | public Employee(string name, double income,
461 | int vacationDays)
462 | {
463 | this.Name = name;
464 | this.Income = income;
465 | this.VacationDays = vacationDays;
466 | }
467 |
468 | // Gets or sets name
469 | public string Name { get; set; }
470 |
471 | // Gets or set income
472 | public double Income { get; set; }
473 |
474 | // Gets or sets vacation days
475 | public int VacationDays { get; set; }
476 |
477 | public virtual void Accept(Visitor visitor)
478 | {
479 | visitor.ReflectiveVisit(this);
480 | }
481 | }
482 |
483 | ///
484 | /// The 'ObjectStructure' class
485 | ///
486 | internal class Employees : List
487 | {
488 | public void Attach(Employee employee)
489 | {
490 | Add(employee);
491 | }
492 |
493 | public void Detach(Employee employee)
494 | {
495 | Remove(employee);
496 | }
497 |
498 | public void Accept(Visitor visitor)
499 | {
500 | // Iterate over all employees and accept visitor
501 | this.ForEach(employee => employee.Accept(visitor));
502 |
503 | Console.WriteLine();
504 | }
505 | }
506 |
507 | // Three employee types
508 |
509 | internal class Clerk : Employee
510 | {
511 | // Constructor
512 | public Clerk()
513 | : base("Hank", 25000.0, 14)
514 | {
515 | }
516 | }
517 |
518 | internal class Director : Employee
519 | {
520 | // Constructor
521 | public Director()
522 | : base("Elly", 35000.0, 16)
523 | {
524 | }
525 | }
526 |
527 | internal class President : Employee
528 | {
529 | // Constructor
530 | public President()
531 | : base("Dick", 45000.0, 21)
532 | {
533 | }
534 | }
535 | ```
536 |
537 | ## Реализация на JAVA ##
538 |
539 | ```java
540 | TODO
541 | ```
--------------------------------------------------------------------------------
/design_patterns/behavioral/visitor_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/behavioral/visitor_UML.gif
--------------------------------------------------------------------------------
/design_patterns/creational/abstract_factory_UML.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/creational/abstract_factory_UML.jpeg
--------------------------------------------------------------------------------
/design_patterns/creational/builder.md:
--------------------------------------------------------------------------------
1 | # Строитель (Builder) #
2 |
3 | Паттерн Строитель инкапсулирует конструирование продукта и позволяет разделить его на этапы.
4 |
5 | 
6 |
7 | * Builder - абстрактный строитель
8 |
9 | * ConcreteBuilder - конкретный строитель
10 |
11 | * Director - распорядитель
12 |
13 | * Product - продукт
14 |
15 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Строитель_(шаблон_проектирования))
16 |
17 | ## Абстрактная реализация на C# (GoF) ##
18 |
19 | ```csharp
20 | ///
21 | /// MainApp startup class for Structural
22 | /// Builder Design Pattern.
23 | ///
24 | public class MainApp
25 | {
26 | ///
27 | /// Entry point into console application.
28 | ///
29 | public static void Main()
30 | {
31 | // Create director and builders
32 | Director director = new Director();
33 |
34 | Builder b1 = new ConcreteBuilder1();
35 | Builder b2 = new ConcreteBuilder2();
36 |
37 | // Construct two products
38 | director.Construct(b1);
39 | Product p1 = b1.GetResult();
40 | p1.Show();
41 |
42 | director.Construct(b2);
43 | Product p2 = b2.GetResult();
44 | p2.Show();
45 |
46 | // Wait for user
47 | Console.ReadKey();
48 | }
49 | }
50 |
51 | ///
52 | /// The 'Director' class
53 | ///
54 | internal class Director
55 | {
56 | // Builder uses a complex series of steps
57 | public void Construct(Builder builder)
58 | {
59 | builder.BuildPartA();
60 | builder.BuildPartB();
61 | }
62 | }
63 |
64 | ///
65 | /// The 'Builder' abstract class
66 | ///
67 | internal abstract class Builder
68 | {
69 | public abstract void BuildPartA();
70 |
71 | public abstract void BuildPartB();
72 |
73 | public abstract Product GetResult();
74 | }
75 |
76 | ///
77 | /// The 'ConcreteBuilder1' class
78 | ///
79 | internal class ConcreteBuilder1 : Builder
80 | {
81 | private Product product = new Product();
82 |
83 | public override void BuildPartA()
84 | {
85 | product.Add("PartA");
86 | }
87 |
88 | public override void BuildPartB()
89 | {
90 | product.Add("PartB");
91 | }
92 |
93 | public override Product GetResult()
94 | {
95 | return product;
96 | }
97 | }
98 |
99 | ///
100 | /// The 'ConcreteBuilder2' class
101 | ///
102 | internal class ConcreteBuilder2 : Builder
103 | {
104 | private Product product = new Product();
105 |
106 | public override void BuildPartA()
107 | {
108 | product.Add("PartX");
109 | }
110 |
111 | public override void BuildPartB()
112 | {
113 | product.Add("PartY");
114 | }
115 |
116 | public override Product GetResult()
117 | {
118 | return product;
119 | }
120 | }
121 |
122 | ///
123 | /// The 'Product' class
124 | ///
125 | internal class Product
126 | {
127 | private List parts = new List();
128 |
129 | public void Add(string part)
130 | {
131 | parts.Add(part);
132 | }
133 |
134 | public void Show()
135 | {
136 | Console.WriteLine("\nProduct Parts -------");
137 | foreach (string part in parts)
138 | Console.WriteLine(part);
139 | }
140 | }
141 | ```
142 |
143 | ## Реальная реализация на C# (GoF) ##
144 |
145 | ```charp
146 | ///
147 | /// MainApp startup class for Real-World
148 | /// Builder Design Pattern.
149 | ///
150 | public class MainApp
151 | {
152 | ///
153 | /// Entry point into console application.
154 | ///
155 | public static void Main()
156 | {
157 | VehicleBuilder builder;
158 |
159 | // Create shop with vehicle builders
160 | Shop shop = new Shop();
161 |
162 | // Construct and display vehicles
163 | builder = new ScooterBuilder();
164 | shop.Construct(builder);
165 | builder.Vehicle.Show();
166 |
167 | builder = new CarBuilder();
168 | shop.Construct(builder);
169 | builder.Vehicle.Show();
170 |
171 | builder = new MotorCycleBuilder();
172 | shop.Construct(builder);
173 | builder.Vehicle.Show();
174 |
175 | // Wait for user
176 | Console.ReadKey();
177 | }
178 | }
179 |
180 | ///
181 | /// The 'Director' class
182 | ///
183 | internal class Shop
184 | {
185 | // Builder uses a complex series of steps
186 | public void Construct(VehicleBuilder vehicleBuilder)
187 | {
188 | vehicleBuilder.BuildFrame();
189 | vehicleBuilder.BuildEngine();
190 | vehicleBuilder.BuildWheels();
191 | vehicleBuilder.BuildDoors();
192 | }
193 | }
194 |
195 | ///
196 | /// The 'Builder' abstract class
197 | ///
198 | internal abstract class VehicleBuilder
199 | {
200 | protected Vehicle vehicle;
201 |
202 | // Gets vehicle instance
203 | public Vehicle Vehicle
204 | {
205 | get { return vehicle; }
206 | }
207 |
208 | // Abstract build methods
209 | public abstract void BuildFrame();
210 |
211 | public abstract void BuildEngine();
212 |
213 | public abstract void BuildWheels();
214 |
215 | public abstract void BuildDoors();
216 | }
217 |
218 | ///
219 | /// The 'ConcreteBuilder1' class
220 | ///
221 | internal class MotorCycleBuilder : VehicleBuilder
222 | {
223 | public MotorCycleBuilder()
224 | {
225 | vehicle = new Vehicle("MotorCycle");
226 | }
227 |
228 | public override void BuildFrame()
229 | {
230 | vehicle["frame"] = "MotorCycle Frame";
231 | }
232 |
233 | public override void BuildEngine()
234 | {
235 | vehicle["engine"] = "500 cc";
236 | }
237 |
238 | public override void BuildWheels()
239 | {
240 | vehicle["wheels"] = "2";
241 | }
242 |
243 | public override void BuildDoors()
244 | {
245 | vehicle["doors"] = "0";
246 | }
247 | }
248 |
249 | ///
250 | /// The 'ConcreteBuilder2' class
251 | ///
252 | internal class CarBuilder : VehicleBuilder
253 | {
254 | public CarBuilder()
255 | {
256 | vehicle = new Vehicle("Car");
257 | }
258 |
259 | public override void BuildFrame()
260 | {
261 | vehicle["frame"] = "Car Frame";
262 | }
263 |
264 | public override void BuildEngine()
265 | {
266 | vehicle["engine"] = "2500 cc";
267 | }
268 |
269 | public override void BuildWheels()
270 | {
271 | vehicle["wheels"] = "4";
272 | }
273 |
274 | public override void BuildDoors()
275 | {
276 | vehicle["doors"] = "4";
277 | }
278 | }
279 |
280 | ///
281 | /// The 'ConcreteBuilder3' class
282 | ///
283 | internal class ScooterBuilder : VehicleBuilder
284 | {
285 | public ScooterBuilder()
286 | {
287 | vehicle = new Vehicle("Scooter");
288 | }
289 |
290 | public override void BuildFrame()
291 | {
292 | vehicle["frame"] = "Scooter Frame";
293 | }
294 |
295 | public override void BuildEngine()
296 | {
297 | vehicle["engine"] = "50 cc";
298 | }
299 |
300 | public override void BuildWheels()
301 | {
302 | vehicle["wheels"] = "2";
303 | }
304 |
305 | public override void BuildDoors()
306 | {
307 | vehicle["doors"] = "0";
308 | }
309 | }
310 |
311 | ///
312 | /// The 'Product' class
313 | ///
314 | internal class Vehicle
315 | {
316 | private string vehicleType;
317 | private Dictionary parts = new Dictionary();
318 |
319 | // Constructor
320 | public Vehicle(string vehicleType)
321 | {
322 | this.vehicleType = vehicleType;
323 | }
324 |
325 | // Indexer
326 | public string this[string key]
327 | {
328 | get { return parts[key]; }
329 | set { parts[key] = value; }
330 | }
331 |
332 | public void Show()
333 | {
334 | Console.WriteLine("\n---------------------------");
335 | Console.WriteLine("Vehicle Type: {0}", vehicleType);
336 | Console.WriteLine(" Frame : {0}", parts["frame"]);
337 | Console.WriteLine(" Engine : {0}", parts["engine"]);
338 | Console.WriteLine(" #Wheels: {0}", parts["wheels"]);
339 | Console.WriteLine(" #Doors : {0}", parts["doors"]);
340 | }
341 | }
342 | ```
343 |
344 | ## Улучшенная реальная реализация на C# (GoF) ##
345 |
346 | ```csharp
347 | ///
348 | /// MainApp startup class for .NET optimized
349 | /// Builder Design Pattern.
350 | ///
351 | public class MainApp
352 | {
353 | ///
354 | /// Entry point into console application.
355 | ///
356 | public static void Main()
357 | {
358 | // Create shop
359 | var shop = new Shop();
360 |
361 | // Construct and display vehicles
362 | shop.Construct(new ScooterBuilder());
363 | shop.ShowVehicle();
364 |
365 | shop.Construct(new CarBuilder());
366 | shop.ShowVehicle();
367 |
368 | shop.Construct(new MotorCycleBuilder());
369 | shop.ShowVehicle();
370 |
371 | // Wait for user
372 | Console.ReadKey();
373 | }
374 | }
375 |
376 | ///
377 | /// The 'Director' class
378 | ///
379 | internal class Shop
380 | {
381 | private VehicleBuilder vehicleBuilder;
382 |
383 | // Builder uses a complex series of steps
384 | public void Construct(VehicleBuilder vehicleBuilder)
385 | {
386 | this.vehicleBuilder = vehicleBuilder;
387 |
388 | this.vehicleBuilder.BuildFrame();
389 | this.vehicleBuilder.BuildEngine();
390 | this.vehicleBuilder.BuildWheels();
391 | this.vehicleBuilder.BuildDoors();
392 | }
393 |
394 | public void ShowVehicle()
395 | {
396 | vehicleBuilder.Vehicle.Show();
397 | }
398 | }
399 |
400 | ///
401 | /// The 'Builder' abstract class
402 | ///
403 | internal abstract class VehicleBuilder
404 | {
405 | public Vehicle Vehicle { get; private set; }
406 |
407 | // Constructor
408 | public VehicleBuilder(VehicleType vehicleType)
409 | {
410 | Vehicle = new Vehicle(vehicleType);
411 | }
412 |
413 | public abstract void BuildFrame();
414 |
415 | public abstract void BuildEngine();
416 |
417 | public abstract void BuildWheels();
418 |
419 | public abstract void BuildDoors();
420 | }
421 |
422 | ///
423 | /// The 'ConcreteBuilder1' class
424 | ///
425 | internal class MotorCycleBuilder : VehicleBuilder
426 | {
427 | // Invoke base class constructor
428 | public MotorCycleBuilder()
429 | : base(VehicleType.MotorCycle)
430 | {
431 | }
432 |
433 | public override void BuildFrame()
434 | {
435 | Vehicle[PartType.Frame] = "MotorCycle Frame";
436 | }
437 |
438 | public override void BuildEngine()
439 | {
440 | Vehicle[PartType.Engine] = "500 cc";
441 | }
442 |
443 | public override void BuildWheels()
444 | {
445 | Vehicle[PartType.Wheel] = "2";
446 | }
447 |
448 | public override void BuildDoors()
449 | {
450 | Vehicle[PartType.Door] = "0";
451 | }
452 | }
453 |
454 | ///
455 | /// The 'ConcreteBuilder2' class
456 | ///
457 | internal class CarBuilder : VehicleBuilder
458 | {
459 | // Invoke base class constructor
460 | public CarBuilder()
461 | : base(VehicleType.Car)
462 | {
463 | }
464 |
465 | public override void BuildFrame()
466 | {
467 | Vehicle[PartType.Frame] = "Car Frame";
468 | }
469 |
470 | public override void BuildEngine()
471 | {
472 | Vehicle[PartType.Engine] = "2500 cc";
473 | }
474 |
475 | public override void BuildWheels()
476 | {
477 | Vehicle[PartType.Wheel] = "4";
478 | }
479 |
480 | public override void BuildDoors()
481 | {
482 | Vehicle[PartType.Door] = "4";
483 | }
484 | }
485 |
486 | ///
487 | /// The 'ConcreteBuilder3' class
488 | ///
489 | internal class ScooterBuilder : VehicleBuilder
490 | {
491 | // Invoke base class constructor
492 | public ScooterBuilder() : base(VehicleType.Scooter)
493 | {
494 | }
495 |
496 | public override void BuildFrame()
497 | {
498 | Vehicle[PartType.Frame] = "Scooter Frame";
499 | }
500 |
501 | public override void BuildEngine()
502 | {
503 | Vehicle[PartType.Engine] = "50 cc";
504 | }
505 |
506 | public override void BuildWheels()
507 | {
508 | Vehicle[PartType.Wheel] = "2";
509 | }
510 |
511 | public override void BuildDoors()
512 | {
513 | Vehicle[PartType.Door] = "0";
514 | }
515 | }
516 |
517 | ///
518 | /// The 'Product' class
519 | ///
520 | internal class Vehicle
521 | {
522 | private VehicleType vehicleType;
523 | private Dictionary parts = new Dictionary();
524 |
525 | // Constructor
526 | public Vehicle(VehicleType vehicleType)
527 | {
528 | this.vehicleType = vehicleType;
529 | }
530 |
531 | public string this[PartType key]
532 | {
533 | get { return parts[key]; }
534 | set { parts[key] = value; }
535 | }
536 |
537 | public void Show()
538 | {
539 | Console.WriteLine("\n---------------------------");
540 | Console.WriteLine("Vehicle Type: {0}", vehicleType);
541 | Console.WriteLine(" Frame : {0}",
542 | this[PartType.Frame]);
543 | Console.WriteLine(" Engine : {0}",
544 | this[PartType.Engine]);
545 | Console.WriteLine(" #Wheels: {0}",
546 | this[PartType.Wheel]);
547 | Console.WriteLine(" #Doors : {0}",
548 | this[PartType.Door]);
549 | }
550 | }
551 |
552 | ///
553 | /// Part type enumeration
554 | ///
555 | public enum PartType
556 | {
557 | Frame,
558 | Engine,
559 | Wheel,
560 | Door
561 | }
562 |
563 | ///
564 | /// Vehicle type enumeration
565 | ///
566 | public enum VehicleType
567 | {
568 | Car,
569 | Scooter,
570 | MotorCycle
571 | }
572 | ```
573 |
574 | ## Реализация на JAVA ##
575 |
576 | ```java
577 | TODO
578 | ```
--------------------------------------------------------------------------------
/design_patterns/creational/builder_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/creational/builder_UML.gif
--------------------------------------------------------------------------------
/design_patterns/creational/factory_method_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/creational/factory_method_UML.gif
--------------------------------------------------------------------------------
/design_patterns/creational/prototype.md:
--------------------------------------------------------------------------------
1 | # Прототип (Prototype) #
2 |
3 | Паттерн Прототип используется в тех случаях, когда создание экземпляра класса требует больших затрат ресурсов или занимает много времени.
4 |
5 | 
6 |
7 | * Prototype - абстрактный прототип
8 |
9 | * ConcretePrototype - конкретный прототип
10 |
11 | * Client - клиент
12 |
13 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Прототип_(шаблон_проектирования))
14 |
15 | ## Абстрактная реализация на C# (GoF) ##
16 |
17 | ```csharp
18 | ///
19 | /// MainApp startup class for Structural
20 | /// Prototype Design Pattern.
21 | ///
22 | internal class MainApp
23 | {
24 | ///
25 | /// Entry point into console application.
26 | ///
27 | private static void Main()
28 | {
29 | // Create two instances and clone each
30 |
31 | ConcretePrototype1 p1 = new ConcretePrototype1("I");
32 | ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
33 | Console.WriteLine("Cloned: {0}", c1.Id);
34 |
35 | ConcretePrototype2 p2 = new ConcretePrototype2("II");
36 | ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
37 | Console.WriteLine("Cloned: {0}", c2.Id);
38 |
39 | // Wait for user
40 | Console.ReadKey();
41 | }
42 | }
43 |
44 | ///
45 | /// The 'Prototype' abstract class
46 | ///
47 | internal abstract class Prototype
48 | {
49 | private string id;
50 |
51 | // Constructor
52 | public Prototype(string id)
53 | {
54 | this.id = id;
55 | }
56 |
57 | // Gets id
58 | public string Id
59 | {
60 | get { return id; }
61 | }
62 |
63 | public abstract Prototype Clone();
64 | }
65 |
66 | ///
67 | /// A 'ConcretePrototype' class
68 | ///
69 | internal class ConcretePrototype1 : Prototype
70 | {
71 | // Constructor
72 | public ConcretePrototype1(string id)
73 | : base(id)
74 | {
75 | }
76 |
77 | // Returns a shallow copy
78 | public override Prototype Clone()
79 | {
80 | return (Prototype)this.MemberwiseClone();
81 | }
82 | }
83 |
84 | ///
85 | /// A 'ConcretePrototype' class
86 | ///
87 | internal class ConcretePrototype2 : Prototype
88 | {
89 | // Constructor
90 | public ConcretePrototype2(string id)
91 | : base(id)
92 | {
93 | }
94 |
95 | // Returns a shallow copy
96 | public override Prototype Clone()
97 | {
98 | return (Prototype)this.MemberwiseClone();
99 | }
100 | }
101 | ```
102 |
103 | ## Реальная реализация на C# (GoF) ##
104 |
105 | ```charp
106 | ///
107 | /// MainApp startup class for Real-World
108 | /// Prototype Design Pattern.
109 | ///
110 | internal class MainApp
111 | {
112 | ///
113 | /// Entry point into console application.
114 | ///
115 | private static void Main()
116 | {
117 | ColorManager colormanager = new ColorManager();
118 |
119 | // Initialize with standard colors
120 | colormanager["red"] = new Color(255, 0, 0);
121 | colormanager["green"] = new Color(0, 255, 0);
122 | colormanager["blue"] = new Color(0, 0, 255);
123 |
124 | // User adds personalized colors
125 | colormanager["angry"] = new Color(255, 54, 0);
126 | colormanager["peace"] = new Color(128, 211, 128);
127 | colormanager["flame"] = new Color(211, 34, 20);
128 |
129 | // User clones selected colors
130 | Color color1 = colormanager["red"].Clone() as Color;
131 | Color color2 = colormanager["peace"].Clone() as Color;
132 | Color color3 = colormanager["flame"].Clone() as Color;
133 |
134 | // Wait for user
135 | Console.ReadKey();
136 | }
137 | }
138 |
139 | ///
140 | /// The 'Prototype' abstract class
141 | ///
142 | internal abstract class ColorPrototype
143 | {
144 | public abstract ColorPrototype Clone();
145 | }
146 |
147 | ///
148 | /// The 'ConcretePrototype' class
149 | ///
150 | internal class Color : ColorPrototype
151 | {
152 | private int red;
153 | private int green;
154 | private int blue;
155 |
156 | // Constructor
157 | public Color(int red, int green, int blue)
158 | {
159 | this.red = red;
160 | this.green = green;
161 | this.blue = blue;
162 | }
163 |
164 | // Create a shallow copy
165 | public override ColorPrototype Clone()
166 | {
167 | Console.WriteLine(
168 | "Cloning color RGB: {0,3},{1,3},{2,3}",
169 | red, green, blue);
170 |
171 | return this.MemberwiseClone() as ColorPrototype;
172 | }
173 | }
174 |
175 | ///
176 | /// Prototype manager
177 | ///
178 | internal class ColorManager
179 | {
180 | private Dictionary colors =
181 | new Dictionary();
182 |
183 | // Indexer
184 | public ColorPrototype this[string key]
185 | {
186 | get { return colors[key]; }
187 | set { colors.Add(key, value); }
188 | }
189 | }
190 | ```
191 |
192 | ## Улучшенная реальная реализация на C# (GoF) ##
193 |
194 | ```csharp
195 | ///
196 | /// MainApp startup class for .NET optimized
197 | /// Prototype Design Pattern.
198 | ///
199 | internal class MainApp
200 | {
201 | ///
202 | /// Entry point into console application.
203 | ///
204 | private static void Main()
205 | {
206 | var colormanager = new ColorManager();
207 |
208 | // Initialize with standard colors
209 | colormanager[ColorType.Red] = new Color { Red = 255, Blue = 0, Green = 0 };
210 | colormanager[ColorType.Green] = new Color { Red = 0, Blue = 255, Green = 0 };
211 | colormanager[ColorType.Blue] = new Color { Red = 0, Blue = 0, Green = 255 };
212 |
213 | // User adds personalized colors
214 | colormanager[ColorType.Angry] = new Color { Red = 255, Blue = 54, Green = 0 };
215 | colormanager[ColorType.Peace] = new Color { Red = 128, Blue = 211, Green = 128 };
216 | colormanager[ColorType.Flame] = new Color { Red = 211, Blue = 34, Green = 20 };
217 |
218 | // User uses selected colors
219 | var color1 = colormanager[ColorType.Red].Clone() as Color;
220 | var color2 = colormanager[ColorType.Peace].Clone() as Color;
221 |
222 | // Creates a "deep copy"
223 | var color3 = colormanager[ColorType.Flame].Clone(false) as Color;
224 |
225 | // Wait for user
226 | Console.ReadKey();
227 | }
228 | }
229 |
230 | ///
231 | /// The 'ConcretePrototype' class
232 | ///
233 | [Serializable]
234 | internal class Color : ICloneable
235 | {
236 | // Gets or sets red value
237 | public byte Red { get; set; }
238 |
239 | // Gets or sets green value
240 | public byte Green { get; set; }
241 |
242 | // Gets or sets blue channel
243 | public byte Blue { get; set; }
244 |
245 | // Returns shallow or deep copy
246 | public object Clone(bool shallow)
247 | {
248 | return shallow ? Clone() : DeepCopy();
249 | }
250 |
251 | // Creates a shallow copy
252 | public object Clone()
253 | {
254 | Console.WriteLine(
255 | "Shallow copy of color RGB: {0,3},{1,3},{2,3}",
256 | Red, Green, Blue);
257 |
258 | return this.MemberwiseClone();
259 | }
260 |
261 | // Creates a deep copy
262 | public object DeepCopy()
263 | {
264 | var stream = new MemoryStream();
265 | var formatter = new BinaryFormatter();
266 |
267 | formatter.Serialize(stream, this);
268 | stream.Seek(0, SeekOrigin.Begin);
269 |
270 | object copy = formatter.Deserialize(stream);
271 | stream.Close();
272 |
273 | Console.WriteLine(
274 | "*Deep* copy of color RGB: {0,3},{1,3},{2,3}",
275 | (copy as Color).Red,
276 | (copy as Color).Green,
277 | (copy as Color).Blue);
278 |
279 | return copy;
280 | }
281 | }
282 |
283 | ///
284 | /// Type-safe prototype manager
285 | ///
286 | internal class ColorManager
287 | {
288 | private Dictionary colors = new Dictionary();
289 |
290 | // Gets or sets color
291 | public Color this[ColorType type]
292 | {
293 | get { return colors[type]; }
294 | set { colors.Add(type, value); }
295 | }
296 | }
297 |
298 | ///
299 | /// Color type enumerations
300 | ///
301 | internal enum ColorType
302 | {
303 | Red,
304 | Green,
305 | Blue,
306 |
307 | Angry,
308 | Peace,
309 | Flame
310 | }
311 | ```
312 |
313 | ## Реализация на JAVA ##
314 |
315 | ```java
316 | TODO
317 | ```
--------------------------------------------------------------------------------
/design_patterns/creational/prototype_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/creational/prototype_UML.gif
--------------------------------------------------------------------------------
/design_patterns/creational/singleton.md:
--------------------------------------------------------------------------------
1 | # Одиночка (Singleton) #
2 |
3 | Паттерн Одиночка гарантирует, что класс имеет только один экземпляр,
4 | и предоставляет глобальную точку доступа к этому экзепляру.
5 |
6 | 
7 |
8 | * Singleton - одиночка
9 |
10 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Одиночка_(шаблон_проектирования))
11 |
12 | ## Абстрактная реализация на C# (GoF) ##
13 |
14 | ```csharp
15 | ///
16 | /// MainApp startup class for Structural
17 | /// Singleton Design Pattern.
18 | ///
19 | internal class MainApp
20 | {
21 | ///
22 | /// Entry point into console application.
23 | ///
24 | private static void Main()
25 | {
26 | // Constructor is protected -- cannot use new
27 | Singleton s1 = Singleton.Instance();
28 | Singleton s2 = Singleton.Instance();
29 |
30 | // Test for same instance
31 | if (s1 == s2)
32 | {
33 | Console.WriteLine("Objects are the same instance");
34 | }
35 |
36 | // Wait for user
37 | Console.ReadKey();
38 | }
39 | }
40 |
41 | ///
42 | /// The 'Singleton' class
43 | ///
44 | internal class Singleton
45 | {
46 | private static Singleton instance;
47 |
48 | // Constructor is 'protected'
49 | protected Singleton()
50 | {
51 | }
52 |
53 | public static Singleton Instance()
54 | {
55 | // Uses lazy initialization.
56 | // Note: this is not thread safe.
57 | if (instance == null)
58 | {
59 | instance = new Singleton();
60 | }
61 |
62 | return instance;
63 | }
64 | }
65 | ```
66 |
67 | ## Реальная реализация на C# (GoF) ##
68 |
69 | ```charp
70 | ///
71 | /// MainApp startup class for Real-World
72 | /// Singleton Design Pattern.
73 | ///
74 | internal class MainApp
75 | {
76 | ///
77 | /// Entry point into console application.
78 | ///
79 | private static void Main()
80 | {
81 | LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
82 | LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
83 | LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
84 | LoadBalancer b4 = LoadBalancer.GetLoadBalancer();
85 |
86 | // Same instance?
87 | if (b1 == b2 && b2 == b3 && b3 == b4)
88 | {
89 | Console.WriteLine("Same instance\n");
90 | }
91 |
92 | // Load balance 15 server requests
93 | LoadBalancer balancer = LoadBalancer.GetLoadBalancer();
94 | for (int i = 0; i < 15; i++)
95 | {
96 | string server = balancer.Server;
97 | Console.WriteLine("Dispatch Request to: " + server);
98 | }
99 |
100 | // Wait for user
101 | Console.ReadKey();
102 | }
103 | }
104 |
105 | ///
106 | /// The 'Singleton' class
107 | ///
108 | internal class LoadBalancer
109 | {
110 | private static LoadBalancer instance;
111 | private List servers = new List();
112 | private Random random = new Random();
113 |
114 | // Lock synchronization object
115 | private static object locker = new object();
116 |
117 | // Constructor (protected)
118 | protected LoadBalancer()
119 | {
120 | // List of available servers
121 | servers.Add("ServerI");
122 | servers.Add("ServerII");
123 | servers.Add("ServerIII");
124 | servers.Add("ServerIV");
125 | servers.Add("ServerV");
126 | }
127 |
128 | public static LoadBalancer GetLoadBalancer()
129 | {
130 | // Support multithreaded applications through
131 | // 'Double checked locking' pattern which (once
132 | // the instance exists) avoids locking each
133 | // time the method is invoked
134 | if (instance == null)
135 | {
136 | lock (locker)
137 | {
138 | if (instance == null)
139 | {
140 | instance = new LoadBalancer();
141 | }
142 | }
143 | }
144 |
145 | return instance;
146 | }
147 |
148 | // Simple, but effective random load balancer
149 | public string Server
150 | {
151 | get
152 | {
153 | int r = random.Next(servers.Count);
154 | return servers[r].ToString();
155 | }
156 | }
157 | }
158 | ```
159 |
160 | ## Улучшенная реальная реализация на C# (GoF) ##
161 |
162 | ```csharp
163 | ///
164 | /// MainApp startup class for .NET optimized
165 | /// Singleton Design Pattern.
166 | ///
167 | internal class MainApp
168 | {
169 | ///
170 | /// Entry point into console application.
171 | ///
172 | private static void Main()
173 | {
174 | var b1 = LoadBalancer.GetLoadBalancer();
175 | var b2 = LoadBalancer.GetLoadBalancer();
176 | var b3 = LoadBalancer.GetLoadBalancer();
177 | var b4 = LoadBalancer.GetLoadBalancer();
178 |
179 | // Confirm these are the same instance
180 | if (b1 == b2 && b2 == b3 && b3 == b4)
181 | {
182 | Console.WriteLine("Same instance\n");
183 | }
184 |
185 | // Next, load balance 15 requests for a server
186 | var balancer = LoadBalancer.GetLoadBalancer();
187 | for (int i = 0; i < 15; i++)
188 | {
189 | string serverName = balancer.NextServer.Name;
190 | Console.WriteLine("Dispatch request to: " + serverName);
191 | }
192 |
193 | // Wait for user
194 | Console.ReadKey();
195 | }
196 | }
197 |
198 | ///
199 | /// The 'Singleton' class
200 | ///
201 | internal sealed class LoadBalancer
202 | {
203 | // Static members are 'eagerly initialized', that is,
204 | // immediately when class is loaded for the first time.
205 | // .NET guarantees thread safety for static initialization
206 | private static readonly LoadBalancer instance = new LoadBalancer();
207 |
208 | // Type-safe generic list of servers
209 | private List servers;
210 |
211 | private Random random = new Random();
212 |
213 | // Note: constructor is 'private'
214 | private LoadBalancer()
215 | {
216 | // Load list of available servers
217 | servers = new List
218 | {
219 | new Server{ Name = "ServerI", IP = "120.14.220.18" },
220 | new Server{ Name = "ServerII", IP = "120.14.220.19" },
221 | new Server{ Name = "ServerIII", IP = "120.14.220.20" },
222 | new Server{ Name = "ServerIV", IP = "120.14.220.21" },
223 | new Server{ Name = "ServerV", IP = "120.14.220.22" },
224 | };
225 | }
226 |
227 | public static LoadBalancer GetLoadBalancer()
228 | {
229 | return instance;
230 | }
231 |
232 | // Simple, but effective load balancer
233 | public Server NextServer
234 | {
235 | get
236 | {
237 | int r = random.Next(servers.Count);
238 | return servers[r];
239 | }
240 | }
241 | }
242 |
243 | ///
244 | /// Represents a server machine
245 | ///
246 | internal class Server
247 | {
248 | // Gets or sets server name
249 | public string Name { get; set; }
250 |
251 | // Gets or sets server IP address
252 | public string IP { get; set; }
253 | }
254 | ```
255 |
256 | ## Реализация на C# (Head First) ##
257 |
258 | ```csharp
259 | internal class SingletonClient
260 | {
261 | private static void Main(string[] args)
262 | {
263 | var singleton = Singleton.getInstance();
264 | singleton.SaySomething();
265 |
266 | // .NET singleton threadsafe example.
267 |
268 | var es1 = EagerSingleton.GetInstance();
269 | var es2 = EagerSingleton.GetInstance();
270 | var es3 = EagerSingleton.GetInstance();
271 |
272 | if (es1 == es2 && es2 == es3)
273 | {
274 | Console.WriteLine("Same instance");
275 | }
276 |
277 | // Wait for user
278 | Console.ReadKey();
279 | }
280 | }
281 |
282 | #region Singleton
283 |
284 | public class Singleton
285 | {
286 | private static Singleton _uniqueInstance;
287 | private static readonly object _syncLock = new Object();
288 |
289 | // other useful instance variables here
290 |
291 | private Singleton()
292 | {
293 | }
294 |
295 | public static Singleton getInstance()
296 | {
297 | // Lock entire body of method
298 | lock (_syncLock)
299 | {
300 | if (_uniqueInstance == null)
301 | {
302 | _uniqueInstance = new Singleton();
303 | }
304 | return _uniqueInstance;
305 | }
306 | }
307 |
308 | // other useful methods here
309 | public void SaySomething()
310 | {
311 | Console.WriteLine("I run, therefore I am");
312 | }
313 | }
314 |
315 | internal sealed class EagerSingleton
316 | {
317 | // CLR eagerly initializes static member when class is first used
318 | // CLR guarantees thread safety for static initialisation
319 | private static readonly EagerSingleton _instance = new EagerSingleton();
320 |
321 | // Note: constructor is private
322 | private EagerSingleton()
323 | {
324 | }
325 |
326 | public static EagerSingleton GetInstance()
327 | {
328 | return _instance;
329 | }
330 | }
331 |
332 | #endregion Singleton
333 | ```
334 |
335 | ## Реализация на JAVA ##
336 |
337 | ```java
338 | /**
339 | * Singleton class. Eagerly initialized static instance guarantees thread safety.
340 | */
341 | public final class EagerlyInitializedSingleton {
342 |
343 | private static final EagerlyInitializedSingleton INSTANCE = new EagerlyInitializedSingleton();
344 |
345 | private EagerlyInitializedSingleton() {}
346 |
347 | public static EagerlyInitializedSingleton getInstance() {
348 | return INSTANCE;
349 | }
350 | }
351 |
352 | /**
353 | * The Initialize-on-demand-holder idiom is a secure way of creating a lazy initialized singleton
354 | * object in Java.
355 | *
356 | * The technique is as lazy as possible and works in all known versions of Java. It takes advantage
357 | * of language guarantees about class initialization, and will therefore work correctly in all
358 | * Java-compliant compilers and virtual machines.
359 | *
360 | * The inner class is referenced no earlier (and therefore loaded no earlier by the class loader) than
361 | * the moment that getInstance() is called. Thus, this solution is thread-safe without requiring special
362 | * language constructs (i.e. volatile or synchronized).
363 | */
364 | public final class InitializingOnDemandSingleton {
365 |
366 | private InitializingOnDemandSingleton() {}
367 |
368 | public static InitializingOnDemandSingleton getInstance() {
369 | return HelperHolder.INSTANCE;
370 | }
371 |
372 | private static class HelperHolder {
373 | private static final InitializingOnDemandSingleton INSTANCE =
374 | new InitializingOnDemandSingleton();
375 | }
376 | }
377 |
378 | /**
379 | * Thread-safe Singleton class.
380 | *
381 | * The instance is lazily initialized and thus needs synchronization mechanism.
382 | *
383 | * Note: if created by reflection then a singleton will not be created but multiple options in the same classloader.
384 | */
385 | public final class ThreadSafeLazyLoadedSingleton {
386 |
387 | private static ThreadSafeLazyLoadedSingleton instance;
388 |
389 | private ThreadSafeLazyLoadedSingleton() {}
390 |
391 | public static synchronized ThreadSafeLazyLoadedSingleton getInstance() {
392 | if (instance == null) {
393 | instance = new ThreadSafeLazyLoadedSingleton();
394 | }
395 | return instance;
396 | }
397 | }
398 |
399 | /**
400 | * Double check locking
401 | *
402 | * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
403 | *
404 | * Broken under Java 1.4.
405 | */
406 | public final class ThreadSafeDoubleCheckLockingSingleton {
407 |
408 | private static volatile ThreadSafeDoubleCheckLockingSingleton instance;
409 |
410 | private ThreadSafeDoubleCheckLockingSingleton() {
411 | // to prevent instantiating by Reflection call
412 | if (instance != null) {
413 | throw new IllegalStateException("Already initialized.");
414 | }
415 | }
416 |
417 | public static ThreadSafeDoubleCheckLockingSingleton getInstance() {
418 | // local variable increases performance by 25 percent
419 | // Joshua Bloch "Effective Java, Second Edition", p. 283-284
420 |
421 | ThreadSafeDoubleCheckLockingSingleton result = instance;
422 | // Check if singleton instance is initialized. If it is initialized then we can return the instance.
423 | if (result == null) {
424 | // It is not initialized but we cannot be sure because some other thread might have initialized it
425 | // in the meanwhile. So to make sure we need to lock on an object to get mutual exclusion.
426 | synchronized (ThreadSafeDoubleCheckLockingSingleton.class) {
427 | // Again assign the instance to local variable to check if it was initialized by some other thread
428 | // while current thread was blocked to enter the locked zone. If it was initialized then we can
429 | // return the previously created instance just like the previous null check.
430 | result = instance;
431 | if (result == null) {
432 | // The instance is still not initialized so we can safely (no other thread can enter this zone)
433 | // create an instance and make it our singleton instance.
434 | instance = result = new ThreadSafeDoubleCheckLockingSingleton();
435 | }
436 | }
437 | }
438 | return result;
439 | }
440 | }
441 |
442 | /**
443 | * Enum based singleton implementation.
444 | *
445 | * Effective Java 2nd Edition (Joshua Bloch) p. 18
446 | */
447 | public enum EnumSingleton {
448 |
449 | INSTANCE;
450 |
451 | @Override
452 | public String toString() {
453 | return getDeclaringClass().getCanonicalName() + "@" + hashCode();
454 | }
455 | }
456 | ```
--------------------------------------------------------------------------------
/design_patterns/creational/singleton_UML.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/creational/singleton_UML.png
--------------------------------------------------------------------------------
/design_patterns/structural/adapter.md:
--------------------------------------------------------------------------------
1 | # Адаптер (Adapter) #
2 |
3 | Паттерн Адаптер преобразует интерфейс класса к другому интерфейсу,
4 | на который рассчитывает клиент. Адаптер обеспечивает совместную работу классов,
5 | невозможную в обычных условиях из-за несовместимости интерфейсов.
6 |
7 | Адаптер класса использует множественное наследование для адаптации одного интерфейса к другому,
8 | поэтому не актуален для языков, в которых множественное наследование недоступно (C#, Java и прочие).
9 |
10 | Адаптер объекта применяет композицию объектов.
11 |
12 | 
13 |
14 | * Target - целевой интерфейс
15 |
16 | * Adaptee - адаптируемый интерфейс
17 |
18 | * Adapter - адаптер
19 |
20 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Адаптер_(шаблон_проектирования))
21 |
22 | ## Абстрактная реализация на C# (GoF) ##
23 |
24 | ```csharp
25 | ///
26 | /// MainApp startup class for Structural
27 | /// Adapter Design Pattern.
28 | ///
29 | internal class MainApp
30 | {
31 | ///
32 | /// Entry point into console application.
33 | ///
34 | private static void Main()
35 | {
36 | // Create adapter and place a request
37 | Target target = new Adapter();
38 | target.Request();
39 |
40 | // Wait for user
41 | Console.ReadKey();
42 | }
43 | }
44 |
45 | ///
46 | /// The 'Target' class
47 | ///
48 | internal class Target
49 | {
50 | public virtual void Request()
51 | {
52 | Console.WriteLine("Called Target Request()");
53 | }
54 | }
55 |
56 | ///
57 | /// The 'Adapter' class
58 | ///
59 | internal class Adapter : Target
60 | {
61 | private Adaptee adaptee = new Adaptee();
62 |
63 | public override void Request()
64 | {
65 | // Possibly do some other work
66 | // and then call SpecificRequest
67 | adaptee.SpecificRequest();
68 | }
69 | }
70 |
71 | ///
72 | /// The 'Adaptee' class
73 | ///
74 | internal class Adaptee
75 | {
76 | public void SpecificRequest()
77 | {
78 | Console.WriteLine("Called SpecificRequest()");
79 | }
80 | }
81 | ```
82 |
83 | ## Реальная реализация на C# (GoF) ##
84 |
85 | ```charp
86 | ///
87 | /// MainApp startup class for Real-World
88 | /// Adapter Design Pattern.
89 | ///
90 | internal class MainApp
91 | {
92 | ///
93 | /// Entry point into console application.
94 | ///
95 | private static void Main()
96 | {
97 | // Non-adapted chemical compound
98 | Compound unknown = new Compound();
99 | unknown.Display();
100 |
101 | // Adapted chemical compounds
102 | Compound water = new RichCompound("Water");
103 | water.Display();
104 |
105 | Compound benzene = new RichCompound("Benzene");
106 | benzene.Display();
107 |
108 | Compound ethanol = new RichCompound("Ethanol");
109 | ethanol.Display();
110 |
111 | // Wait for user
112 | Console.ReadKey();
113 | }
114 | }
115 |
116 | ///
117 | /// The 'Target' class
118 | ///
119 | internal class Compound
120 | {
121 | protected float boilingPoint;
122 | protected float meltingPoint;
123 | protected double molecularWeight;
124 | protected string molecularFormula;
125 |
126 | public virtual void Display()
127 | {
128 | Console.WriteLine("\nCompound: Unknown ------ ");
129 | }
130 | }
131 |
132 | ///
133 | /// The 'Adapter' class
134 | ///
135 | internal class RichCompound : Compound
136 | {
137 | private string chemical;
138 | private ChemicalDatabank bank;
139 |
140 | // Constructor
141 | public RichCompound(string chemical)
142 | {
143 | this.chemical = chemical;
144 | }
145 |
146 | public override void Display()
147 | {
148 | // The Adaptee
149 | bank = new ChemicalDatabank();
150 |
151 | boilingPoint = bank.GetCriticalPoint(chemical, "B");
152 | meltingPoint = bank.GetCriticalPoint(chemical, "M");
153 | molecularWeight = bank.GetMolecularWeight(chemical);
154 | molecularFormula = bank.GetMolecularStructure(chemical);
155 |
156 | Console.WriteLine("\nCompound: {0} ------ ", chemical);
157 | Console.WriteLine(" Formula: {0}", molecularFormula);
158 | Console.WriteLine(" Weight : {0}", molecularWeight);
159 | Console.WriteLine(" Melting Pt: {0}", meltingPoint);
160 | Console.WriteLine(" Boiling Pt: {0}", boilingPoint);
161 | }
162 | }
163 |
164 | ///
165 | /// The 'Adaptee' class
166 | ///
167 | internal class ChemicalDatabank
168 | {
169 | // The databank 'legacy API'
170 | public float GetCriticalPoint(string compound, string point)
171 | {
172 | // Melting Point
173 | if (point == "M")
174 | {
175 | switch (compound.ToLower())
176 | {
177 | case "water": return 0.0f;
178 | case "benzene": return 5.5f;
179 | case "ethanol": return -114.1f;
180 | default: return 0f;
181 | }
182 | }
183 | // Boiling Point
184 | else
185 | {
186 | switch (compound.ToLower())
187 | {
188 | case "water": return 100.0f;
189 | case "benzene": return 80.1f;
190 | case "ethanol": return 78.3f;
191 | default: return 0f;
192 | }
193 | }
194 | }
195 |
196 | public string GetMolecularStructure(string compound)
197 | {
198 | switch (compound.ToLower())
199 | {
200 | case "water": return "H20";
201 | case "benzene": return "C6H6";
202 | case "ethanol": return "C2H5OH";
203 | default: return "";
204 | }
205 | }
206 |
207 | public double GetMolecularWeight(string compound)
208 | {
209 | switch (compound.ToLower())
210 | {
211 | case "water": return 18.015;
212 | case "benzene": return 78.1134;
213 | case "ethanol": return 46.0688;
214 | default: return 0d;
215 | }
216 | }
217 | }
218 | ```
219 |
220 | ## Улучшенная реальная реализация на C# (GoF) ##
221 |
222 | ```csharp
223 | ///
224 | /// MainApp startup class for the .NET optimized
225 | /// Adapter Design Pattern.
226 | ///
227 | internal class MainApp
228 | {
229 | ///
230 | /// Entry point into console application.
231 | ///
232 | private static void Main()
233 | {
234 | // Non-adapted chemical compound
235 | var unknown = new Compound();
236 | unknown.Display();
237 |
238 | // Adapted chemical compounds
239 | var water = new RichCompound(Chemical.Water);
240 | water.Display();
241 |
242 | var benzene = new RichCompound(Chemical.Benzene);
243 | benzene.Display();
244 |
245 | var ethanol = new RichCompound(Chemical.Ethanol);
246 | ethanol.Display();
247 |
248 | // Wait for user
249 | Console.ReadKey();
250 | }
251 | }
252 |
253 | ///
254 | /// The 'Target' class
255 | ///
256 | internal class Compound
257 | {
258 | public Chemical Chemical { get; protected set; }
259 | public float BoilingPoint { get; protected set; }
260 | public float MeltingPoint { get; protected set; }
261 | public double MolecularWeight { get; protected set; }
262 | public string MolecularFormula { get; protected set; }
263 |
264 | public virtual void Display()
265 | {
266 | Console.WriteLine("\nCompound: Unknown ------ ");
267 | }
268 | }
269 |
270 | ///
271 | /// The 'Adapter' class
272 | ///
273 | internal class RichCompound : Compound
274 | {
275 | private ChemicalDatabank bank;
276 |
277 | // Constructor
278 | public RichCompound(Chemical chemical)
279 | {
280 | Chemical = chemical;
281 |
282 | // The Adaptee
283 | bank = new ChemicalDatabank();
284 | }
285 |
286 | public override void Display()
287 | {
288 | // Adaptee request methods
289 | BoilingPoint = bank.GetCriticalPoint(Chemical, State.Boiling);
290 | MeltingPoint = bank.GetCriticalPoint(Chemical, State.Melting);
291 | MolecularWeight = bank.GetMolecularWeight(Chemical);
292 | MolecularFormula = bank.GetMolecularStructure(Chemical);
293 |
294 | Console.WriteLine("\nCompound: {0} ------ ", Chemical);
295 | Console.WriteLine(" Formula: {0}", MolecularFormula);
296 | Console.WriteLine(" Weight : {0}", MolecularWeight);
297 | Console.WriteLine(" Melting Pt: {0}", MeltingPoint);
298 | Console.WriteLine(" Boiling Pt: {0}", BoilingPoint);
299 | }
300 | }
301 |
302 | ///
303 | /// The 'Adaptee' class
304 | ///
305 | internal class ChemicalDatabank
306 | {
307 | // The databank 'legacy API'
308 | public float GetCriticalPoint(Chemical compound, State point)
309 | {
310 | // Melting Point
311 | if (point == State.Melting)
312 | {
313 | switch (compound)
314 | {
315 | case Chemical.Water: return 0.0f;
316 | case Chemical.Benzene: return 5.5f;
317 | case Chemical.Ethanol: return -114.1f;
318 | default: return 0f;
319 | }
320 | }
321 | // Boiling Point
322 | else
323 | {
324 | switch (compound)
325 | {
326 | case Chemical.Water: return 100.0f;
327 | case Chemical.Benzene: return 80.1f;
328 | case Chemical.Ethanol: return 78.3f;
329 | default: return 0f;
330 | }
331 | }
332 | }
333 |
334 | public string GetMolecularStructure(Chemical compound)
335 | {
336 | switch (compound)
337 | {
338 | case Chemical.Water: return "H20";
339 | case Chemical.Benzene: return "C6H6";
340 | case Chemical.Ethanol: return "C2H5OH";
341 | default: return "";
342 | }
343 | }
344 |
345 | public double GetMolecularWeight(Chemical compound)
346 | {
347 | switch (compound)
348 | {
349 | case Chemical.Water: return 18.015;
350 | case Chemical.Benzene: return 78.1134;
351 | case Chemical.Ethanol: return 46.0688;
352 | }
353 | return 0d;
354 | }
355 | }
356 |
357 | ///
358 | /// Chemical enumeration
359 | ///
360 | public enum Chemical
361 | {
362 | Water,
363 | Benzene,
364 | Ethanol
365 | }
366 |
367 | ///
368 | /// State enumeration
369 | ///
370 | public enum State
371 | {
372 | Boiling,
373 | Melting
374 | }
375 | ```
376 |
377 | ## Реализация на C# (Head First) ##
378 |
379 | ```csharp
380 | internal class DuckTestDrive
381 | {
382 | private static void Main(string[] args)
383 | {
384 | // Test 1: Duck test drive
385 |
386 | var duck = new MallardDuck();
387 |
388 | var turkey = new WildTurkey();
389 | IDuck turkeyAdapter = new TurkeyAdapter(turkey);
390 |
391 | Console.WriteLine("The Turkey says...");
392 | turkey.Gobble();
393 | turkey.Fly();
394 |
395 | Console.WriteLine("\nThe Duck says...");
396 | TestDuck(duck);
397 |
398 | Console.WriteLine("\nThe TurkeyAdapter says...");
399 | TestDuck(turkeyAdapter);
400 |
401 | // Test 2: Turkey test drive
402 |
403 | ITurkey duckAdapter = new DuckAdapter(duck);
404 |
405 | for (int i = 0; i < 10; i++)
406 | {
407 | Console.WriteLine("The DuckAdapter says...");
408 | duckAdapter.Gobble();
409 | duckAdapter.Fly();
410 | }
411 |
412 | // Wait for user
413 | Console.ReadKey();
414 | }
415 |
416 | private static void TestDuck(IDuck duck)
417 | {
418 | duck.Quack();
419 | duck.Fly();
420 | }
421 | }
422 |
423 | public interface IDuck
424 | {
425 | void Quack();
426 |
427 | void Fly();
428 | }
429 |
430 | public interface ITurkey
431 | {
432 | void Gobble();
433 |
434 | void Fly();
435 | }
436 |
437 | public class MallardDuck : IDuck
438 | {
439 | public void Quack()
440 | {
441 | Console.WriteLine("Quack");
442 | }
443 |
444 | public void Fly()
445 | {
446 | Console.WriteLine("I'm flying");
447 | }
448 | }
449 |
450 | public class WildTurkey : ITurkey
451 | {
452 | public void Gobble()
453 | {
454 | Console.WriteLine("Gobble gobble");
455 | }
456 |
457 | public void Fly()
458 | {
459 | Console.WriteLine("I'm flying a short distance");
460 | }
461 | }
462 |
463 | public class DuckAdapter : ITurkey
464 | {
465 | private IDuck _duck;
466 | private Random _random = new Random();
467 |
468 | // Constructor
469 | public DuckAdapter(IDuck duck)
470 | {
471 | this._duck = duck;
472 | }
473 |
474 | public void Gobble()
475 | {
476 | _duck.Quack();
477 | }
478 |
479 | public void Fly()
480 | {
481 | if (_random.Next(5) == 0)
482 | {
483 | _duck.Fly();
484 | }
485 | }
486 | }
487 |
488 | public class TurkeyAdapter : IDuck
489 | {
490 | private ITurkey _turkey;
491 |
492 | // Constructor
493 | public TurkeyAdapter(ITurkey turkey)
494 | {
495 | this._turkey = turkey;
496 | }
497 |
498 | public void Quack()
499 | {
500 | _turkey.Gobble();
501 | }
502 |
503 | public void Fly()
504 | {
505 | for (int i = 0; i < 5; i++)
506 | {
507 | _turkey.Fly();
508 | }
509 | }
510 | }
511 | ```
512 |
513 | ## Реализация на JAVA ##
514 |
515 | ```java
516 | TODO
517 | ```
--------------------------------------------------------------------------------
/design_patterns/structural/adapter_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/adapter_UML.gif
--------------------------------------------------------------------------------
/design_patterns/structural/bridge.md:
--------------------------------------------------------------------------------
1 | # Мост (Bridge) #
2 |
3 | Также известен как Handle/Body (Описатель/Тело).
4 |
5 | Паттерн Мост позволяет изменять реализацию и абстракцию, для чего они размещаются в двух разных иерархиях классов.
6 |
7 | 
8 |
9 | * Abstraction - абстракция
10 |
11 | * RefinedAbstraction - уточненная абстракция
12 |
13 | * Implementor - абстрактый реализатор
14 |
15 | * ConcreteImplementor - конкретный реализатор
16 |
17 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Мост_(шаблон_проектирования))
18 |
19 | ## Абстрактная реализация на C# (GoF) ##
20 |
21 | ```csharp
22 | ///
23 | /// MainApp startup class for Structural
24 | /// Bridge Design Pattern.
25 | ///
26 | internal class MainApp
27 | {
28 | ///
29 | /// Entry point into console application.
30 | ///
31 | private static void Main()
32 | {
33 | Abstraction ab = new RefinedAbstraction();
34 |
35 | // Set implementation and call
36 | ab.Implementor = new ConcreteImplementorA();
37 | ab.Operation();
38 |
39 | // Change implemention and call
40 | ab.Implementor = new ConcreteImplementorB();
41 | ab.Operation();
42 |
43 | // Wait for user
44 | Console.ReadKey();
45 | }
46 | }
47 |
48 | ///
49 | /// The 'Abstraction' class
50 | ///
51 | internal class Abstraction
52 | {
53 | protected Implementor implementor;
54 |
55 | // Property
56 | public Implementor Implementor
57 | {
58 | set { implementor = value; }
59 | }
60 |
61 | public virtual void Operation()
62 | {
63 | implementor.Operation();
64 | }
65 | }
66 |
67 | ///
68 | /// The 'Implementor' abstract class
69 | ///
70 | internal abstract class Implementor
71 | {
72 | public abstract void Operation();
73 | }
74 |
75 | ///
76 | /// The 'RefinedAbstraction' class
77 | ///
78 | internal class RefinedAbstraction : Abstraction
79 | {
80 | public override void Operation()
81 | {
82 | implementor.Operation();
83 | }
84 | }
85 |
86 | ///
87 | /// The 'ConcreteImplementorA' class
88 | ///
89 | internal class ConcreteImplementorA : Implementor
90 | {
91 | public override void Operation()
92 | {
93 | Console.WriteLine("ConcreteImplementorA Operation");
94 | }
95 | }
96 |
97 | ///
98 | /// The 'ConcreteImplementorB' class
99 | ///
100 | internal class ConcreteImplementorB : Implementor
101 | {
102 | public override void Operation()
103 | {
104 | Console.WriteLine("ConcreteImplementorB Operation");
105 | }
106 | }
107 | ```
108 |
109 | ## Реальная реализация на C# (GoF) ##
110 |
111 | ```charp
112 | ///
113 | /// MainApp startup class for Real-World
114 | /// Bridge Design Pattern.
115 | ///
116 | internal class MainApp
117 | {
118 | ///
119 | /// Entry point into console application.
120 | ///
121 | private static void Main()
122 | {
123 | // Create RefinedAbstraction
124 | var customers = new Customers();
125 |
126 | // Set ConcreteImplementor
127 | customers.Data = new CustomersData("Chicago");
128 |
129 | // Exercise the bridge
130 | customers.Show();
131 | customers.Next();
132 | customers.Show();
133 | customers.Next();
134 | customers.Show();
135 | customers.Add("Henry Velasquez");
136 |
137 | customers.ShowAll();
138 |
139 | // Wait for user
140 | Console.ReadKey();
141 | }
142 | }
143 |
144 | ///
145 | /// The 'Abstraction' class
146 | ///
147 | internal class CustomersBase
148 | {
149 | private DataObject dataObject;
150 |
151 | public DataObject Data
152 | {
153 | set { dataObject = value; }
154 | get { return dataObject; }
155 | }
156 |
157 | public virtual void Next()
158 | {
159 | dataObject.NextRecord();
160 | }
161 |
162 | public virtual void Prior()
163 | {
164 | dataObject.PriorRecord();
165 | }
166 |
167 | public virtual void Add(string customer)
168 | {
169 | dataObject.AddRecord(customer);
170 | }
171 |
172 | public virtual void Delete(string customer)
173 | {
174 | dataObject.DeleteRecord(customer);
175 | }
176 |
177 | public virtual void Show()
178 | {
179 | dataObject.ShowRecord();
180 | }
181 |
182 | public virtual void ShowAll()
183 | {
184 | dataObject.ShowAllRecords();
185 | }
186 | }
187 |
188 | ///
189 | /// The 'RefinedAbstraction' class
190 | ///
191 | internal class Customers : CustomersBase
192 | {
193 | public override void ShowAll()
194 | {
195 | // Add separator lines
196 | Console.WriteLine();
197 | Console.WriteLine("------------------------");
198 | base.ShowAll();
199 | Console.WriteLine("------------------------");
200 | }
201 | }
202 |
203 | ///
204 | /// The 'Implementor' abstract class
205 | ///
206 | internal abstract class DataObject
207 | {
208 | public abstract void NextRecord();
209 |
210 | public abstract void PriorRecord();
211 |
212 | public abstract void AddRecord(string name);
213 |
214 | public abstract void DeleteRecord(string name);
215 |
216 | public abstract string GetCurrentRecord();
217 |
218 | public abstract void ShowRecord();
219 |
220 | public abstract void ShowAllRecords();
221 | }
222 |
223 | ///
224 | /// The 'ConcreteImplementor' class
225 | ///
226 | internal class CustomersData : DataObject
227 | {
228 | private List customers = new List();
229 | private int current = 0;
230 |
231 | private string city;
232 |
233 | public CustomersData(string city)
234 | {
235 | this.city = city;
236 |
237 | // Loaded from a database
238 | customers.Add("Jim Jones");
239 | customers.Add("Samual Jackson");
240 | customers.Add("Allen Good");
241 | customers.Add("Ann Stills");
242 | customers.Add("Lisa Giolani");
243 | }
244 |
245 | public override void NextRecord()
246 | {
247 | if (current <= customers.Count - 1)
248 | {
249 | current++;
250 | }
251 | }
252 |
253 | public override void PriorRecord()
254 | {
255 | if (current > 0)
256 | {
257 | current--;
258 | }
259 | }
260 |
261 | public override void AddRecord(string customer)
262 | {
263 | customers.Add(customer);
264 | }
265 |
266 | public override void DeleteRecord(string customer)
267 | {
268 | customers.Remove(customer);
269 | }
270 |
271 | public override string GetCurrentRecord()
272 | {
273 | return customers[current];
274 | }
275 |
276 | public override void ShowRecord()
277 | {
278 | Console.WriteLine(customers[current]);
279 | }
280 |
281 | public override void ShowAllRecords()
282 | {
283 | Console.WriteLine("Customer City: " + city);
284 | foreach (string customer in customers)
285 | {
286 | Console.WriteLine(" " + customer);
287 | }
288 | }
289 | }
290 | ```
291 |
292 | ## Улучшенная реальная реализация на C# (GoF) ##
293 |
294 | ```csharp
295 | ///
296 | /// MainApp startup class for .NET optimized
297 | /// Bridge Design Pattern.
298 | ///
299 | internal class MainApp
300 | {
301 | ///
302 | /// Entry point into console application.
303 | ///
304 | private static void Main()
305 | {
306 | // Create RefinedAbstraction
307 | var customers = new Customers();
308 |
309 | // Set ConcreteImplementor
310 | customers.DataObject = new CustomersData { City = "Chicago" };
311 |
312 | // Exercise the bridge
313 | customers.Show();
314 | customers.Next();
315 | customers.Show();
316 | customers.Next();
317 | customers.Show();
318 |
319 | customers.Add("Henry Velasquez");
320 | customers.ShowAll();
321 |
322 | // Wait for user
323 | Console.ReadKey();
324 | }
325 | }
326 |
327 | ///
328 | /// The 'Abstraction' class
329 | ///
330 | internal class CustomersBase
331 | {
332 | // Gets or sets data object
333 | public IDataObject DataObject { get; set; }
334 |
335 | public virtual void Next()
336 | {
337 | DataObject.NextRecord();
338 | }
339 |
340 | public virtual void Prior()
341 | {
342 | DataObject.PriorRecord();
343 | }
344 |
345 | public virtual void Add(string name)
346 | {
347 | DataObject.AddRecord(name);
348 | }
349 |
350 | public virtual void Delete(string name)
351 | {
352 | DataObject.DeleteRecord(name);
353 | }
354 |
355 | public virtual void Show()
356 | {
357 | DataObject.ShowRecord();
358 | }
359 |
360 | public virtual void ShowAll()
361 | {
362 | DataObject.ShowAllRecords();
363 | }
364 | }
365 |
366 | ///
367 | /// The 'RefinedAbstraction' class
368 | ///
369 | internal class Customers : CustomersBase
370 | {
371 | public override void ShowAll()
372 | {
373 | // Add separator lines
374 | Console.WriteLine();
375 | Console.WriteLine("------------------------");
376 | base.ShowAll();
377 | Console.WriteLine("------------------------");
378 | }
379 | }
380 |
381 | ///
382 | /// The 'Implementor' interface
383 | ///
384 | internal interface IDataObject
385 | {
386 | void NextRecord();
387 |
388 | void PriorRecord();
389 |
390 | void AddRecord(T t);
391 |
392 | void DeleteRecord(T t);
393 |
394 | T GetCurrentRecord();
395 |
396 | void ShowRecord();
397 |
398 | void ShowAllRecords();
399 | }
400 |
401 | ///
402 | /// The 'ConcreteImplementor' class
403 | ///
404 | internal class CustomersData : IDataObject
405 | {
406 | // Gets or sets city
407 | public string City { get; set; }
408 |
409 | private List customers;
410 | private int current = 0;
411 |
412 | // Constructor
413 | public CustomersData()
414 | {
415 | // Simulate loading from database
416 | customers = new List
417 | { "Jim Jones", "Samual Jackson", "Allan Good",
418 | "Ann Stills", "Lisa Giolani" };
419 | }
420 |
421 | public void NextRecord()
422 | {
423 | if (current <= customers.Count - 1)
424 | {
425 | current++;
426 | }
427 | }
428 |
429 | public void PriorRecord()
430 | {
431 | if (current > 0)
432 | {
433 | current--;
434 | }
435 | }
436 |
437 | public void AddRecord(string customer)
438 | {
439 | customers.Add(customer);
440 | }
441 |
442 | public void DeleteRecord(string customer)
443 | {
444 | customers.Remove(customer);
445 | }
446 |
447 | public string GetCurrentRecord()
448 | {
449 | return customers[current];
450 | }
451 |
452 | public void ShowRecord()
453 | {
454 | Console.WriteLine(customers[current]);
455 | }
456 |
457 | public void ShowAllRecords()
458 | {
459 | Console.WriteLine("Customer Group: " + City);
460 | customers.ForEach(customer =>
461 | Console.WriteLine(" " + customer));
462 | }
463 | }
464 | ```
465 |
466 | ## Реализация на JAVA ##
467 |
468 | ```java
469 | TODO
470 | ```
--------------------------------------------------------------------------------
/design_patterns/structural/bridge_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/bridge_UML.gif
--------------------------------------------------------------------------------
/design_patterns/structural/composite_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/composite_UML.gif
--------------------------------------------------------------------------------
/design_patterns/structural/decorator_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/decorator_UML.gif
--------------------------------------------------------------------------------
/design_patterns/structural/facade_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/facade_UML.gif
--------------------------------------------------------------------------------
/design_patterns/structural/flyweight.md:
--------------------------------------------------------------------------------
1 | # Приспособленец (Flyweight) #
2 |
3 | Используйте паттерн Приспособленец, если один экземпляр класса может предоставлять много "виртуальных экземпляров".
4 |
5 | 
6 |
7 | * Flyweight - абстрактный приспособленец
8 |
9 | * ConcreteFlyweight - конкретный приспособленец
10 |
11 | * UnsharedConcreteFlyweight - неразделяемый конкретный приспособленец
12 |
13 | * FlyweightFactory - фабрика приспособленцев
14 |
15 | * Client - клиент
16 |
17 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Приспособленец_(шаблон_проектирования))
18 |
19 | ## Абстрактная реализация на C# (GoF) ##
20 |
21 | ```csharp
22 | ///
23 | /// MainApp startup class for Structural
24 | /// Flyweight Design Pattern.
25 | ///
26 | internal class MainApp
27 | {
28 | ///
29 | /// Entry point into console application.
30 | ///
31 | private static void Main()
32 | {
33 | // Arbitrary extrinsic state
34 | int extrinsicstate = 22;
35 |
36 | FlyweightFactory factory = new FlyweightFactory();
37 |
38 | // Work with different flyweight instances
39 | Flyweight fx = factory.GetFlyweight("X");
40 | fx.Operation(--extrinsicstate);
41 |
42 | Flyweight fy = factory.GetFlyweight("Y");
43 | fy.Operation(--extrinsicstate);
44 |
45 | Flyweight fz = factory.GetFlyweight("Z");
46 | fz.Operation(--extrinsicstate);
47 |
48 | UnsharedConcreteFlyweight fu = new
49 | UnsharedConcreteFlyweight();
50 |
51 | fu.Operation(--extrinsicstate);
52 |
53 | // Wait for user
54 | Console.ReadKey();
55 | }
56 | }
57 |
58 | ///
59 | /// The 'FlyweightFactory' class
60 | ///
61 | internal class FlyweightFactory
62 | {
63 | private Hashtable flyweights = new Hashtable();
64 |
65 | // Constructor
66 | public FlyweightFactory()
67 | {
68 | flyweights.Add("X", new ConcreteFlyweight());
69 | flyweights.Add("Y", new ConcreteFlyweight());
70 | flyweights.Add("Z", new ConcreteFlyweight());
71 | }
72 |
73 | public Flyweight GetFlyweight(string key)
74 | {
75 | return ((Flyweight)flyweights[key]);
76 | }
77 | }
78 |
79 | ///
80 | /// The 'Flyweight' abstract class
81 | ///
82 | internal abstract class Flyweight
83 | {
84 | public abstract void Operation(int extrinsicstate);
85 | }
86 |
87 | ///
88 | /// The 'ConcreteFlyweight' class
89 | ///
90 | internal class ConcreteFlyweight : Flyweight
91 | {
92 | public override void Operation(int extrinsicstate)
93 | {
94 | Console.WriteLine("ConcreteFlyweight: " + extrinsicstate);
95 | }
96 | }
97 |
98 | ///
99 | /// The 'UnsharedConcreteFlyweight' class
100 | ///
101 | internal class UnsharedConcreteFlyweight : Flyweight
102 | {
103 | public override void Operation(int extrinsicstate)
104 | {
105 | Console.WriteLine("UnsharedConcreteFlyweight: " +
106 | extrinsicstate);
107 | }
108 | }
109 | ```
110 |
111 | ## Реальная реализация на C# (GoF) ##
112 |
113 | ```charp
114 | ///
115 | /// MainApp startup class for Real-World
116 | /// Flyweight Design Pattern.
117 | ///
118 | internal class MainApp
119 | {
120 | ///
121 | /// Entry point into console application.
122 | ///
123 | private static void Main()
124 | {
125 | // Build a document with text
126 | string document = "AAZZBBZB";
127 | char[] chars = document.ToCharArray();
128 |
129 | CharacterFactory factory = new CharacterFactory();
130 |
131 | // extrinsic state
132 | int pointSize = 10;
133 |
134 | // For each character use a flyweight object
135 | foreach (char c in chars)
136 | {
137 | pointSize++;
138 | Character character = factory.GetCharacter(c);
139 | character.Display(pointSize);
140 | }
141 |
142 | // Wait for user
143 | Console.ReadKey();
144 | }
145 | }
146 |
147 | ///
148 | /// The 'FlyweightFactory' class
149 | ///
150 | internal class CharacterFactory
151 | {
152 | private Dictionary characters = new Dictionary();
153 |
154 | public Character GetCharacter(char key)
155 | {
156 | // Uses "lazy initialization"
157 | Character character = null;
158 | if (characters.ContainsKey(key))
159 | {
160 | character = characters[key];
161 | }
162 | else
163 | {
164 | switch (key)
165 | {
166 | case 'A': character = new CharacterA(); break;
167 | case 'B': character = new CharacterB(); break;
168 | //...
169 | case 'Z': character = new CharacterZ(); break;
170 | }
171 | characters.Add(key, character);
172 | }
173 | return character;
174 | }
175 | }
176 |
177 | ///
178 | /// The 'Flyweight' abstract class
179 | ///
180 | internal abstract class Character
181 | {
182 | protected char symbol;
183 | protected int width;
184 | protected int height;
185 | protected int ascent;
186 | protected int descent;
187 | protected int pointSize;
188 |
189 | public abstract void Display(int pointSize);
190 | }
191 |
192 | ///
193 | /// A 'ConcreteFlyweight' class
194 | ///
195 | internal class CharacterA : Character
196 | {
197 | // Constructor
198 | public CharacterA()
199 | {
200 | this.symbol = 'A';
201 | this.height = 100;
202 | this.width = 120;
203 | this.ascent = 70;
204 | this.descent = 0;
205 | }
206 |
207 | public override void Display(int pointSize)
208 | {
209 | this.pointSize = pointSize;
210 | Console.WriteLine(this.symbol +
211 | " (pointsize " + this.pointSize + ")");
212 | }
213 | }
214 |
215 | ///
216 | /// A 'ConcreteFlyweight' class
217 | ///
218 | internal class CharacterB : Character
219 | {
220 | // Constructor
221 | public CharacterB()
222 | {
223 | this.symbol = 'B';
224 | this.height = 100;
225 | this.width = 140;
226 | this.ascent = 72;
227 | this.descent = 0;
228 | }
229 |
230 | public override void Display(int pointSize)
231 | {
232 | this.pointSize = pointSize;
233 | Console.WriteLine(this.symbol +
234 | " (pointsize " + this.pointSize + ")");
235 | }
236 | }
237 |
238 | // ... C, D, E, etc.
239 |
240 | ///
241 | /// A 'ConcreteFlyweight' class
242 | ///
243 | internal class CharacterZ : Character
244 | {
245 | // Constructor
246 | public CharacterZ()
247 | {
248 | this.symbol = 'Z';
249 | this.height = 100;
250 | this.width = 100;
251 | this.ascent = 68;
252 | this.descent = 0;
253 | }
254 |
255 | public override void Display(int pointSize)
256 | {
257 | this.pointSize = pointSize;
258 | Console.WriteLine(this.symbol +
259 | " (pointsize " + this.pointSize + ")");
260 | }
261 | }
262 | ```
263 |
264 | ## Улучшенная реальная реализация на C# (GoF) ##
265 |
266 | ```csharp
267 | ///
268 | /// MainApp startup class for .NET optimized
269 | /// Flyweight Design Pattern.
270 | ///
271 | internal class MainApp
272 | {
273 | ///
274 | /// Entry point into console application.
275 | ///
276 | private static void Main()
277 | {
278 | // Build a document with text
279 | string document = "AAZZBBZB";
280 | char[] chars = document.ToCharArray();
281 |
282 | var factory = new CharacterFactory();
283 |
284 | // extrinsic state
285 | int pointSize = 10;
286 |
287 | // For each character use a flyweight object
288 | foreach (char c in chars)
289 | {
290 | var character = factory[c];
291 | character.Display(++pointSize);
292 | }
293 |
294 | // Wait for user
295 | Console.ReadKey();
296 | }
297 | }
298 |
299 | ///
300 | /// The 'FlyweightFactory' class
301 | ///
302 | internal class CharacterFactory
303 | {
304 | private Dictionary characters = new Dictionary();
305 |
306 | // Character indexer
307 | public Character this[char key]
308 | {
309 | get
310 | {
311 | // Uses "lazy initialization" -- i.e. only create when needed.
312 | Character character = null;
313 | if (characters.ContainsKey(key))
314 | {
315 | character = characters[key];
316 | }
317 | else
318 | {
319 | // Instead of a case statement with 26 cases (characters).
320 | // First, get qualified class name, then dynamically create instance
321 | string name = this.GetType().Namespace + "." + "Character" + key.ToString();
322 | character = (Character)Activator.CreateInstance(Type.GetType(name));
323 | }
324 |
325 | return character;
326 | }
327 | }
328 | }
329 |
330 | ///
331 | /// The 'Flyweight' class
332 | ///
333 | internal class Character
334 | {
335 | protected char symbol;
336 | protected int width;
337 | protected int height;
338 | protected int ascent;
339 | protected int descent;
340 |
341 | public void Display(int pointSize)
342 | {
343 | Console.WriteLine(this.symbol +
344 | " (pointsize " + pointSize + ")");
345 | }
346 | }
347 |
348 | ///
349 | /// A 'ConcreteFlyweight' class
350 | ///
351 | internal class CharacterA : Character
352 | {
353 | // Constructor
354 | public CharacterA()
355 | {
356 | this.symbol = 'A';
357 | this.height = 100;
358 | this.width = 120;
359 | this.ascent = 70;
360 | this.descent = 0;
361 | }
362 | }
363 |
364 | ///
365 | /// A 'ConcreteFlyweight' class
366 | ///
367 | internal class CharacterB : Character
368 | {
369 | // Constructor
370 | public CharacterB()
371 | {
372 | this.symbol = 'B';
373 | this.height = 100;
374 | this.width = 140;
375 | this.ascent = 72;
376 | this.descent = 0;
377 | }
378 | }
379 |
380 | // ... C, D, E, etc.
381 |
382 | ///
383 | /// A 'ConcreteFlyweight' class
384 | ///
385 | internal class CharacterZ : Character
386 | {
387 | // Constructor
388 | public CharacterZ()
389 | {
390 | this.symbol = 'Z';
391 | this.height = 100;
392 | this.width = 100;
393 | this.ascent = 68;
394 | this.descent = 0;
395 | }
396 | }
397 | ```
398 |
399 | ## Реализация на JAVA ##
400 |
401 | ```java
402 | TODO
403 | ```
--------------------------------------------------------------------------------
/design_patterns/structural/flyweight_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/flyweight_UML.gif
--------------------------------------------------------------------------------
/design_patterns/structural/proxy.md:
--------------------------------------------------------------------------------
1 | # Заместитель (Proxy) #
2 |
3 | Также известен как Суррогат (Surrogate).
4 |
5 | Паттерн Заместитель предоставляет суррогатный объект, управляющий доступом к другому объекту.
6 |
7 | 
8 |
9 | * Proxy - заместитель
10 |
11 | * Subject - абстрактный субъект замещения
12 |
13 | * RealSubject - реальный субъект замещения
14 |
15 | * Client - клиент
16 |
17 | [Статья на Википедии](https://ru.wikipedia.org/wiki/Proxy_(шаблон_проектирования))
18 |
19 | Разновидности заместителей:
20 |
21 | * _Удаленный Заместитель_ управляет доступом к удаленному объекту из локального объекта-суррогата.
22 |
23 | * _Виртуальный Заместитель_ управляет доступом к объекту, создание которого требует больщих затрат ресурсов.
24 |
25 | * _Защитный Заместитель_ контролирует доступ к объекту в соответствии с системой привелегий.
26 |
27 | * _Фильтрирующий Заместитель_ управляет доступом к группам сетевых ресурсов, защищая их от несанкционированного доступа.
28 |
29 | * _Умная Ссылка_ обеспечивает выполнение дополнительных действий при обращении к объекту (например, счетчик обращений и т.д.).
30 |
31 | * _Кэширующий Заместитель_ обеспечивает временное хранение результатов высокозатратных операций.
32 | Также может обеспечивать совместный доступ к результатам для предотвращения лишних вычислений или пересылки данных по сети.
33 |
34 | * _Синхронизирующий Заместитель_ предоставляет безопасный доступ к объекту из нескольких программных потоков.
35 |
36 | * _Упрощающий Заместитель_ скрывает сложность и управляет доступом к сложному набору классов.
37 | Иногда называется Фасадным Заместителем. Отличается от паттерна Фасад тем, что первый управляет доступом,
38 | а второй только предоставляет альтернативный интерфейс.
39 |
40 | * _Заместитель Отложенного Копирования_ задерживает фактическое копирование объекта до момента выполнения операций с копией
41 | (разновидность Виртуального Заместителя).
42 |
43 | ## Абстрактная реализация на C# (GoF) ##
44 |
45 | ```csharp
46 | ///
47 | /// MainApp startup class for Structural
48 | /// Proxy Design Pattern.
49 | ///
50 | internal class MainApp
51 | {
52 | ///
53 | /// Entry point into console application.
54 | ///
55 | private static void Main()
56 | {
57 | // Create proxy and request a service
58 | Proxy proxy = new Proxy();
59 | proxy.Request();
60 |
61 | // Wait for user
62 | Console.ReadKey();
63 | }
64 | }
65 |
66 | ///
67 | /// The 'Subject' abstract class
68 | ///
69 | internal abstract class Subject
70 | {
71 | public abstract void Request();
72 | }
73 |
74 | ///
75 | /// The 'RealSubject' class
76 | ///
77 | internal class RealSubject : Subject
78 | {
79 | public override void Request()
80 | {
81 | Console.WriteLine("Called RealSubject.Request()");
82 | }
83 | }
84 |
85 | ///
86 | /// The 'Proxy' class
87 | ///
88 | internal class Proxy : Subject
89 | {
90 | private RealSubject realSubject;
91 |
92 | public override void Request()
93 | {
94 | // Use 'lazy initialization'
95 | if (realSubject == null)
96 | {
97 | realSubject = new RealSubject();
98 | }
99 |
100 | realSubject.Request();
101 | }
102 | }
103 | ```
104 |
105 | ## Реальная реализация на C# (GoF) ##
106 |
107 | ```charp
108 | ///
109 | /// MainApp startup class for Real-World
110 | /// Proxy Design Pattern.
111 | ///
112 | internal class MainApp
113 | {
114 | ///
115 | /// Entry point into console application.
116 | ///
117 | private static void Main()
118 | {
119 | // Create math proxy
120 | MathProxy proxy = new MathProxy();
121 |
122 | // Do the math
123 | Console.WriteLine("4 + 2 = " + proxy.Add(4, 2));
124 | Console.WriteLine("4 - 2 = " + proxy.Sub(4, 2));
125 | Console.WriteLine("4 * 2 = " + proxy.Mul(4, 2));
126 | Console.WriteLine("4 / 2 = " + proxy.Div(4, 2));
127 |
128 | // Wait for user
129 | Console.ReadKey();
130 | }
131 | }
132 |
133 | ///
134 | /// The 'Subject interface
135 | ///
136 | public interface IMath
137 | {
138 | double Add(double x, double y);
139 |
140 | double Sub(double x, double y);
141 |
142 | double Mul(double x, double y);
143 |
144 | double Div(double x, double y);
145 | }
146 |
147 | ///
148 | /// The 'RealSubject' class
149 | ///
150 | internal class Math : IMath
151 | {
152 | public double Add(double x, double y)
153 | {
154 | return x + y;
155 | }
156 |
157 | public double Sub(double x, double y)
158 | {
159 | return x - y;
160 | }
161 |
162 | public double Mul(double x, double y)
163 | {
164 | return x * y;
165 | }
166 |
167 | public double Div(double x, double y)
168 | {
169 | return x / y;
170 | }
171 | }
172 |
173 | ///
174 | /// The 'Proxy Object' class
175 | ///
176 | internal class MathProxy : IMath
177 | {
178 | private Math math = new Math();
179 |
180 | public double Add(double x, double y)
181 | {
182 | return math.Add(x, y);
183 | }
184 |
185 | public double Sub(double x, double y)
186 | {
187 | return math.Sub(x, y);
188 | }
189 |
190 | public double Mul(double x, double y)
191 | {
192 | return math.Mul(x, y);
193 | }
194 |
195 | public double Div(double x, double y)
196 | {
197 | return math.Div(x, y);
198 | }
199 | }
200 | ```
201 |
202 | ## Улучшенная реальная реализация на C# (GoF) ##
203 |
204 | ```csharp
205 | ///
206 | /// MainApp startup class for .NET optimized
207 | /// Proxy Design Pattern.
208 | ///
209 | internal class MainApp
210 | {
211 | ///
212 | /// Entry point into console application.
213 | ///
214 | private static void Main()
215 | {
216 | // Create math proxy
217 | var proxy = new MathProxy();
218 |
219 | // Do the math
220 | Console.WriteLine("4 + 2 = " + proxy.Add(4, 2));
221 | Console.WriteLine("4 - 2 = " + proxy.Sub(4, 2));
222 | Console.WriteLine("4 * 2 = " + proxy.Mul(4, 2));
223 | Console.WriteLine("4 / 2 = " + proxy.Div(4, 2));
224 |
225 | // Wait for user
226 | Console.ReadKey();
227 | }
228 | }
229 |
230 | ///
231 | /// The 'Subject' interface
232 | ///
233 | public interface IMath
234 | {
235 | double Add(double x, double y);
236 |
237 | double Sub(double x, double y);
238 |
239 | double Mul(double x, double y);
240 |
241 | double Div(double x, double y);
242 | }
243 |
244 | ///
245 | /// The 'RealSubject' class
246 | ///
247 | internal class Math : MarshalByRefObject, IMath
248 | {
249 | public double Add(double x, double y)
250 | {
251 | return x + y;
252 | }
253 |
254 | public double Sub(double x, double y)
255 | {
256 | return x - y;
257 | }
258 |
259 | public double Mul(double x, double y)
260 | {
261 | return x * y;
262 | }
263 |
264 | public double Div(double x, double y)
265 | {
266 | return x / y;
267 | }
268 | }
269 |
270 | ///
271 | /// The remote 'Proxy Object' class
272 | ///
273 | internal class MathProxy : IMath
274 | {
275 | private Math math;
276 |
277 | // Constructor
278 | public MathProxy()
279 | {
280 | // Create Math instance in a different AppDomain
281 | var ad = AppDomain.CreateDomain("MathDomain", null, null);
282 |
283 | var o = ad.CreateInstance(
284 | "DoFactory.GangOfFour.Proxy.NETOptimized",
285 | "DoFactory.GangOfFour.Proxy.NETOptimized.Math");
286 | math = (Math)o.Unwrap();
287 | }
288 |
289 | public double Add(double x, double y)
290 | {
291 | return math.Add(x, y);
292 | }
293 |
294 | public double Sub(double x, double y)
295 | {
296 | return math.Sub(x, y);
297 | }
298 |
299 | public double Mul(double x, double y)
300 | {
301 | return math.Mul(x, y);
302 | }
303 |
304 | public double Div(double x, double y)
305 | {
306 | return math.Div(x, y);
307 | }
308 | }
309 | ```
310 |
311 | ## Реализация на C# (Head First) ##
312 |
313 | ```csharp
314 | ///
315 | /// Summary description for FormVirtualProxy.
316 | ///
317 | public class FormVirtualProxy : System.Windows.Forms.Form
318 | {
319 | private System.Windows.Forms.Button buttonTestImageProxy;
320 | private System.Windows.Forms.PictureBox pictureBox;
321 | private System.Windows.Forms.Label label1;
322 |
323 | ///
324 | /// Required designer variable.
325 | ///
326 | private System.ComponentModel.Container components = null;
327 |
328 | public FormVirtualProxy()
329 | {
330 | //
331 | // Required for Windows Form Designer support
332 | //
333 | InitializeComponent();
334 | }
335 |
336 | ///
337 | /// Clean up any resources being used.
338 | ///
339 | protected override void Dispose(bool disposing)
340 | {
341 | if (disposing)
342 | {
343 | if (components != null)
344 | {
345 | components.Dispose();
346 | }
347 | }
348 | base.Dispose(disposing);
349 | }
350 |
351 | #region Windows Form Designer generated code
352 |
353 | ///
354 | /// Required method for Designer support - do not modify
355 | /// the contents of this method with the code editor.
356 | ///
357 | private void InitializeComponent()
358 | {
359 | this.buttonTestImageProxy = new System.Windows.Forms.Button();
360 | this.pictureBox = new System.Windows.Forms.PictureBox();
361 | this.label1 = new System.Windows.Forms.Label();
362 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
363 | this.SuspendLayout();
364 | //
365 | // buttonTestImageProxy
366 | //
367 | this.buttonTestImageProxy.Location = new System.Drawing.Point(197, 25);
368 | this.buttonTestImageProxy.Name = "buttonTestImageProxy";
369 | this.buttonTestImageProxy.Size = new System.Drawing.Size(105, 23);
370 | this.buttonTestImageProxy.TabIndex = 0;
371 | this.buttonTestImageProxy.Text = "Test Image Proxy";
372 | this.buttonTestImageProxy.Click += new System.EventHandler(this.buttonTestImageProxy_Click);
373 | //
374 | // pictureBox
375 | //
376 | this.pictureBox.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
377 | this.pictureBox.Location = new System.Drawing.Point(31, 24);
378 | this.pictureBox.Name = "pictureBox";
379 | this.pictureBox.Size = new System.Drawing.Size(147, 159);
380 | this.pictureBox.TabIndex = 1;
381 | this.pictureBox.TabStop = false;
382 | this.pictureBox.Click += new System.EventHandler(this.pictureBox_Click);
383 | //
384 | // label1
385 | //
386 | this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
387 | this.label1.Location = new System.Drawing.Point(194, 51);
388 | this.label1.Name = "label1";
389 | this.label1.Size = new System.Drawing.Size(118, 20);
390 | this.label1.TabIndex = 2;
391 | this.label1.Text = "Click button twice";
392 | this.label1.Click += new System.EventHandler(this.label1_Click);
393 | //
394 | // FormVirtualProxy
395 | //
396 | this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
397 | this.ClientSize = new System.Drawing.Size(323, 217);
398 | this.Controls.Add(this.label1);
399 | this.Controls.Add(this.pictureBox);
400 | this.Controls.Add(this.buttonTestImageProxy);
401 | this.Name = "FormVirtualProxy";
402 | this.Text = "Virtual Proxy Test";
403 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit();
404 | this.ResumeLayout(false);
405 | }
406 |
407 | #endregion Windows Form Designer generated code
408 |
409 | ///
410 | /// The main entry point for the application.
411 | ///
412 | [STAThread]
413 | private static void Main()
414 | {
415 | Application.Run(new FormVirtualProxy());
416 | }
417 |
418 | private void buttonTestImageProxy_Click(object sender, System.EventArgs e)
419 | {
420 | this.pictureBox.Image = new ImageProxy().Image;
421 | }
422 |
423 | private void pictureBox_Click(object sender, System.EventArgs e)
424 | {
425 | }
426 |
427 | private void label1_Click(object sender, System.EventArgs e)
428 | {
429 | }
430 |
431 | private class ImageProxy
432 | {
433 | private static Image _image = null;
434 | private int _width = 133;
435 | private int _height = 154;
436 | private bool _retrieving = false;
437 |
438 | public int Width
439 | {
440 | get { return _image == null ? _width : _image.Width; }
441 | }
442 |
443 | public int Height
444 | {
445 | get { return _image == null ? _height : _image.Height; }
446 | }
447 |
448 | public Image Image
449 | {
450 | get
451 | {
452 | if (_image != null)
453 | return _image;
454 | else
455 | {
456 | if (!_retrieving)
457 | {
458 | _retrieving = true;
459 | Thread retrievalThread = new Thread(new ThreadStart(RetrieveImage));
460 | retrievalThread.Start();
461 | }
462 | return PlaceHolderImage();
463 | }
464 | }
465 | }
466 |
467 | public Image PlaceHolderImage()
468 | {
469 | return new Bitmap(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("DoFactory.HeadFirst.Proxy.VirtualProxy.PlaceHolder.jpg"));
470 | }
471 |
472 | public void RetrieveImage()
473 | {
474 | // Book image from amazon
475 | string url = "http://images.amazon.com/images/P/0596007124.01._PE34_SCMZZZZZZZ_.jpg";
476 |
477 | HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
478 | HttpWebResponse response = (HttpWebResponse)request.GetResponse();
479 | _image = Image.FromStream(response.GetResponseStream());
480 | }
481 | }
482 | }
483 | ```
484 |
485 | ## Реализация на JAVA ##
486 |
487 | ```java
488 | TODO
489 | ```
--------------------------------------------------------------------------------
/design_patterns/structural/proxy_UML.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binakot/Developer-Knowledge-Base/bc558103902296cc896e6680a02ad07d6409822c/design_patterns/structural/proxy_UML.gif
--------------------------------------------------------------------------------