├── .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 | [![forthebadge](https://forthebadge.com/images/badges/check-it-out.svg)](https://forthebadge.com) 16 | 17 | [![forthebadge](https://forthebadge.com/images/badges/contains-technical-debt.svg)](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 | ![UML](/design_patterns/behavioral/chain_of_responsibility_UML.gif) 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 | ![UML](/design_patterns/behavioral/interpreter_UML.gif) 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 | ![UML](/design_patterns/behavioral/mediator_UML.gif) 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 | ![UML](/design_patterns/behavioral/momento_UML.gif) 10 | 11 | Нестандартная структура паттерна Хранитель: 12 | 13 | ![UML2](/design_patterns/behavioral/momento_UML_2.png) 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 | ![UML](/design_patterns/behavioral/observer_UML.gif) 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 | ![UML](/design_patterns/behavioral/strategy_UML.gif) 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 | ![UML](/design_patterns/behavioral/template_method_UML.gif) 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 | ![UML](/design_patterns/behavioral/visitor_UML.gif) 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 | ![UML](/design_patterns/creational/builder_UML.gif) 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 | ![UML](/design_patterns/creational/prototype_UML.gif) 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 | ![UML](/design_patterns/creational/singleton_UML.png) 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 | ![UML](/design_patterns/structural/adapter_UML.gif) 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 | ![UML](/design_patterns/structural/bridge_UML.gif) 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 | ![UML](/design_patterns/structural/flyweight_UML.gif) 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 | ![UML](/design_patterns/structural/proxy_UML.gif) 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 --------------------------------------------------------------------------------