├── Program.cs
└── README.md
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CSharpDesignPatternsForHumans
4 | {
5 | class Program
6 | {
7 | static void Main(string[] args)
8 | {
9 | Console.WriteLine("This is a C# Repository");
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
4 | All the explanation for design patterns stays the same, with minor changes.
5 |
6 | ****
7 |
8 |
9 | 🎉 Ultra-simplified explanation to design patterns! 🎉
10 |
11 |
12 | A topic that can easily make anyone's mind wobble. Here I try to make them stick in to your mind (and maybe mine) by explaining them in the simplest way possible.
13 |
14 |
15 | You can find full length examples for code snippets used in this article here.
16 |
17 |
18 | ****
19 | 🚀 Introduction
20 | =================
21 |
22 | Design patterns are solutions to recurring problems; **guidelines on how to tackle certain problems**. They are not classes, packages or libraries that you can plug into your application and wait for the magic to happen. These are, rather, guidelines on how to tackle certain problems in certain situations.
23 |
24 | > Design patterns are solutions to recurring problems; guidelines on how to tackle certain problems
25 |
26 | Wikipedia describes them as
27 |
28 | > In software engineering, a software design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. It is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations.
29 |
30 | ⚠️ Be Careful
31 | -----------------
32 | - Design patterns are not a silver bullet to all your problems.
33 | - Do not try to force them; bad things are supposed to happen, if done so. Keep in mind that design patterns are solutions **to** problems, not solutions **finding** problems; so don't overthink.
34 | - If used in a correct place in a correct manner, they can prove to be a savior; or else they can result in a horrible mess of a code.
35 |
36 | > Also note that the code samples below are in C#-7, however this shouldn't stop you because the concepts are same anyways. Plus the **support for other languages is underway**.
37 |
38 | Types of Design Patterns
39 | -----------------
40 |
41 | * [Creational](#creational-design-patterns)
42 | * [Structural](#structural-design-patterns)
43 | * [Behavioral](#behavioral-design-patterns)
44 |
45 | Creational Design Patterns
46 | ==========================
47 |
48 | In plain words
49 | > Creational patterns are focused towards how to instantiate an object or group of related objects.
50 |
51 | Wikipedia says
52 | > In software engineering, creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation.
53 |
54 | * [Simple Factory](#-simple-factory)
55 | * [Factory Method](#-factory-method)
56 | * [Abstract Factory](#-abstract-factory)
57 | * [Builder](#-builder)
58 | * [Prototype](#-prototype)
59 | * [Singleton](#-singleton)
60 |
61 | 🏠 Simple Factory
62 | --------------
63 | Real world example
64 | > Consider, you are building a house and you need doors. It would be a mess if every time you need a door, you put on your carpenter clothes and start making a door in your house. Instead you get it made from a factory.
65 |
66 | In plain words
67 | > Simple factory simply generates an instance for client without exposing any instantiation logic to the client
68 |
69 | Wikipedia says
70 | > In object-oriented programming (OOP), a factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class from some method call, which is assumed to be "new".
71 |
72 | **Programmatic Example**
73 |
74 | First of all we have a door interface and the implementation
75 | ```C#
76 | public interface IDoor
77 | {
78 | int GetHeight();
79 | int GetWidth();
80 | }
81 |
82 | public class WoodenDoor : IDoor
83 | {
84 | private int Height { get; set; }
85 | private int Width { get; set; }
86 |
87 | public WoodenDoor(int height, int width)
88 | {
89 | this.Height = height;
90 | this.Width = width;
91 | }
92 |
93 | public int GetHeight()
94 | {
95 | return this.Height;
96 | }
97 | public int GetWidth()
98 | {
99 | return this.Width;
100 | }
101 | }
102 | ```
103 | Then we have our door factory that makes the door and returns it
104 | ```C#
105 | public static class DoorFactory
106 | {
107 | public static IDoor MakeDoor(int height, int width)
108 | {
109 | return new WoodenDoor(height, width);
110 | }
111 | }
112 | ```
113 | And then it can be used as
114 | ```C#
115 | var door = DoorFactory.MakeDoor(80, 30);
116 | Console.WriteLine($"Height of Door : {door.GetHeight()}");
117 | Console.WriteLine($"Width of Door : {door.GetWidth()}");
118 | ```
119 |
120 | **When to Use?**
121 |
122 | When creating an object is not just a few assignments and involves some logic, it makes sense to put it in a dedicated factory instead of repeating the same code everywhere.
123 |
124 | 🏭 Factory Method
125 | --------------
126 |
127 | Real world example
128 | > Consider the case of a hiring manager. It is impossible for one person to interview for each of the positions. Based on the job opening, she has to decide and delegate the interview steps to different people.
129 |
130 | In plain words
131 | > It provides a way to delegate the instantiation logic to child classes.
132 |
133 | Wikipedia says
134 | > In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.
135 |
136 | **Programmatic Example**
137 |
138 | Taking our hiring manager example above. First of all we have an interviewer interface and some implementations for it
139 |
140 | ```C#
141 | interface IInterviewer
142 | {
143 | void AskQuestions();
144 | }
145 |
146 | class Developer : IInterviewer
147 | {
148 | public void AskQuestions()
149 | {
150 | Console.WriteLine("Asking about design patterns!");
151 | }
152 | }
153 |
154 | class CommunityExecutive : IInterviewer
155 | {
156 | public void AskQuestions()
157 | {
158 | Console.WriteLine("Asking about community building!");
159 | }
160 | }
161 | ```
162 |
163 | Now let us create our `HiringManager`
164 |
165 | ```C#
166 | abstract class HiringManager
167 | {
168 | // Factory method
169 | abstract protected IInterviewer MakeInterviewer();
170 | public void TakeInterview()
171 | {
172 | var interviewer = this.MakeInterviewer();
173 | interviewer.AskQuestions();
174 | }
175 | }
176 |
177 | ```
178 | Now any child can extend it and provide the required interviewer
179 | ```C#
180 | class DevelopmentManager : HiringManager
181 | {
182 | protected override IInterviewer MakeInterviewer()
183 | {
184 | return new Developer();
185 | }
186 | }
187 |
188 | class MarketingManager : HiringManager
189 | {
190 | protected override IInterviewer MakeInterviewer()
191 | {
192 | return new CommunityExecutive();
193 | }
194 | }
195 |
196 | ```
197 | and then it can be used as
198 |
199 | ```C#
200 | var devManager = new DevelopmentManager();
201 | devManager.TakeInterview(); //Output : Asking about design patterns!
202 |
203 | var marketingManager = new MarketingManager();
204 | marketingManager.TakeInterview();//Output : Asking about community building!
205 |
206 | ```
207 |
208 | **When to use?**
209 |
210 | Useful when there is some generic processing in a class but the required sub-class is dynamically decided at runtime. Or putting it in other words, when the client doesn't know what exact sub-class it might need.
211 |
212 | 🔨 Abstract Factory
213 | ----------------
214 |
215 | Real world example
216 | > Extending our door example from Simple Factory. Based on your needs you might get a wooden door from a wooden door shop, iron door from an iron shop or a PVC door from the relevant shop. Plus you might need a guy with different kind of specialities to fit the door, for example a carpenter for wooden door, welder for iron door etc. As you can see there is a dependency between the doors now, wooden door needs carpenter, iron door needs a welder etc.
217 |
218 | In plain words
219 | > A factory of factories; a factory that groups the individual but related/dependent factories together without specifying their concrete classes.
220 |
221 | Wikipedia says
222 | > The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes
223 |
224 | **Programmatic Example**
225 |
226 | Translating the door example above. First of all we have our `Door` interface and some implementation for it
227 |
228 | ```C#
229 | interface IDoor {
230 |
231 | void GetDescription();
232 |
233 | }
234 | class WoodenDoor : IDoor
235 | {
236 | public void GetDescription()
237 | {
238 | Console.WriteLine("I am a wooden door");
239 | }
240 | }
241 |
242 | class IronDoor : IDoor
243 | {
244 | public void GetDescription()
245 | {
246 | Console.WriteLine("I am a iron door");
247 | }
248 | }
249 | ```
250 | Then we have some fitting experts for each door type
251 |
252 | ```C#
253 | interface IDoorFittingExpert
254 | {
255 | void GetDescription();
256 | }
257 |
258 | class Welder : IDoorFittingExpert
259 | {
260 | public void GetDescription()
261 | {
262 | Console.WriteLine("I can only fit iron doors");
263 | }
264 | }
265 |
266 | class Carpenter : IDoorFittingExpert
267 | {
268 | public void GetDescription()
269 | {
270 | Console.WriteLine("I can only fit wooden doors");
271 | }
272 | }
273 | ```
274 |
275 | Now we have our abstract factory that would let us make family of related objects i.e. wooden door factory would create a wooden door and wooden door fitting expert and iron door factory would create an iron door and iron door fitting expert
276 | ```C#
277 | interface IDoorFactory {
278 | IDoor MakeDoor();
279 | IDoorFittingExpert MakeFittingExpert();
280 | }
281 |
282 | // Wooden factory to return carpenter and wooden door
283 | class WoodenDoorFactory : IDoorFactory
284 | {
285 | public IDoor MakeDoor()
286 | {
287 | return new WoodenDoor();
288 | }
289 |
290 | public IDoorFittingExpert MakeFittingExpert()
291 | {
292 | return new Carpenter();
293 | }
294 | }
295 |
296 | // Iron door factory to get iron door and the relevant fitting expert
297 | class IronDoorFactory : IDoorFactory
298 | {
299 | public IDoor MakeDoor()
300 | {
301 | return new IronDoor();
302 | }
303 |
304 | public IDoorFittingExpert MakeFittingExpert()
305 | {
306 | return new Welder();
307 | }
308 | }
309 | ```
310 | And then it can be used as
311 | ```C#
312 | var woodenDoorFactory = new WoodenDoorFactory();
313 |
314 | var woodenDoor = woodenDoorFactory.MakeDoor();
315 | var woodenDoorFittingExpert = woodenDoorFactory.MakeFittingExpert();
316 |
317 | woodenDoor.GetDescription(); //Output : I am a wooden door
318 | woodenDoorFittingExpert.GetDescription();//Output : I can only fit woooden doors
319 |
320 | var ironDoorFactory = new IronDoorFactory();
321 |
322 | var ironDoor = ironDoorFactory.MakeDoor();
323 | var ironDoorFittingExpert = ironDoorFactory.MakeFittingExpert();
324 |
325 | ironDoor.GetDescription();//Output : I am a iron door
326 | ironDoorFittingExpert.GetDescription();//Output : I can only fit iron doors
327 | ```
328 |
329 | As you can see the wooden door factory has encapsulated the `carpenter` and the `wooden door` also iron door factory has encapsulated the `iron door` and `welder`. And thus it had helped us make sure that for each of the created door, we do not get a wrong fitting expert.
330 |
331 | **When to use?**
332 |
333 | When there are interrelated dependencies with not-that-simple creation logic involved
334 |
335 | 👷 Builder
336 | --------------------------------------------
337 | Real world example
338 | > Imagine you are at Hardee's and you order a specific deal, lets say, "Big Hardee" and they hand it over to you without *any questions*; this is the example of simple factory. But there are cases when the creation logic might involve more steps. For example you want a customized Subway deal, you have several options in how your burger is made e.g what bread do you want? what types of sauces would you like? What cheese would you want? etc. In such cases builder pattern comes to the rescue.
339 |
340 | In plain words
341 | > Allows you to create different flavors of an object while avoiding constructor pollution. Useful when there could be several flavors of an object. Or when there are a lot of steps involved in creation of an object.
342 |
343 | Wikipedia says
344 | > The builder pattern is an object creation software design pattern with the intentions of finding a solution to the telescoping constructor anti-pattern.
345 |
346 | Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point or the other we have all seen a constructor like below:
347 |
348 | ```C#
349 | public Burger(int size, bool cheese, bool pepperoni, bool lettuce, bool tomato)
350 | {
351 | }
352 | ```
353 |
354 | As you can see; the number of constructor parameters can quickly get out of hand and it might become difficult to understand the arrangement of parameters. Plus this parameter list could keep on growing if you would want to add more options in future. This is called telescoping constructor anti-pattern.
355 |
356 | **Programmatic Example**
357 |
358 | The sane alternative is to use the builder pattern. First of all we have our burger that we want to make
359 |
360 | ```C#
361 | class Burger
362 | {
363 | private int mSize;
364 | private bool mCheese;
365 | private bool mPepperoni;
366 | private bool mLettuce;
367 | private bool mTomato;
368 |
369 | public Burger(BurgerBuilder builder)
370 | {
371 | this.mSize = builder.Size;
372 | this.mCheese = builder.Cheese;
373 | this.mPepperoni = builder.Pepperoni;
374 | this.mLettuce = builder.Lettuce;
375 | this.mTomato = builder.Tomato;
376 | }
377 |
378 | public string GetDescription()
379 | {
380 | var sb = new StringBuilder();
381 | sb.Append($"This is {this.mSize} inch Burger. ");
382 | return sb.ToString();
383 | }
384 | }
385 | ```
386 |
387 | And then we have the builder
388 |
389 | ```C#
390 | class BurgerBuilder {
391 | public int Size;
392 | public bool Cheese;
393 | public bool Pepperoni;
394 | public bool Lettuce;
395 | public bool Tomato;
396 |
397 | public BurgerBuilder(int size)
398 | {
399 | this.Size = size;
400 | }
401 |
402 | public BurgerBuilder AddCheese()
403 | {
404 | this.Cheese = true;
405 | return this;
406 | }
407 |
408 | public BurgerBuilder AddPepperoni()
409 | {
410 | this.Pepperoni = true;
411 | return this;
412 | }
413 |
414 | public BurgerBuilder AddLettuce()
415 | {
416 | this.Lettuce = true;
417 | return this;
418 | }
419 |
420 | public BurgerBuilder AddTomato()
421 | {
422 | this.Tomato = true;
423 | return this;
424 | }
425 |
426 | public Burger Build()
427 | {
428 | return new Burger(this);
429 | }
430 | }
431 | ```
432 | And then it can be used as:
433 |
434 | ```C#
435 | var burger = new BurgerBuilder(4).AddCheese()
436 | .AddPepperoni()
437 | .AddLettuce()
438 | .AddTomato()
439 | .Build();
440 | Console.WriteLine(burger.GetDescription());
441 | ```
442 |
443 | **When to use?**
444 |
445 | When there could be several flavors of an object and to avoid the constructor telescoping. The key difference from the factory pattern is that; factory pattern is to be used when the creation is a one step process while builder pattern is to be used when the creation is a multi step process.
446 |
447 | 🐑 Prototype
448 | ------------
449 | Real world example
450 | > Remember dolly? The sheep that was cloned! Lets not get into the details but the key point here is that it is all about cloning
451 |
452 | In plain words
453 | > Create object based on an existing object through cloning.
454 |
455 | Wikipedia says
456 | > The prototype pattern is a creational design pattern in software development. It is used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects.
457 |
458 | In short, it allows you to create a copy of an existing object and modify it to your needs, instead of going through the trouble of creating an object from scratch and setting it up.
459 |
460 | **Programmatic Example**
461 |
462 | In C#, it can be easily done using `MemberwiseClone()`
463 |
464 | ```C#
465 | class Sheep
466 | {
467 | public string Name { get; set; }
468 |
469 | public string Category { get; set; }
470 |
471 | public Sheep(string name, string category)
472 | {
473 | Name = name;
474 | Category = category;
475 | }
476 |
477 | public Sheep Clone()
478 | {
479 | return MemberwiseClone() as Sheep;
480 | }
481 | }
482 | ```
483 | Then it can be cloned like below
484 | ```C#
485 | var original = new Sheep("Jolly", "Mountain Sheep");
486 | Console.WriteLine(original.Name); // Jolly
487 | Console.WriteLine(original.Category); // Mountain Sheep
488 |
489 | var cloned = original.Clone();
490 | cloned.Name = "Dolly";
491 | Console.WriteLine(cloned.Name); // Dolly
492 | Console.WriteLine(cloned.Category); // Mountain Sheep
493 | Console.WriteLine(original.Name); // Jolly
494 | ```
495 |
496 | **When to use?**
497 |
498 | When an object is required that is similar to existing object or when the creation would be expensive as compared to cloning.
499 |
500 | 💍 Singleton
501 | ------------
502 | Real world example
503 | > There can only be one president of a country at a time. The same president has to be brought to action, whenever duty calls. President here is singleton.
504 |
505 | In plain words
506 | > Ensures that only one object of a particular class is ever created.
507 |
508 | Wikipedia says
509 | > In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
510 |
511 | Singleton pattern is actually considered an anti-pattern and overuse of it should be avoided. It is not necessarily bad and could have some valid use-cases but should be used with caution because it introduces a global state in your application and change to it in one place could affect in the other areas and it could become pretty difficult to debug. The other bad thing about them is it makes your code tightly coupled plus mocking the singleton could be difficult.
512 |
513 | **Programmatic Example**
514 |
515 | To create a singleton, make the constructor private, disable cloning, disable extension and create a static variable to house the instance
516 | ```C#
517 | public class President
518 | {
519 | static President instance;
520 | // Private constructor
521 | private President()
522 | {
523 | //Hiding the Constructor
524 | }
525 |
526 | // Public constructor
527 | public static President GetInstance()
528 | {
529 | if (instance == null) {
530 | instance = new President();
531 | }
532 | return instance;
533 | }
534 | }
535 | ```
536 | Then in order to use
537 | ```C#
538 | President a = President.GetInstance();
539 | President b = President.GetInstance();
540 |
541 | Console.WriteLine(a == b); //Output : true
542 | ```
543 |
544 | Structural Design Patterns
545 | ==========================
546 | In plain words
547 | > Structural patterns are mostly concerned with object composition or in other words how the entities can use each other. Or yet another explanation would be, they help in answering "How to build a software component?"
548 |
549 | Wikipedia says
550 | > In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities.
551 |
552 | * [Adapter](#-adapter)
553 | * [Bridge](#-bridge)
554 | * [Composite](#-composite)
555 | * [Decorator](#-decorator)
556 | * [Facade](#-facade)
557 | * [Flyweight](#-flyweight)
558 | * [Proxy](#-proxy)
559 |
560 | 🔌 Adapter
561 | -------
562 | Real world example
563 | > Consider that you have some pictures in your memory card and you need to transfer them to your computer. In order to transfer them you need some kind of adapter that is compatible with your computer ports so that you can attach memory card to your computer. In this case card reader is an adapter.
564 | > Another example would be the famous power adapter; a three legged plug can't be connected to a two pronged outlet, it needs to use a power adapter that makes it compatible with the two pronged outlet.
565 | > Yet another example would be a translator translating words spoken by one person to another
566 |
567 | In plain words
568 | > Adapter pattern lets you wrap an otherwise incompatible object in an adapter to make it compatible with another class.
569 |
570 | Wikipedia says
571 | > In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code.
572 |
573 | **Programmatic Example**
574 |
575 | Consider a game where there is a hunter and he hunts lions.
576 |
577 | First we have an interface `Lion` that all types of lions have to implement
578 |
579 | ```C#
580 | interface ILion
581 | {
582 | void Roar();
583 | }
584 |
585 | class AfricanLion : ILion
586 | {
587 | public void Roar()
588 | {
589 |
590 | }
591 | }
592 |
593 | class AsiaLion : ILion
594 | {
595 | public void Roar()
596 | {
597 |
598 | }
599 | }
600 | ```
601 | And hunter expects any implementation of `Lion` interface to hunt.
602 | ```C#
603 | class Hunter
604 | {
605 | public void Hunt(ILion lion)
606 | {
607 |
608 | }
609 | }
610 | ```
611 |
612 | Now let's say we have to add a `WildDog` in our game so that hunter can hunt that also. But we can't do that directly because dog has a different interface. To make it compatible for our hunter, we will have to create an adapter that is compatible
613 |
614 | ```C#
615 | // This needs to be added to the game
616 | class WildDog
617 | {
618 | public void bark()
619 | {
620 | }
621 | }
622 |
623 | // Adapter around wild dog to make it compatible with our game
624 | class WildDogAdapter : ILion
625 | {
626 | private WildDog mDog;
627 | public WildDogAdapter(WildDog dog)
628 | {
629 | this.mDog = dog;
630 | }
631 | public void Roar()
632 | {
633 | mDog.bark();
634 | }
635 | }
636 | ```
637 | And now the `WildDog` can be used in our game using `WildDogAdapter`.
638 |
639 | ```C#
640 | var wildDog = new WildDog();
641 | var wildDogAdapter = new WildDogAdapter(wildDog);
642 |
643 | var hunter = new Hunter();
644 | hunter.Hunt(wildDogAdapter);
645 | ```
646 |
647 | 🚡 Bridge
648 | ------
649 | Real world example
650 | > Consider you have a website with different pages and you are supposed to allow the user to change the theme. What would you do? Create multiple copies of each of the pages for each of the themes or would you just create separate theme and load them based on the user's preferences? Bridge pattern allows you to do the second i.e.
651 |
652 | 
653 |
654 | In Plain Words
655 | > Bridge pattern is about preferring composition over inheritance. Implementation details are pushed from a hierarchy to another object with a separate hierarchy.
656 |
657 | Wikipedia says
658 | > The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently"
659 |
660 | **Programmatic Example**
661 |
662 | Translating our WebPage example from above. Here we have the `WebPage` hierarchy
663 |
664 | ```C#
665 | interface IWebPage
666 | {
667 | string GetContent();
668 | }
669 |
670 | class About : IWebPage
671 | {
672 | protected ITheme theme;
673 |
674 | public About(ITheme theme)
675 | {
676 | this.theme = theme;
677 | }
678 |
679 | public string GetContent()
680 | {
681 | return $"About page in {theme.GetColor()}";
682 | }
683 | }
684 |
685 | class Careers : IWebPage
686 | {
687 | protected ITheme theme;
688 |
689 | public Careers(ITheme theme)
690 | {
691 | this.theme = theme;
692 | }
693 |
694 | public string GetContent()
695 | {
696 | return $"Careers page in {theme.GetColor()}";
697 | }
698 | }
699 | ```
700 | And the separate theme hierarchy
701 | ```C#
702 |
703 | interface ITheme
704 | {
705 | string GetColor();
706 | }
707 |
708 | class DarkTheme : ITheme
709 | {
710 | public string GetColor()
711 | {
712 | return "Dark Black";
713 | }
714 | }
715 |
716 | class LightTheme : ITheme
717 | {
718 | public string GetColor()
719 | {
720 | return "Off White";
721 | }
722 | }
723 |
724 | class AquaTheme : ITheme
725 | {
726 | public string GetColor()
727 | {
728 | return "Light blue";
729 | }
730 | }
731 | ```
732 | And both the hierarchies
733 | ```C#
734 | var darkTheme = new DarkTheme();
735 | var lightTheme = new LightTheme();
736 |
737 | var about= new About(darkTheme);
738 | var careers = new Careers(lightTheme);
739 |
740 | Console.WriteLine(about.GetContent()); //Output: About page in Dark Black
741 | Console.WriteLine(careers.GetContent()); //Output: Careers page in Off White
742 | ```
743 |
744 | 🌿 Composite
745 | -----------------
746 |
747 | Real world example
748 | > Every organization is composed of employees. Each of the employees has the same features i.e. has a salary, has some responsibilities, may or may not report to someone, may or may not have some subordinates etc.
749 |
750 | In plain words
751 | > Composite pattern lets clients treat the individual objects in a uniform manner.
752 |
753 | Wikipedia says
754 | > In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.
755 |
756 | **Programmatic Example**
757 |
758 | Taking our employees example from above. Here we have different employee types
759 |
760 | ```C#
761 | interface IEmployee
762 | {
763 | float GetSalary();
764 | string GetRole();
765 | string GetName();
766 | }
767 |
768 |
769 | class Developer : IEmployee
770 | {
771 | private string mName;
772 | private float mSalary;
773 |
774 | public Developer(string name, float salary)
775 | {
776 | this.mName = name;
777 | this.mSalary = salary;
778 | }
779 |
780 | public float GetSalary()
781 | {
782 | return this.mSalary;
783 | }
784 |
785 | public string GetRole()
786 | {
787 | return "Developer";
788 | }
789 |
790 | public string GetName()
791 | {
792 | return this.mName;
793 | }
794 | }
795 |
796 | class Designer : IEmployee
797 | {
798 | private string mName;
799 | private float mSalary;
800 |
801 | public Designer(string name, float salary)
802 | {
803 | this.mName = name;
804 | this.mSalary = salary;
805 | }
806 |
807 | public float GetSalary()
808 | {
809 | return this.mSalary;
810 | }
811 |
812 | public string GetRole()
813 | {
814 | return "Designer";
815 | }
816 |
817 | public string GetName()
818 | {
819 | return this.mName;
820 | }
821 | }
822 | ```
823 |
824 | Then we have an organization which consists of several different types of employees
825 |
826 | ```C#
827 | class Organization
828 | {
829 | protected List employees;
830 |
831 | public Organization()
832 | {
833 | employees = new List();
834 | }
835 |
836 | public void AddEmployee(IEmployee employee)
837 | {
838 | employees.Add(employee);
839 | }
840 |
841 | public float GetNetSalaries()
842 | {
843 | float netSalary = 0;
844 |
845 | foreach (var e in employees) {
846 | netSalary += e.GetSalary();
847 | }
848 | return netSalary;
849 | }
850 | }
851 | ```
852 |
853 | And then it can be used as
854 |
855 | ```C#
856 | //Arrange Employees, Organization and add employees
857 | var developer = new Developer("John", 5000);
858 | var designer = new Designer("Arya", 5000);
859 |
860 | var organization = new Organization();
861 | organization.AddEmployee(developer);
862 | organization.AddEmployee(designer);
863 |
864 | Console.WriteLine($"Net Salary of Employees in Organization is {organization.GetNetSalaries():c}");
865 | //Ouptut: Net Salary of Employees in Organization is $10000.00
866 | ```
867 |
868 | ☕ Decorator
869 | -------------
870 |
871 | Real world example
872 |
873 | > Imagine you run a car service shop offering multiple services. Now how do you calculate the bill to be charged? You pick one service and dynamically keep adding to it the prices for the provided services till you get the final cost. Here each type of service is a decorator.
874 |
875 | In plain words
876 | > Decorator pattern lets you dynamically change the behavior of an object at run time by wrapping them in an object of a decorator class.
877 |
878 | Wikipedia says
879 | > In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.
880 |
881 | **Programmatic Example**
882 |
883 | Lets take coffee for example. First of all we have a simple coffee implementing the coffee interface
884 |
885 | ```C#
886 | interface ICoffee
887 | {
888 | int GetCost();
889 | string GetDescription();
890 | }
891 |
892 | class SimpleCoffee : ICoffee
893 | {
894 | public int GetCost()
895 | {
896 | return 5;
897 | }
898 |
899 | public string GetDescription()
900 | {
901 | return "Simple Coffee";
902 | }
903 | }
904 | ```
905 | We want to make the code extensible to allow options to modify it if required. Lets make some add-ons (decorators)
906 | ```C#
907 | class MilkCoffee : ICoffee
908 | {
909 | private readonly ICoffee mCoffee;
910 |
911 | public MilkCoffee(ICoffee coffee)
912 | {
913 | mCoffee = coffee ?? throw new ArgumentNullException("coffee", "coffee should not be null");
914 | }
915 | public int GetCost()
916 | {
917 | return mCoffee.GetCost() + 1;
918 | }
919 |
920 | public string GetDescription()
921 | {
922 | return String.Concat(mCoffee.GetDescription(), ", milk");
923 | }
924 | }
925 |
926 | class WhipCoffee : ICoffee
927 | {
928 | private readonly ICoffee mCoffee;
929 |
930 | public WhipCoffee(ICoffee coffee)
931 | {
932 | mCoffee = coffee ?? throw new ArgumentNullException("coffee", "coffee should not be null");
933 | }
934 | public int GetCost()
935 | {
936 | return mCoffee.GetCost() + 1;
937 | }
938 |
939 | public string GetDescription()
940 | {
941 | return String.Concat(mCoffee.GetDescription(), ", whip");
942 | }
943 | }
944 |
945 | class VanillaCoffee : ICoffee
946 | {
947 | private readonly ICoffee mCoffee;
948 |
949 | public VanillaCoffee(ICoffee coffee)
950 | {
951 | mCoffee = coffee ?? throw new ArgumentNullException("coffee", "coffee should not be null");
952 | }
953 | public int GetCost()
954 | {
955 | return mCoffee.GetCost() + 1;
956 | }
957 |
958 | public string GetDescription()
959 | {
960 | return String.Concat(mCoffee.GetDescription(), ", vanilla");
961 | }
962 | }
963 |
964 | ```
965 |
966 | Lets make a coffee now
967 |
968 | ```C#
969 | var myCoffee = new SimpleCoffee();
970 | Console.WriteLine($"{myCoffee.GetCost():c}"); // $ 5.00
971 | Console.WriteLine(myCoffee.GetDescription()); // Simple Coffee
972 |
973 | var milkCoffee = new MilkCoffee(myCoffee);
974 | Console.WriteLine($"{milkCoffee.GetCost():c}"); // $ 6.00
975 | Console.WriteLine(milkCoffee.GetDescription()); // Simple Coffee, milk
976 |
977 | var whipCoffee = new WhipCoffee(milkCoffee);
978 | Console.WriteLine($"{whipCoffee.GetCost():c}"); // $ 7.00
979 | Console.WriteLine(whipCoffee.GetDescription()); // Simple Coffee, milk, whip
980 |
981 | var vanillaCoffee = new VanillaCoffee(whipCoffee);
982 | Console.WriteLine($"{vanillaCoffee.GetCost():c}"); // $ 8.00
983 | Console.WriteLine(vanillaCoffee.GetDescription()); // Simple Coffee, milk, whip, vanilla
984 | ```
985 |
986 | 📦 Facade
987 | ----------------
988 |
989 | Real world example
990 | > How do you turn on the computer? "Hit the power button" you say! That is what you believe because you are using a simple interface that computer provides on the outside, internally it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a facade.
991 |
992 | In plain words
993 | > Facade pattern provides a simplified interface to a complex subsystem.
994 |
995 | Wikipedia says
996 | > A facade is an object that provides a simplified interface to a larger body of code, such as a class library.
997 |
998 | **Programmatic Example**
999 |
1000 | Taking our computer example from above. Here we have the computer class
1001 |
1002 | ```C#
1003 | class Computer
1004 | {
1005 | public void GetElectricShock()
1006 | {
1007 | Console.Write("Ouch!");
1008 | }
1009 |
1010 | public void MakeSound()
1011 | {
1012 | Console.Write("Beep beep!");
1013 | }
1014 |
1015 | public void ShowLoadingScreen()
1016 | {
1017 | Console.Write("Loading..");
1018 | }
1019 |
1020 | public void Bam()
1021 | {
1022 | Console.Write("Ready to be used!");
1023 | }
1024 |
1025 | public void CloseEverything()
1026 | {
1027 | Console.Write("Bup bup bup buzzzz!");
1028 | }
1029 |
1030 | public void Sooth()
1031 | {
1032 | Console.Write("Zzzzz");
1033 | }
1034 |
1035 | public void PullCurrent()
1036 | {
1037 | Console.Write("Haaah!");
1038 | }
1039 | }
1040 | ```
1041 | Here we have the facade
1042 | ```C#
1043 | class ComputerFacade
1044 | {
1045 | private readonly Computer mComputer;
1046 |
1047 | public ComputerFacade(Computer computer)
1048 | {
1049 | this.mComputer = computer ?? throw new ArgumentNullException("computer", "computer cannot be null");
1050 | }
1051 |
1052 | public void TurnOn()
1053 | {
1054 | mComputer.GetElectricShock();
1055 | mComputer.MakeSound();
1056 | mComputer.ShowLoadingScreen();
1057 | mComputer.Bam();
1058 | }
1059 |
1060 | public void TurnOff()
1061 | {
1062 | mComputer.CloseEverything();
1063 | mComputer.PullCurrent();
1064 | mComputer.Sooth();
1065 | }
1066 | }
1067 | ```
1068 | Now to use the facade
1069 | ```C#
1070 | var computer = new ComputerFacade(new Computer());
1071 | computer.TurnOn(); // Ouch! Beep beep! Loading.. Ready to be used!
1072 | Console.WriteLine();
1073 | computer.TurnOff(); // Bup bup buzzz! Haah! Zzzzz
1074 | Console.ReadLine();
1075 | ```
1076 |
1077 | 🍃 Flyweight
1078 | ---------
1079 |
1080 | Real world example
1081 | > Did you ever have fresh tea from some stall? They often make more than one cup that you demanded and save the rest for any other customer so to save the resources e.g. gas etc. Flyweight pattern is all about that i.e. sharing.
1082 |
1083 | In plain words
1084 | > It is used to minimize memory usage or computational expenses by sharing as much as possible with similar objects.
1085 |
1086 | Wikipedia says
1087 | > In computer programming, flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory.
1088 |
1089 | **Programmatic example**
1090 |
1091 | Translating our tea example from above. First of all we have tea types and tea maker
1092 |
1093 | ```C#
1094 | // Anything that will be cached is flyweight.
1095 | // Types of tea here will be flyweights.
1096 | class KarakTea
1097 | {
1098 | }
1099 |
1100 | // Acts as a factory and saves the tea
1101 | class TeaMaker
1102 | {
1103 | private Dictionary mAvailableTea = new Dictionary();
1104 |
1105 | public KarakTea Make(string preference)
1106 | {
1107 | if (!mAvailableTea.ContainsKey(preference))
1108 | {
1109 | mAvailableTea[preference] = new KarakTea();
1110 | }
1111 |
1112 | return mAvailableTea[preference];
1113 | }
1114 | }
1115 | ```
1116 |
1117 | Then we have the `TeaShop` which takes orders and serves them
1118 |
1119 | ```C#
1120 | class TeaShop
1121 | {
1122 | private Dictionary mOrders = new Dictionary();
1123 | private readonly TeaMaker mTeaMaker;
1124 |
1125 | public TeaShop(TeaMaker teaMaker)
1126 | {
1127 | mTeaMaker = teaMaker ?? throw new ArgumentNullException("teaMaker", "teaMaker cannot be null");
1128 | }
1129 |
1130 | public void TakeOrder(string teaType, int table)
1131 | {
1132 | mOrders[table] = mTeaMaker.Make(teaType);
1133 | }
1134 |
1135 | public void Serve()
1136 | {
1137 | foreach(var table in mOrders.Keys){
1138 | Console.WriteLine($"Serving Tea to table # {table}");
1139 | }
1140 | }
1141 | }
1142 | ```
1143 | And it can be used as below
1144 |
1145 | ```C#
1146 | var teaMaker = new TeaMaker();
1147 | var teaShop = new TeaShop(teaMaker);
1148 |
1149 | teaShop.TakeOrder("less sugar", 1);
1150 | teaShop.TakeOrder("more milk", 2);
1151 | teaShop.TakeOrder("without sugar", 5);
1152 |
1153 | teaShop.Serve();
1154 | // Serving tea to table# 1
1155 | // Serving tea to table# 2
1156 | // Serving tea to table# 5
1157 | ```
1158 |
1159 | 🎱 Proxy
1160 | -------------------
1161 | Real world example
1162 | > Have you ever used an access card to go through a door? There are multiple options to open that door i.e. it can be opened either using access card or by pressing a button that bypasses the security. The door's main functionality is to open but there is a proxy added on top of it to add some functionality. Let me better explain it using the code example below.
1163 |
1164 | In plain words
1165 | > Using the proxy pattern, a class represents the functionality of another class.
1166 |
1167 | Wikipedia says
1168 | > A proxy, in its most general form, is a class functioning as an interface to something else. A proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked.
1169 |
1170 | **Programmatic Example**
1171 |
1172 | Taking our security door example from above. Firstly we have the door interface and an implementation of door
1173 |
1174 | ```C#
1175 | interface IDoor
1176 | {
1177 | void Open();
1178 | void Close();
1179 | }
1180 |
1181 | class LabDoor : IDoor
1182 | {
1183 | public void Close()
1184 | {
1185 | Console.WriteLine("Closing lab door");
1186 | }
1187 |
1188 | public void Open()
1189 | {
1190 | Console.WriteLine("Opening lab door");
1191 | }
1192 | }
1193 | ```
1194 | Then we have a proxy to secure any doors that we want
1195 | ```C#
1196 | class SecuredDoor : IDoor
1197 | {
1198 | private IDoor mDoor;
1199 |
1200 | public SecuredDoor(IDoor door)
1201 | {
1202 | mDoor = door ?? throw new ArgumentNullException("door", "door can not be null");
1203 | }
1204 |
1205 | public void Open(string password)
1206 | {
1207 | if (Authenticate(password))
1208 | {
1209 | mDoor.Open();
1210 | }
1211 | else
1212 | {
1213 | Console.WriteLine("Big no! It ain't possible.");
1214 | }
1215 | }
1216 |
1217 | private bool Authenticate(string password)
1218 | {
1219 | return password == "$ecr@t";
1220 | }
1221 |
1222 | public void Close()
1223 | {
1224 | mDoor.Close();
1225 | }
1226 | }
1227 | ```
1228 | And here is how it can be used
1229 | ```C#
1230 | var door = new SecuredDoor(new LabDoor());
1231 | door.Open("invalid"); // Big no! It ain't possible.
1232 |
1233 | door.Open("$ecr@t"); // Opening lab door
1234 | door.Close(); // Closing lab door
1235 | ```
1236 | Yet another example would be some sort of data-mapper implementation. For example, I recently made an ODM (Object Data Mapper) for MongoDB using this pattern where I wrote a proxy around mongo classes while utilizing the magic method `__call()`. All the method calls were proxied to the original mongo class and result retrieved was returned as it is but in case of `find` or `findOne` data was mapped to the required class objects and the object was returned instead of `Cursor`.
1237 |
1238 | Behavioral Design Patterns
1239 | ==========================
1240 |
1241 | In plain words
1242 | > It is concerned with assignment of responsibilities between the objects. What makes them different from structural patterns is they don't just specify the structure but also outline the patterns for message passing/communication between them. Or in other words, they assist in answering "How to run a behavior in software component?"
1243 |
1244 | Wikipedia says
1245 | > In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.
1246 |
1247 | * [Chain of Responsibility](#-chain-of-responsibility)
1248 | * [Command](#-command)
1249 | * [Iterator](#-iterator)
1250 | * [Mediator](#-mediator)
1251 | * [Memento](#-memento)
1252 | * [Observer](#-observer)
1253 | * [Visitor](#-visitor)
1254 | * [Strategy](#-strategy)
1255 | * [State](#-state)
1256 | * [Template Method](#-template-method)
1257 |
1258 | 🔗 Chain of Responsibility
1259 | -----------------------
1260 |
1261 | Real world example
1262 | > For example, you have three payment methods (`A`, `B` and `C`) setup in your account; each having a different amount in it. `A` has 100 USD, `B` has 300 USD and `C` having 1000 USD and the preference for payments is chosen as `A` then `B` then `C`. You try to purchase something that is worth 210 USD. Using Chain of Responsibility, first of all account `A` will be checked if it can make the purchase, if yes purchase will be made and the chain will be broken. If not, request will move forward to account `B` checking for amount if yes chain will be broken otherwise the request will keep forwarding till it finds the suitable handler. Here `A`, `B` and `C` are links of the chain and the whole phenomenon is Chain of Responsibility.
1263 |
1264 | In plain words
1265 | > It helps building a chain of objects. Request enters from one end and keeps going from object to object till it finds the suitable handler.
1266 |
1267 | Wikipedia says
1268 | > In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.
1269 |
1270 | **Programmatic Example**
1271 |
1272 | Translating our account example above. First of all we have a base account having the logic for chaining the accounts together and some accounts
1273 |
1274 | ```C#
1275 | abstract class Account
1276 | {
1277 | private Account mSuccessor;
1278 | protected decimal mBalance;
1279 |
1280 | public void SetNext(Account account)
1281 | {
1282 | mSuccessor = account;
1283 | }
1284 |
1285 | public void Pay(decimal amountTopay)
1286 | {
1287 | if (CanPay(amountTopay))
1288 | {
1289 | Console.WriteLine($"Paid {amountTopay:c} using {this.GetType().Name}.");
1290 | }
1291 | else if (this.mSuccessor != null)
1292 | {
1293 | Console.WriteLine($"Cannot pay using {this.GetType().Name}. Proceeding..");
1294 | mSuccessor.Pay(amountTopay);
1295 | }
1296 | else
1297 | {
1298 | throw new Exception("None of the accounts have enough balance");
1299 | }
1300 | }
1301 | private bool CanPay(decimal amount)
1302 | {
1303 | return mBalance >= amount;
1304 | }
1305 | }
1306 |
1307 | class Bank : Account
1308 | {
1309 | public Bank(decimal balance)
1310 | {
1311 | this.mBalance = balance;
1312 | }
1313 | }
1314 |
1315 | class Paypal : Account
1316 | {
1317 | public Paypal(decimal balance)
1318 | {
1319 | this.mBalance = balance;
1320 | }
1321 | }
1322 |
1323 | class Bitcoin : Account
1324 | {
1325 | public Bitcoin(decimal balance)
1326 | {
1327 | this.mBalance = balance;
1328 | }
1329 | }
1330 | ```
1331 |
1332 | Now let's prepare the chain using the links defined above (i.e. Bank, Paypal, Bitcoin)
1333 |
1334 | ```C#
1335 | // Let's prepare a chain like below
1336 | // $bank->$paypal->$bitcoin
1337 | //
1338 | // First priority bank
1339 | // If bank can't pay then paypal
1340 | // If paypal can't pay then bit coin
1341 | var bank = new Bank(100); // Bank with balance 100
1342 | var paypal = new Paypal(200); // Paypal with balance 200
1343 | var bitcoin = new Bitcoin(300); // Bitcoin with balance 300
1344 |
1345 | bank.SetNext(paypal);
1346 | paypal.SetNext(bitcoin);
1347 |
1348 | // Let's try to pay using the first priority i.e. bank
1349 | bank.Pay(259);
1350 | // Output will be
1351 | // ==============
1352 | // Cannot pay using bank. Proceeding ..
1353 | // Cannot pay using paypal. Proceeding ..:
1354 | // Paid 259 using Bitcoin!
1355 | ```
1356 |
1357 | 👮 Command
1358 | -------
1359 |
1360 | Real world example
1361 | > A generic example would be you ordering food at a restaurant. You (i.e. `Client`) ask the waiter (i.e. `Invoker`) to bring some food (i.e. `Command`) and waiter simply forwards the request to Chef (i.e. `Receiver`) who has the knowledge of what and how to cook.
1362 | > Another example would be you (i.e. `Client`) switching on (i.e. `Command`) the television (i.e. `Receiver`) using a remote control (`Invoker`).
1363 |
1364 | In plain words
1365 | > Allows you to encapsulate actions in objects. The key idea behind this pattern is to provide the means to decouple client from receiver.
1366 |
1367 | Wikipedia says
1368 | > In object-oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method and values for the method parameters.
1369 |
1370 | **Programmatic Example**
1371 |
1372 | First of all we have the receiver that has the implementation of every action that could be performed
1373 | ```C#
1374 | // Receiver
1375 | class Bulb
1376 | {
1377 | public void TurnOn()
1378 | {
1379 | Console.WriteLine("Bulb has been lit");
1380 | }
1381 |
1382 | public void TurnOff()
1383 | {
1384 | Console.WriteLine("Darkness!");
1385 | }
1386 | }
1387 | ```
1388 | then we have an interface that each of the commands are going to implement and then we have a set of commands
1389 | ```C#
1390 | interface ICommand
1391 | {
1392 | void Execute();
1393 | void Undo();
1394 | void Redo();
1395 | }
1396 |
1397 | // Command
1398 | class TurnOn : ICommand
1399 | {
1400 | private Bulb mBulb;
1401 |
1402 | public TurnOn(Bulb bulb)
1403 | {
1404 | mBulb = bulb ?? throw new ArgumentNullException("Bulb", "Bulb cannot be null");
1405 | }
1406 |
1407 | public void Execute()
1408 | {
1409 | mBulb.TurnOn();
1410 | }
1411 |
1412 | public void Undo()
1413 | {
1414 | mBulb.TurnOff();
1415 | }
1416 |
1417 | public void Redo()
1418 | {
1419 | Execute();
1420 | }
1421 | }
1422 |
1423 | class TurnOff : ICommand
1424 | {
1425 | private Bulb mBulb;
1426 |
1427 | public TurnOff(Bulb bulb)
1428 | {
1429 | mBulb = bulb ?? throw new ArgumentNullException("Bulb", "Bulb cannot be null");
1430 | }
1431 |
1432 | public void Execute()
1433 | {
1434 | mBulb.TurnOff();
1435 | }
1436 |
1437 | public void Undo()
1438 | {
1439 | mBulb.TurnOn();
1440 | }
1441 |
1442 | public void Redo()
1443 | {
1444 | Execute();
1445 | }
1446 | }
1447 | ```
1448 | Then we have an `Invoker` with whom the client will interact to process any commands
1449 | ```C#
1450 | // Invoker
1451 | class RemoteControl
1452 | {
1453 | public void Submit(ICommand command)
1454 | {
1455 | command.Execute();
1456 | }
1457 | }
1458 | ```
1459 | Finally let's see how we can use it in our client
1460 | ```C#
1461 | var bulb = new Bulb();
1462 |
1463 | var turnOn = new TurnOn(bulb);
1464 | var turnOff = new TurnOff(bulb);
1465 |
1466 | var remote = new RemoteControl();
1467 | remote.Submit(turnOn); // Bulb has been lit!
1468 | remote.Submit(turnOff); // Darkness!
1469 |
1470 | Console.ReadLine();
1471 | ```
1472 |
1473 | Command pattern can also be used to implement a transaction based system. Where you keep maintaining the history of commands as soon as you execute them. If the final command is successfully executed, all good otherwise just iterate through the history and keep executing the `undo` on all the executed commands.
1474 |
1475 | ➿ Iterator
1476 | --------
1477 |
1478 | Real world example
1479 | > An old radio set will be a good example of iterator, where user could start at some channel and then use next or previous buttons to go through the respective channels. Or take an example of MP3 player or a TV set where you could press the next and previous buttons to go through the consecutive channels or in other words they all provide an interface to iterate through the respective channels, songs or radio stations.
1480 |
1481 | In plain words
1482 | > It presents a way to access the elements of an object without exposing the underlying presentation.
1483 |
1484 | Wikipedia says
1485 | > In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.
1486 |
1487 | **Programmatic example**
1488 |
1489 | In C# it can be done by implementing IEnumerable. Translating our radio statiIons example from above. First of all we have `RadioStation`
1490 |
1491 | ```C#
1492 | class RadioStation
1493 | {
1494 | private float mFrequency;
1495 |
1496 | public RadioStation(float frequency)
1497 | {
1498 | mFrequency = frequency;
1499 | }
1500 |
1501 | public float GetFrequecy()
1502 | {
1503 | return mFrequency;
1504 | }
1505 |
1506 | }
1507 |
1508 | ```
1509 | Then we have our iterator
1510 |
1511 | ```C#
1512 | class StationList : IEnumerable
1513 | {
1514 | List mStations = new List();
1515 |
1516 | public RadioStation this[int index]
1517 | {
1518 | get { return mStations[index]; }
1519 | set { mStations.Insert(index, value); }
1520 | }
1521 |
1522 | public void Add(RadioStation station)
1523 | {
1524 | mStations.Add(station);
1525 | }
1526 |
1527 | public void Remove(RadioStation station)
1528 | {
1529 | mStations.Remove(station);
1530 | }
1531 |
1532 | public IEnumerator GetEnumerator()
1533 | {
1534 | return this.GetEnumerator();
1535 | }
1536 |
1537 | IEnumerator IEnumerable.GetEnumerator()
1538 | {
1539 | //Use can switch to this internal collection if you do not want to transform
1540 | //return mStations.GetEnumerator();
1541 |
1542 | //use this if you want to transform the object before rendering
1543 | foreach (var x in mStations)
1544 | {
1545 | yield return x;
1546 | }
1547 | }
1548 | }
1549 | ```
1550 | And then it can be used as
1551 | ```C#
1552 | var stations = new StationList();
1553 | var station1 = new RadioStation(89);
1554 | stations.Add(station1);
1555 |
1556 | var station2 = new RadioStation(101);
1557 | stations.Add(station2);
1558 |
1559 | var station3 = new RadioStation(102);
1560 | stations.Add(station3);
1561 |
1562 | foreach(var x in stations)
1563 | {
1564 | Console.Write(x.GetFrequecy());
1565 | }
1566 |
1567 | var q = stations.Where(x => x.GetFrequecy() == 89).FirstOrDefault();
1568 | Console.WriteLine(q.GetFrequecy());
1569 |
1570 | Console.ReadLine();
1571 | ```
1572 |
1573 | 👽 Mediator
1574 | ========
1575 |
1576 | Real world example
1577 | > A general example would be when you talk to someone on your mobile phone, there is a network provider sitting between you and them and your conversation goes through it instead of being directly sent. In this case network provider is mediator.
1578 |
1579 | In plain words
1580 | > Mediator pattern adds a third party object (called mediator) to control the interaction between two objects (called colleagues). It helps reduce the coupling between the classes communicating with each other. Because now they don't need to have the knowledge of each other's implementation.
1581 |
1582 | Wikipedia says
1583 | > In software engineering, the mediator pattern defines an object that encapsulates how a set of objects interact. This pattern is considered to be a behavioral pattern due to the way it can alter the program's running behavior.
1584 |
1585 | **Programmatic Example**
1586 |
1587 | Here is the simplest example of a chat room (i.e. mediator) with users (i.e. colleagues) sending messages to each other.
1588 |
1589 | First of all, we have the mediator i.e. the chat room
1590 |
1591 | ```C#
1592 | interface IChatRoomMediator
1593 | {
1594 | void ShowMessage(User user, string message);
1595 | }
1596 |
1597 | //Mediator
1598 | class ChatRoom : IChatRoomMediator
1599 | {
1600 | public void ShowMessage(User user, string message)
1601 | {
1602 | Console.WriteLine($"{DateTime.Now.ToString("MMMM dd, H:mm")} [{user.GetName()}]:{message}");
1603 | }
1604 | }
1605 | ```
1606 |
1607 | Then we have our users i.e. colleagues
1608 | ```C#
1609 | class User
1610 | {
1611 | private string mName;
1612 | private IChatRoomMediator mChatRoom;
1613 |
1614 | public User(string name, IChatRoomMediator chatroom)
1615 | {
1616 | mChatRoom = chatroom;
1617 | mName = name;
1618 | }
1619 |
1620 | public string GetName()
1621 | {
1622 | return mName;
1623 | }
1624 |
1625 | public void Send(string message)
1626 | {
1627 | mChatRoom.ShowMessage(this, message);
1628 | }
1629 | }
1630 | ```
1631 | And the usage
1632 | ```C#
1633 | var mediator = new ChatRoom();
1634 |
1635 | var john = new User("John", mediator);
1636 | var jane = new User("Jane", mediator);
1637 |
1638 | john.Send("Hi there!");
1639 | jane.Send("Hey!");
1640 |
1641 | //April 14, 20:05[John]:Hi there!
1642 | //April 14, 20:05[Jane]:Hey!
1643 | ```
1644 |
1645 | 💾 Memento
1646 | -------
1647 | Real world example
1648 | > Take the example of calculator (i.e. originator), where whenever you perform some calculation the last calculation is saved in memory (i.e. memento) so that you can get back to it and maybe get it restored using some action buttons (i.e. caretaker).
1649 |
1650 | In plain words
1651 | > Memento pattern is about capturing and storing the current state of an object in a manner that it can be restored later on in a smooth manner.
1652 |
1653 | Wikipedia says
1654 | > The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback).
1655 |
1656 | Usually useful when you need to provide some sort of undo functionality.
1657 |
1658 | **Programmatic Example**
1659 |
1660 | Lets take an example of text editor which keeps saving the state from time to time and that you can restore if you want.
1661 |
1662 | First of all we have our memento object that will be able to hold the editor state
1663 |
1664 | ```C#
1665 | class EditorMemento
1666 | {
1667 | private string mContent;
1668 |
1669 | public EditorMemento(string content)
1670 | {
1671 | mContent = content;
1672 | }
1673 |
1674 | public string Content
1675 | {
1676 | get
1677 | {
1678 | return mContent;
1679 | }
1680 | }
1681 | }
1682 | ```
1683 |
1684 | Then we have our editor i.e. originator that is going to use memento object
1685 |
1686 | ```C#
1687 | class Editor {
1688 |
1689 | private string mContent = string.Empty;
1690 | private EditorMemento memento;
1691 |
1692 | public Editor()
1693 | {
1694 | memento = new EditorMemento(string.Empty);
1695 | }
1696 |
1697 | public void Type(string words)
1698 | {
1699 | mContent = String.Concat(mContent," ", words);
1700 | }
1701 |
1702 | public string Content
1703 | {
1704 | get
1705 | {
1706 | return mContent;
1707 | }
1708 | }
1709 |
1710 | public void Save()
1711 | {
1712 | memento = new EditorMemento(mContent);
1713 | }
1714 |
1715 | public void Restore()
1716 | {
1717 | mContent = memento.Content;
1718 | }
1719 | }
1720 | ```
1721 |
1722 | And then it can be used as
1723 |
1724 | ```C#
1725 | var editor = new Editor();
1726 |
1727 | //Type some stuff
1728 | editor.Type("This is the first sentence.");
1729 | editor.Type("This is second.");
1730 |
1731 | // Save the state to restore to : This is the first sentence. This is second.
1732 | editor.Save();
1733 |
1734 | //Type some more
1735 | editor.Type("This is third.");
1736 |
1737 | //Output the content
1738 | Console.WriteLine(editor.Content); // This is the first sentence. This is second. This is third.
1739 |
1740 | //Restoring to last saved state
1741 | editor.Restore();
1742 |
1743 | Console.Write(editor.Content); // This is the first sentence. This is second
1744 |
1745 | ```
1746 |
1747 | 😎 Observer
1748 | --------
1749 | Real world example
1750 | > A good example would be the job seekers where they subscribe to some job posting site and they are notified whenever there is a matching job opportunity.
1751 |
1752 | In plain words
1753 | > Defines a dependency between objects so that whenever an object changes its state, all its dependents are notified.
1754 |
1755 | Wikipedia says
1756 | > The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
1757 |
1758 | **Programmatic example**
1759 |
1760 | Translating our example from above. First of all we have job seekers that need to be notified for a job posting
1761 | ```C#
1762 | class JobPost
1763 | {
1764 | public string Title { get; private set; }
1765 |
1766 | public JobPost(string title)
1767 | {
1768 | Title = title;
1769 | }
1770 | }
1771 | class JobSeeker : IObserver
1772 | {
1773 | public string Name { get; private set; }
1774 |
1775 | public JobSeeker(string name)
1776 | {
1777 | Name = name;
1778 | }
1779 |
1780 | //Method is not being called by JobPostings class currently
1781 | public void OnCompleted()
1782 | {
1783 | //No Implementation
1784 | }
1785 |
1786 | //Method is not being called by JobPostings class currently
1787 | public void OnError(Exception error)
1788 | {
1789 | //No Implementation
1790 | }
1791 |
1792 | public void OnNext(JobPost value)
1793 | {
1794 | Console.WriteLine($"Hi {Name} ! New job posted: {value.Title}");
1795 | }
1796 | }
1797 | ```
1798 | Then we have our job postings to which the job seekers will subscribe
1799 | ```C#
1800 | class JobPostings : IObservable
1801 | {
1802 | private List> mObservers;
1803 | private List mJobPostings;
1804 |
1805 | public JobPostings()
1806 | {
1807 | mObservers = new List>();
1808 | mJobPostings = new List();
1809 | }
1810 |
1811 | public IDisposable Subscribe(IObserver observer)
1812 | {
1813 | // Check whether observer is already registered. If not, add it
1814 | if (!mObservers.Contains(observer))
1815 | {
1816 | mObservers.Add(observer);
1817 | }
1818 | return new Unsubscriber(mObservers, observer);
1819 | }
1820 |
1821 | private void Notify(JobPost jobPost)
1822 | {
1823 | foreach(var observer in mObservers)
1824 | {
1825 | observer.OnNext(jobPost);
1826 | }
1827 | }
1828 |
1829 | public void AddJob(JobPost jobPost)
1830 | {
1831 | mJobPostings.Add(jobPost);
1832 | Notify(jobPost);
1833 | }
1834 |
1835 | }
1836 |
1837 | internal class Unsubscriber : IDisposable
1838 | {
1839 | private List> mObservers;
1840 | private IObserver mObserver;
1841 |
1842 | internal Unsubscriber(List> observers, IObserver observer)
1843 | {
1844 | this.mObservers = observers;
1845 | this.mObserver = observer;
1846 | }
1847 |
1848 | public void Dispose()
1849 | {
1850 | if (mObservers.Contains(mObserver))
1851 | mObservers.Remove(mObserver);
1852 | }
1853 | }
1854 | ```
1855 | Then it can be used as
1856 | ```C#
1857 | //Create Subscribers
1858 | var johnDoe = new JobSeeker("John Doe");
1859 | var janeDoe = new JobSeeker("Jane Doe");
1860 |
1861 | //Create publisher and attch subscribers
1862 | var jobPostings = new JobPostings();
1863 | jobPostings.Subscribe(johnDoe);
1864 | jobPostings.Subscribe(janeDoe);
1865 |
1866 | //Add a new job and see if subscribers get notified
1867 | jobPostings.AddJob(new JobPost("Software Engineer"));
1868 |
1869 | //Output
1870 | // Hi John Doe! New job posted: Software Engineer
1871 | // Hi Jane Doe! New job posted: Software Engineer
1872 |
1873 | Console.ReadLine();
1874 | ```
1875 |
1876 | 🏃 Visitor
1877 | -------
1878 | Real world example
1879 | > Consider someone visiting Dubai. They just need a way (i.e. visa) to enter Dubai. After arrival, they can come and visit any place in Dubai on their own without having to ask for permission or to do some leg work in order to visit any place here; just let them know of a place and they can visit it. Visitor pattern lets you do just that, it helps you add places to visit so that they can visit as much as they can without having to do any legwork.
1880 |
1881 | In plain words
1882 | > Visitor pattern lets you add further operations to objects without having to modify them.
1883 |
1884 | Wikipedia says
1885 | > In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to follow the open/closed principle.
1886 |
1887 | **Programmatic example**
1888 |
1889 | Let's take an example of a zoo simulation where we have several different kinds of animals and we have to make them Sound. Let's translate this using visitor pattern
1890 |
1891 | ```C#
1892 | // Visitee
1893 | interface IAnimal
1894 | {
1895 | void Accept(IAnimalOperation operation);
1896 | }
1897 |
1898 | // Visitor
1899 | interface IAnimalOperation
1900 | {
1901 | void VisitMonkey(Monkey monkey);
1902 | void VisitLion(Lion lion);
1903 | void VisitDolphin(Dolphin dolphin);
1904 | }
1905 | ```
1906 | Then we have our implementations for the animals
1907 | ```C#
1908 | class Monkey : IAnimal
1909 | {
1910 | public void Shout()
1911 | {
1912 | Console.WriteLine("Oooh o aa aa!");
1913 | }
1914 |
1915 | public void Accept(IAnimalOperation operation)
1916 | {
1917 | operation.VisitMonkey(this);
1918 | }
1919 | }
1920 |
1921 | class Lion : IAnimal
1922 | {
1923 | public void Roar()
1924 | {
1925 | Console.WriteLine("Roaar!");
1926 | }
1927 |
1928 | public void Accept(IAnimalOperation operation)
1929 | {
1930 | operation.VisitLion(this);
1931 | }
1932 | }
1933 |
1934 | class Dolphin : IAnimal
1935 | {
1936 | public void Speak()
1937 | {
1938 | Console.WriteLine("Tuut tittu tuutt!");
1939 | }
1940 |
1941 | public void Accept(IAnimalOperation operation)
1942 | {
1943 | operation.VisitDolphin(this);
1944 | }
1945 | }
1946 | ```
1947 | Let's implement our visitor
1948 | ```C#
1949 | class Speak : IAnimalOperation
1950 | {
1951 | public void VisitDolphin(Dolphin dolphin)
1952 | {
1953 | dolphin.Speak();
1954 | }
1955 |
1956 | public void VisitLion(Lion lion)
1957 | {
1958 | lion.Roar();
1959 | }
1960 |
1961 | public void VisitMonkey(Monkey monkey)
1962 | {
1963 | monkey.Shout();
1964 | }
1965 | }
1966 | ```
1967 |
1968 | And then it can be used as
1969 | ```C#
1970 | var monkey = new Monkey();
1971 | var lion = new Lion();
1972 | var dolphin = new Dolphin();
1973 |
1974 | var speak = new Speak();
1975 |
1976 | monkey.Accept(speak); // Ooh oo aa aa!
1977 | lion.Accept(speak); // Roaaar!
1978 | dolphin.Accept(speak); // Tuut tutt tuutt!
1979 |
1980 | ```
1981 | We could have done this simply by having an inheritance hierarchy for the animals but then we would have to modify the animals whenever we would have to add new actions to animals. But now we will not have to change them. For example, let's say we are asked to add the jump behavior to the animals, we can simply add that by creating a new visitor i.e.
1982 |
1983 | ```C#
1984 | class Jump : IAnimalOperation
1985 | {
1986 | public void VisitDolphin(Dolphin dolphin)
1987 | {
1988 | Console.WriteLine("Walked on water a little and disappeared!");
1989 | }
1990 |
1991 | public void VisitLion(Lion lion)
1992 | {
1993 | Console.WriteLine("Jumped 7 feet! Back on the ground!");
1994 | }
1995 |
1996 | public void VisitMonkey(Monkey monkey)
1997 | {
1998 | Console.WriteLine("Jumped 20 feet high! on to the tree!");
1999 | }
2000 | }
2001 | ```
2002 | And for the usage
2003 | ```C#
2004 | var jump = new Jump();
2005 |
2006 | monkey.Accept(speak); // Ooh oo aa aa!
2007 | monkey.Accept(jump); // Jumped 20 feet high! on to the tree!
2008 |
2009 | lion.Accept(speak); // Roaaar!
2010 | lion.Accept(jump); // Jumped 7 feet! Back on the ground!
2011 |
2012 | dolphin.Accept(speak); // Tuut tutt tuutt!
2013 | dolphin.Accept(jump); // Walked on water a little and disappeared
2014 |
2015 | ```
2016 |
2017 | 💡 Strategy
2018 | --------
2019 |
2020 | Real world example
2021 | > Consider the example of sorting, we implemented bubble sort but the data started to grow and bubble sort started getting very slow. In order to tackle this we implemented Quick sort. But now although the quick sort algorithm was doing better for large datasets, it was very slow for smaller datasets. In order to handle this we implemented a strategy where for small datasets, bubble sort will be used and for larger, quick sort.
2022 |
2023 | In plain words
2024 | > Strategy pattern allows you to switch the algorithm or strategy based upon the situation.
2025 |
2026 | Wikipedia says
2027 | > In computer programming, the strategy pattern (also known as the policy pattern) is a behavioural software design pattern that enables an algorithm's behavior to be selected at runtime.
2028 |
2029 | **Programmatic example**
2030 |
2031 | Translating our example from above. First of all we have our strategy interface and different strategy implementations
2032 |
2033 | ```C#
2034 | interface ISortStrategy
2035 | {
2036 | List Sort(List dataset);
2037 | }
2038 |
2039 | class BubbleSortStrategy : ISortStrategy
2040 | {
2041 | public List Sort(List dataset)
2042 | {
2043 | Console.WriteLine("Sorting using Bubble Sort !");
2044 | return dataset;
2045 | }
2046 | }
2047 |
2048 | class QuickSortStrategy : ISortStrategy
2049 | {
2050 | public List Sort(List dataset)
2051 | {
2052 | Console.WriteLine("Sorting using Quick Sort !");
2053 | return dataset;
2054 | }
2055 | }
2056 | ```
2057 |
2058 | And then we have our client that is going to use any strategy
2059 | ```C#
2060 | class Sorter
2061 | {
2062 | private readonly ISortStrategy mSorter;
2063 |
2064 | public Sorter(ISortStrategy sorter)
2065 | {
2066 | mSorter = sorter;
2067 | }
2068 |
2069 | public List Sort(List unSortedList)
2070 | {
2071 | return mSorter.Sort(unSortedList);
2072 | }
2073 | }
2074 | ```
2075 | And it can be used as
2076 | ```C#
2077 | var unSortedList = new List { 1, 10, 2, 16, 19 };
2078 |
2079 | var sorter = new Sorter(new BubbleSortStrategy());
2080 | sorter.Sort(unSortedList); // // Output : Sorting using Bubble Sort !
2081 |
2082 | sorter = new Sorter(new QuickSortStrategy());
2083 | sorter.Sort(unSortedList); // // Output : Sorting using Quick Sort !
2084 | ```
2085 |
2086 | 💢 State
2087 | -----
2088 | Real world example
2089 | > Imagine you are using some drawing application, you choose the paint brush to draw. Now the brush changes its behavior based on the selected color i.e. if you have chosen red color it will draw in red, if blue then it will be in blue etc.
2090 |
2091 | In plain words
2092 | > It lets you change the behavior of a class when the state changes.
2093 |
2094 | Wikipedia says
2095 | > The state pattern is a behavioral software design pattern that implements a state machine in an object-oriented way. With the state pattern, a state machine is implemented by implementing each individual state as a derived class of the state pattern interface, and implementing state transitions by invoking methods defined by the pattern's superclass.
2096 | > The state pattern can be interpreted as a strategy pattern which is able to switch the current strategy through invocations of methods defined in the pattern's interface.
2097 |
2098 | **Programmatic example**
2099 |
2100 | Let's take an example of text editor, it lets you change the state of text that is typed i.e. if you have selected bold, it starts writing in bold, if italic then in italics etc.
2101 |
2102 | First of all we have our state interface and some state implementations
2103 |
2104 | ```C#
2105 | interface IWritingState {
2106 |
2107 | void Write(string words);
2108 |
2109 | }
2110 |
2111 | class UpperCase : IWritingState
2112 | {
2113 | public void Write(string words)
2114 | {
2115 | Console.WriteLine(words.ToUpper());
2116 | }
2117 | }
2118 |
2119 | class LowerCase : IWritingState
2120 | {
2121 | public void Write(string words)
2122 | {
2123 | Console.WriteLine(words.ToLower());
2124 | }
2125 | }
2126 |
2127 | class DefaultText : IWritingState
2128 | {
2129 | public void Write(string words)
2130 | {
2131 | Console.WriteLine(words);
2132 | }
2133 | }
2134 | ```
2135 | Then we have our editor
2136 | ```C#
2137 | class TextEditor {
2138 |
2139 | private IWritingState mState;
2140 |
2141 | public TextEditor()
2142 | {
2143 | mState = new DefaultText();
2144 | }
2145 |
2146 | public void SetState(IWritingState state)
2147 | {
2148 | mState = state;
2149 | }
2150 |
2151 | public void Type(string words)
2152 | {
2153 | mState.Write(words);
2154 | }
2155 |
2156 | }
2157 | ```
2158 | And then it can be used as
2159 | ```C#
2160 | var editor = new TextEditor();
2161 |
2162 | editor.Type("First line");
2163 |
2164 | editor.SetState(new UpperCase());
2165 |
2166 | editor.Type("Second Line");
2167 | editor.Type("Third Line");
2168 |
2169 | editor.SetState(new LowerCase());
2170 |
2171 | editor.Type("Fourth Line");
2172 | editor.Type("Fifthe Line");
2173 |
2174 | // Output:
2175 | // First line
2176 | // SECOND LINE
2177 | // THIRD LINE
2178 | // fourth line
2179 | // fifth line
2180 | ```
2181 |
2182 | 📒 Template Method
2183 | ---------------
2184 |
2185 | Real world example
2186 | > Suppose we are getting some house built. The steps for building might look like
2187 | > - Prepare the base of house
2188 | > - Build the walls
2189 | > - Add roof
2190 | > - Add other floors
2191 |
2192 | > The order of these steps could never be changed i.e. you can't build the roof before building the walls etc but each of the steps could be modified for example walls can be made of wood or polyester or stone.
2193 |
2194 | In plain words
2195 | > Template method defines the skeleton of how a certain algorithm could be performed, but defers the implementation of those steps to the children classes.
2196 |
2197 | Wikipedia says
2198 | > In software engineering, the template method pattern is a behavioral design pattern that defines the program skeleton of an algorithm in an operation, deferring some steps to subclasses. It lets one redefine certain steps of an algorithm without changing the algorithm's structure.
2199 |
2200 | **Programmatic Example**
2201 |
2202 | Imagine we have a build tool that helps us test, lint, build, generate build reports (i.e. code coverage reports, linting report etc) and deploy our app on the test server.
2203 |
2204 | First of all we have our base class that specifies the skeleton for the build algorithm
2205 | ```C#
2206 | abstract class Builder
2207 | {
2208 | // Template method
2209 | public void Build()
2210 | {
2211 | Test();
2212 | Lint();
2213 | Assemble();
2214 | Deploy();
2215 | }
2216 |
2217 | abstract public void Test();
2218 | abstract public void Lint();
2219 | abstract public void Assemble();
2220 | abstract public void Deploy();
2221 | }
2222 | ```
2223 |
2224 | Then we can have our implementations
2225 |
2226 | ```C#
2227 | class AndroidBuilder : Builder
2228 | {
2229 | public override void Assemble()
2230 | {
2231 | Console.WriteLine("Assembling the android build");
2232 | }
2233 |
2234 | public override void Deploy()
2235 | {
2236 | Console.WriteLine("Deploying android build to server");
2237 | }
2238 |
2239 | public override void Lint()
2240 | {
2241 | Console.WriteLine("Linting the android code");
2242 | }
2243 |
2244 | public override void Test()
2245 | {
2246 | Console.WriteLine("Running android tests");
2247 | }
2248 | }
2249 |
2250 |
2251 | class IosBuilder : Builder
2252 | {
2253 | public override void Assemble()
2254 | {
2255 | Console.WriteLine("Assembling the ios build");
2256 | }
2257 |
2258 | public override void Deploy()
2259 | {
2260 | Console.WriteLine("Deploying ios build to server");
2261 | }
2262 |
2263 | public override void Lint()
2264 | {
2265 | Console.WriteLine("Linting the ios code");
2266 | }
2267 |
2268 | public override void Test()
2269 | {
2270 | Console.WriteLine("Running ios tests");
2271 | }
2272 | }
2273 |
2274 | ```
2275 | And then it can be used as
2276 |
2277 | ```C#
2278 | var androidBuilder = new AndroidBuilder();
2279 | androidBuilder.Build();
2280 |
2281 | // Output:
2282 | // Running android tests
2283 | // Linting the android code
2284 | // Assembling the android build
2285 | // Deploying android build to server
2286 |
2287 | var iosBuilder = new IosBuilder();
2288 | iosBuilder.Build();
2289 |
2290 | // Output:
2291 | // Running ios tests
2292 | // Linting the ios code
2293 | // Assembling the ios build
2294 | // Deploying ios build to server
2295 | ```
2296 |
2297 | ## 🚦 Wrap Up Folks
2298 |
2299 | And that about wraps it up. I will continue to improve this, so you might want to watch/star this repository to revisit. Also, I have plans on writing the same about the architectural patterns, stay tuned for it.
2300 |
2301 | ## 👬 Contribution
2302 |
2303 | - Report issues
2304 | - Open pull request with improvements
2305 | - Spread the word
2306 | - Contact me on Twitter
2307 |
2308 | ## License
2309 |
2310 | [](https://creativecommons.org/licenses/by/4.0/)
2311 |
--------------------------------------------------------------------------------