└── README.md
/README.md:
--------------------------------------------------------------------------------
1 | # design-pattern-practice
2 | Practice notes for problems and solutions learned from Head First Design Pattern book
3 |
4 | [](https://github.com/)
5 |
6 |
7 |
8 |
9 | *******
10 | Tables of contents
11 | 1. [Strategy Pattern](#strategypattern)
12 | 2. [Observer Pattern](#observerpattern)
13 | 3. [Decorator Pattern](#decoratorpattern)
14 | 4. [Factory Pattern](#factorypattern)
15 | 5. [Singleton Pattern](#singletonpattern)
16 | 6. [Command Pattern](#commandpattern)
17 |
18 | *******
19 | [Jump to end](#theend)
20 |
21 |
22 | # Strategy Pattern:
23 |
24 | **Get started:** Write a program to display a Duck and other kinds of duck. Basic action that a duck can perform is swim, quack and display
25 |
26 | **Naive approach:** Use OO basics like Inheritance, create a Duck then other kinds of duck inherits attributes, method and override it if needed.
27 |
28 | The class diagram looks like:
29 |
30 | ```mermaid
31 |
32 | classDiagram
33 | Duck <|-- OtherKindsOfDuck
34 | Duck <|-- MallardDuck
35 | Duck <|-- RedheadDuck
36 |
37 | class Duck{
38 | +swim()
39 | +quack()
40 | +display()
41 | }
42 | class OtherKindsOfDuck{
43 | +display()
44 | }
45 | class MallardDuck{
46 | +display()
47 | }
48 | class RedheadDuck{
49 | +display()
50 | }
51 |
52 | ```
53 |
54 |
55 | **What if ..? :**
56 | - The customer wants to add a Rubber Duck. It's ok, just override all the methods then leave it empty
57 | - The customer wants to add new action to a duck, like fly. We can add fly method to Duck class, and we forget to override this method in 33 subclass of Duck that can not fly. Big problem here!
58 | - The customer wants different duck to quack differently, We have to override quack in every Duck subclass?
59 |
60 | **Another approach:**
61 | - Use Interface `Quackable` and `Flyable`. Which type of duck can flly or quack can implement from theese interfaces but this is still not a good approach.
62 | - This approach looks good at first, but not good for mantainance. When we need to modify a behavior, we need to track and change it in all subclasses, this can lead to new bug.
63 |
64 | ```mermaid
65 | classDiagram
66 | Duck <|-- RubberDuck
67 | Duck <|-- MallardDuck
68 | Duck <|-- RedheadDuck
69 | Quackable <.. RedheadDuck
70 | Quackable <.. MallardDuck
71 |
72 | class Duck{
73 | +swim()
74 | +quack()
75 | +display()
76 | }
77 | class RubberDuck{
78 | +display()
79 | }
80 | class MallardDuck{
81 | +display()
82 | +quack()
83 | }
84 | class RedheadDuck{
85 | +display()
86 | +fly()
87 | +quack()
88 | }
89 |
90 | class Quackable{
91 | <>
92 | +quack()
93 | }
94 |
95 | Flyable <.. RedheadDuck
96 | class Flyable{
97 | <>
98 | +fly()
99 | }
100 |
101 | ```
102 |
103 |
104 |
105 | **Efficient approach:**
106 | - We will delegate our Duck methods to another class, and interface so that our program would be less code reuse but, more flexible and maintainable (Following some Design Principles noted at the end of this section)
107 | - Create interfaces for behaviors like FlyBehavior, QuackBehavior. Then for each specific behavior, we create a class that implements the interface. Next, add a reference of each behavior inside a kind of Duck.
108 | - Our final result:
109 |
110 | ```mermaid
111 |
112 | classDiagram
113 | Duck <|-- RubberDuck
114 | Duck <|-- MallardDuck
115 | Duck <|-- RedheadDuck
116 |
117 | class Duck{
118 | -FlyBehavior flyBehavior
119 | -QuackBehavior quackBehavior
120 | +swim()
121 | +quack()
122 | +display()
123 | +setFlyBehavior()
124 | +setQuackBehavior()
125 | }
126 |
127 | class RubberDuck{
128 | +display()
129 | }
130 |
131 | class MallardDuck{
132 | +display()
133 | +quack()
134 | }
135 |
136 | class RedheadDuck{
137 | +display()
138 | +fly()
139 | +quack()
140 | }
141 | FlyBehavior <.. FlyWithWings
142 | FlyBehavior <.. FlyNoWay
143 |
144 | class FlyBehavior{
145 | <>
146 | +fly()
147 | }
148 |
149 | class FlyWithWings{
150 | +fly()
151 | }
152 |
153 | class FlyNoWay{
154 | +fly()
155 | }
156 |
157 |
158 | QuackBehavior <.. Quack
159 | QuackBehavior <.. Squeak
160 |
161 | class QuackBehavior{
162 | <>
163 | +fly()
164 | }
165 |
166 | class Quack{
167 | +quack()
168 | }
169 |
170 | class Squeak{
171 | +quack()
172 | }
173 |
174 | ```
175 |
176 |
177 | **Conclusion:**
178 | - **The Strategy Pattern** defines a family of algorithms,encapsulates each one, and makes them interchangeable.Strategy lets the algorithm vary independently from clients that use it
179 |
180 | [Back to top](#top)
181 |
182 |
183 |
184 | # Observer Pattern:
185 | **Get started:** Given that we need to write a Weather monitor application. In this application, we have to get data from a provider. The important thing is that, we need to notify to all users whenver the forecase measurement data is updated. And also we need to display it with in multiple forms.
186 |
187 | **Naive approach:** So first of all, we need a class contains the data and some methods to get and display data to the user. The class would look like:
188 |
189 | ```mermaid
190 | classDiagram
191 |
192 | class WeatherData{
193 | -CurrentConditionDisplay currentConditionDisplay
194 | -StatisticsDisplay statisticsDisplay
195 | -ForecastDisplay forecastDisplay
196 | +getTemprature()
197 | +getHumidity()
198 | +getPressure()
199 | +measurementsDataChanged()
200 | }
201 | ```
202 |
203 | And our `measurementsDataChanged` method would look something like:
204 |
205 | ```java
206 | public void measurementsDataChanged() {
207 | float temp = getTemperature()
208 | float humidity = getHumidity()
209 | float pressure = getPressure()
210 |
211 | currentConditionDisplay.update(temp, humidity, pressure)
212 | statisticsDisplay.update(temp, humidity, pressure)
213 | forecastDisplay.update(temp, humidity, pressure)
214 | }
215 | ```
216 |
217 |
218 | **What if ..? :**
219 | - We need to add more display or remove one. Because the `measurementsDataChanged()` method is implemented in concrete way, we can not add or remove display withou making changes to the program
220 |
221 | **Efficient approach:** We use Observer Pattern for this case. In this pattern, we will have a `Subject` which is our `WeatherData` class, where we get data from. The next one is `Observers`, all the thing that consume the data which is our displays
222 | - First, we need to define all the interface needed for `Observers`, `Subjects` along with shared behavior of each observer:
223 | ```mermaid
224 | classDiagram
225 | class Subject{
226 | <>
227 | +registerObserver(Observer o)
228 | +removeObserver(Observer o)
229 | +notifyObservers()
230 | }
231 |
232 | class Observer{
233 | <>
234 | +update(float temp, float humidity, float pressure)
235 | }
236 |
237 | class DisplayElement{
238 | <>
239 | +display()
240 | }
241 |
242 | ```
243 | - Next, refactor our `WeatherData` class:
244 | ```java
245 | public class WeatherData implements Subject {
246 | private ArrayList observers;
247 | private float temperature;
248 | private float humidity;
249 | private float pressure;
250 |
251 | public WeatherData() {
252 | observers = new ArrayList();
253 | }
254 |
255 | public void registerObserver(Observer o) {
256 | observers.add(o);
257 | }
258 |
259 | public void removeObserver(Observer o) {
260 | int i = observers.indexOf(o);
261 | if (i >= 0) {
262 | observers.remove(i);
263 | }
264 | }
265 |
266 | public void notifyObservers() {
267 | for (int i = 0; i < observers.size(); i++) {
268 | Observer observer = (Observer) observers.get(i);
269 | observer.update(temperature, humidity, pressure);
270 | }
271 | }
272 |
273 | public void measurementsChanged() {
274 | notifyObservers();
275 | }
276 | public void setMeasurements(float temperature, float humidity, float pressure) {
277 | this.temperature = temperature;
278 | this.humidity = humidity;
279 | this.pressure = pressure;
280 | measurementsChanged();
281 | }
282 | }
283 | ```
284 |
285 |
286 | - Our final result:
287 |
288 | ```mermaid
289 | classDiagram
290 | WeatherData <|-- Subject
291 | class WeatherData{
292 | -CurrentConditionDisplay currentConditionDisplay
293 | -StatisticsDisplay statisticsDisplay
294 | -ForecastDisplay forecastDisplay
295 | +getTemprature()
296 | +getHumidity()
297 | +getPressure()
298 | +measurementsDataChanged()
299 | +registerObserver(Observer o)
300 | +removeObserver(Observer o)
301 | +notifyObservers()
302 | }
303 | class Subject{
304 | <>
305 | +registerObserver(Observer o)
306 | +removeObserver(Observer o)
307 | +notifyObservers()
308 | }
309 |
310 | class Observer{
311 | <>
312 | +update(float temp, float humidity, float pressure)
313 | }
314 |
315 | class DisplayElement{
316 | <>
317 | +display()
318 | }
319 |
320 | CurrentConditionDisplay <|-- Observer
321 | CurrentConditionDisplay <|-- DisplayElement
322 | class CurrentConditionDisplay {
323 | +update(float temp, float humidity, float pressure)
324 | +display()
325 | }
326 |
327 | StatisticsDisplay <|-- Observer
328 | StatisticsDisplay <|-- DisplayElement
329 | class StatisticsDisplay {
330 | +update(float temp, float humidity, float pressure)
331 | +display()
332 | }
333 |
334 | ForecastDisplay <|-- Observer
335 | ForecastDisplay <|-- DisplayElement
336 | class ForecastDisplay {
337 | +update(float temp, float humidity, float pressure)
338 | +display()
339 | }
340 | ```
341 | **Conclusion:**
342 | - **The Observer Pattern** defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically
343 |
344 | [Back to top](#top)
345 |
346 |
347 |
348 | # Decorator Pattern:
349 | **Get started:** Write a program to for a coffee shop to create order with many beverages, of course, many toppings and other properties are added onto each beverage.
350 |
351 | **Naive approach:** Create an abstract class called Beverage, and other kind will extends this class. Then just override methods like cost() to calculate the price for each kind of beverage.
352 |
353 | The class diagram looks like:
354 | ```mermaid
355 | classDiagram
356 | class Beverage{
357 | -String description
358 | +getDescription()
359 | +cost()
360 | }
361 |
362 | Beverage <|-- HouseBlend
363 | class HouseBlend{
364 | +cost()
365 | }
366 |
367 | Beverage <|-- DarkRoast
368 | class DarkRoast{
369 | +cost()
370 | }
371 |
372 | Beverage <|-- Decaf
373 | class Decaf{
374 | +cost()
375 | }
376 |
377 |
378 | Beverage <|-- Espresso
379 | class Espresso{
380 | +cost()
381 | }
382 | ```
383 |
384 | **What if ..? :**
385 | - We want to add some condiments like milk, chocolate, then we just need to create more class for this kind of "new" beverage. Maybe for current Coffee type, we would have new classes such as CoffeeWithMilk, CoffeeWithSoy,..**uh oh Class Explosion**
386 | - We calculate the price for each beverage, with different condiments, size
387 |
388 | **Another approach:**
389 | - Put all the condiments inside the abstract Beverage class, then for each subclass, we have to override all the checking condiments method as below. This is still not a good approach
390 |
391 | ```mermaid
392 | classDiagram
393 | class Beverage{
394 | -String description
395 | -Condiment milk
396 | -Condiment mocha
397 | -Condiment soy
398 | -Condiment whip
399 | +getDescription()
400 | +cost()
401 | +hasMilk()
402 | +setMilk()
403 | +hasMocha()
404 | +setMocha()
405 | +hasWhip()
406 | +setWhip()
407 | }
408 |
409 | Beverage <|-- HouseBlend
410 | class HouseBlend{
411 | +cost()
412 | }
413 |
414 | Beverage <|-- DarkRoast
415 | class DarkRoast{
416 | +cost()
417 | }
418 |
419 | Beverage <|-- Decaf
420 | class Decaf{
421 | +cost()
422 | }
423 |
424 | Beverage <|-- Espresso
425 | class Espresso{
426 | +cost()
427 | }
428 | ```
429 | - Our `cost()` method in `Beverage` class would look like:
430 | ```java
431 | public double cost() {
432 | double condimentCost = 0.0
433 | if (hasMilk()) {
434 | condimentCost += milk.getCost()
435 | }
436 |
437 | if (hasMocha()) {
438 | coondimentCost += mocha.getCost()
439 | }
440 | return condimentCost
441 | }
442 | ```
443 |
444 | - OUr `cost()` method in concreate class lets say `DarkRoast` would loook like:
445 |
446 | ```java
447 | public double cost() {
448 | return 1.99 + super.cost()
449 | }
450 | ```
451 |
452 | **Efficient approach:** WE will use the Decorator Pattern. The core concept of this pattern would look like:
453 | ```mermaid
454 | classDiagram
455 | class Component{
456 | +methodA()
457 | +methodB()
458 | }
459 |
460 | Component <|-- ConcreteComponent
461 | class ConcreteComponent{
462 | +methodA()
463 | +methodB()
464 | }
465 |
466 | Component <|-- Decorator
467 | class Decorator{
468 | +methodA()
469 | +methodB()
470 | }
471 |
472 | Decorator <|-- ConcreteDecoratorA
473 | class ConcreteDecoratorA{
474 | +methodA()
475 | +methodB()
476 | }
477 |
478 | Decorator <|-- ConcreteDecoratorB
479 | class ConcreteDecoratorB{
480 | +methodA()
481 | +methodB()
482 | }
483 | ```
484 | - When we apply to our current design, it would look like:
485 | ```mermaid
486 | classDiagram
487 | class Beverage{
488 | -String description
489 | +cost()
490 | +getDescription()
491 | }
492 |
493 | Beverage <|-- HouseBlend
494 | class HouseBlend{
495 | +cost()
496 | }
497 |
498 | Beverage <|-- Espresso
499 | class Espresso{
500 | +cost()
501 | }
502 |
503 | Beverage <|-- DarkRoast
504 | class DarkRoast{
505 | +cost()
506 | }
507 |
508 | Beverage <|-- CondimentDecorator
509 | class CondimentDecorator{
510 | +getDescription()
511 | }
512 |
513 | CondimentDecorator <|-- Milk
514 | class Milk{
515 | -Beverage beverage
516 | +cost()
517 | +getDescription()
518 | }
519 |
520 | CondimentDecorator <|-- Mocha
521 | class Mocha{
522 | -Beverage beverage
523 | +cost()
524 | +getDescription()
525 | }
526 |
527 | CondimentDecorator <|-- Soy
528 | class Soy{
529 | -Beverage beverage
530 | +cost()
531 | +getDescription()
532 | }
533 |
534 | CondimentDecorator <|-- Whip
535 | class Whip{
536 | -Beverage beverage
537 | +cost()
538 | +getDescription()
539 | }
540 | ```
541 |
542 | - Here is how we actually use this pattern in code:
543 |
544 | ```java
545 | public abstract class Beverage {
546 | String description = “Unknown Beverage”;
547 | public String getDescription() {
548 | return description;
549 | }
550 | public abstract double cost();
551 | }
552 |
553 | public abstract class CondimentDecorator extends Beverage {
554 | public abstract String getDescription();
555 | }
556 | ```
557 | - Our concrete beverages:
558 | ```java
559 | public class Espresso extends Beverage {
560 | public Espresso() {
561 | description = “Espresso”;
562 | }
563 | public double cost() {
564 | return 1.99;
565 | }
566 | }
567 | ```
568 |
569 | ```java
570 | public class HouseBlend extends Beverage {
571 | public HouseBlend() {
572 | description = “House Blend Coffee”;
573 | }
574 | public double cost() {
575 | return .89;
576 | }
577 | }
578 | ```
579 | - Our condiment decorator
580 | ```java
581 | public class Mocha extends CondimentDecorator {
582 | Beverage beverage;
583 | public Mocha(Beverage beverage) {
584 | this.beverage = beverage;
585 | }
586 | public String getDescription() {
587 | return beverage.getDescription() + “, Mocha”;
588 | }
589 | public double cost() {
590 | return .20 + beverage.cost();
591 | }
592 | }
593 | ```
594 | - And finally how we decorate objects in runtime:
595 | ```java
596 | public static void main(String args[]) {
597 | Beverage beverage = new Espresso();
598 | System.out.println(beverage.getDescription() +
599 | “$” + beverage.cost());
600 | Beverage beverage2 = new DarkRoast();
601 | beverage2 = new Mocha(beverage2);
602 | beverage2 = new Mocha(beverage2);
603 | beverage2 = new Whip(beverage2);
604 | System.out.println(beverage2.getDescription() +
605 | “$” + beverage2.cost());
606 | Beverage beverage3 = new HouseBlend();
607 | beverage3 = new Soy(beverage3);
608 | beverage3 = new Mocha(beverage3);
609 | beverage3 = new Whip(beverage3);
610 | System.out.println(beverage3.getDescription() +
611 | “$” + beverage3.cost());
612 | }
613 | ```
614 | - The output looks like:
615 |
616 | ```
617 | Espresso $1.99
618 | Dark Roast Coffee, Mocha, Mocha, Whip $1.49
619 | House Blend Coffee, Soy, Mocha, Whip $1.34
620 | ```
621 |
622 | [Back to top](#top)
623 |
624 |
625 |
626 | # Factory Pattern:
627 | - Simple Factory
628 | - Factory Method
629 | - Abstract Factory
630 |
631 | **Get started:** Write a program to support a pizza shop make their order process mroe smooth. This program supports creating many types of Pizza and be able to customized based on branches.
632 |
633 |
634 | **Naive approach:** As usual, we will come up with a `orderPizza` function like this, because to order a pizza, we need some mroe steps like prepare, bake, cut,... so we have:
635 |
636 | ```java
637 | Pizza orderPizza(){
638 | Pizza pizza = new Pizza();
639 |
640 | pizza.perpare();
641 | pizza.bake();
642 | pizze,cut();
643 | pizza.box();
644 | return pizza;
645 | }
646 | ```
647 |
648 | The class diagram looks like:
649 |
650 | **What if ..? :**
651 | - We need to add more pizze types. Then our `orderPizza` becomes:
652 | ```java
653 | Pizza orderPizza(String type){
654 | Pizza pizza;
655 |
656 | if (type.equals("cheese") pizza = new CheesePizza();
657 | else if (type.equals("geekl") pizza = new GeekPizza();
658 | else if (type.equals("cheese") pizza = new CheesePizza();
659 | else if (type.equals("clam") pizza = new ClamPizza();
660 |
661 | pizza.perpare();
662 | pizza.bake();
663 | pizze,cut();
664 | pizza.box();
665 | return pizza;
666 | }
667 | ```
668 |
669 | **Another approach:**
670 | - We can improve the code inside `orderPizza` function. AS you can see, we can separate the code for creating a pizza based on its type. Put the creation code to a separated class, and we have a simple factory. **This is not actually a Design Pattern but commonly used**
671 | ```java
672 | public class SimplePizzaFactory {
673 |
674 | public Pizza createPizza(String type) {
675 | Pizza pizza;
676 |
677 | if (type.equals("cheese") pizza = new CheesePizza();
678 | else if (type.equals("geekl") pizza = new GeekPizza();
679 | else if (type.equals("cheese") pizza = new CheesePizza();
680 | else if (type.equals("clam") pizza = new ClamPizza();
681 |
682 | return pizza;
683 | }
684 | }
685 | ```
686 |
687 | - The code for the PizzaStore class would look like:
688 |
689 | ```java
690 | public class PizzaStore {
691 | SimplePizzaFactory factory;
692 | public PizzaStore(SimplePizzaFactory factory) {
693 | this.factory = factory;
694 | }
695 | public Pizza orderPizza(String type) {
696 | Pizza pizza;
697 |
698 | pizza = factory.createPizza(type);
699 | pizza.perpare();
700 | pizza.bake();
701 | pizze,cut();
702 | pizza.box();
703 |
704 | return pizza;
705 | }
706 |
707 | }
708 | ```
709 | - The class diagram looks like:
710 |
711 | ```mermaid
712 | classDiagram
713 | SimplePizzaFactory *-- PizzaStore
714 | class PizzaStore{
715 | -SimplePizzaFactory factory
716 | +orderPizza()
717 | }
718 |
719 | class Pizza{
720 | +prepare()
721 | +bake()
722 | +cut()
723 | +box()
724 | }
725 |
726 | Pizza <|-- CheesePizza
727 | class CheesePizza{
728 | }
729 |
730 | Pizza <|-- GeekPizza
731 | class GeekPizza{
732 | }
733 |
734 | Pizza <|-- PeperoniPizza
735 | class PeperoniPizza{
736 | }
737 |
738 | Pizza <-- SimplePizzaFactory
739 | class SimplePizzaFactory{
740 | -Pizza factory
741 | +createPizza()
742 | }
743 |
744 | class SimplePizzaFactory{
745 | -Pizza factory
746 | +createPizza()
747 | }
748 |
749 | ```
750 | **Problem occurs:**
751 | - When we need to fanchise our PizzaStore to many places with many different types of Pizza. For example. New York style pizza, Chicago style Pizza. Now we need to build a framework to create the right type of pizza and also keep our process smooth. Because our Pizza Store is already stable.
752 | - A naive approach is that we can create factory object for each fanchise. For example: NYPizzaFactory, ChicagoPizzaFactory and whenever we need, just `new NYPizzaFactory()`
753 |
754 | **Better approach**
755 | - Make our PizzaStore class and the `createPizza` method `abstract` as well. Because our ordering process is stable so we just keep it as usual. If you want every fanchise has the same process, make it `final`.
756 | - Implement orderPizze method
757 | - Create other franchise pizza factory by subclass from PizzaStore, and override the createPizza method. Because our createrPizze is abstract, we force all concreate class override it and let subclass decide what type of pizza they create.
758 | The code:
759 | ```java
760 | public abstract class PizzaStore {
761 | public Pizza orderPizza(String type) {
762 | Pizza pizza;
763 |
764 | pizza = factory.createPizza(type);
765 | pizza.perpare();
766 | pizza.bake();
767 | pizze,cut();
768 | pizza.box();
769 |
770 | return pizza;
771 | }
772 |
773 | abstract Pizza createPizza(String type);
774 |
775 | }
776 | ```
777 |
778 | - Class diagram for franchise would look like:
779 |
780 | ```mermaid
781 | classDiagram
782 | class PizzaStore{
783 | +createPizza()
784 | +orderPizza()
785 | }
786 |
787 | PizzaStore <|-- NewYorkStylePizzaStore
788 | class NewYorkStylePizzaStore{
789 | +createPizza()
790 | }
791 |
792 | PizzaStore <|-- ChicagoStylePizzaStore
793 | class ChicagoStylePizzaStore{
794 | +createPizza()
795 | }
796 | ```
797 | - In each subclass of PizzaStore, let's say ChicagoStylePizzaStore, the `createPizze` method would look like:
798 |
799 | ```java
800 | public class ChicagoStylePizzaStore extends PizzaStore {
801 | Pizza createPizza(String item) {
802 | if (item.equals(“cheese”)) {
803 | return new NYStyleCheesePizza();
804 | } else if (item.equals(“veggie”)) {
805 | return new NYStyleVeggiePizza();
806 | } else if (item.equals(“clam”)) {
807 | return new NYStyleClamPizza();
808 | } else if (item.equals(“pepperoni”)) {
809 | return new NYStylePepperoniPizza();
810 | } else return null;
811 | }
812 | }
813 | ```
814 | The `createPizza` method above is called Factory method. Which is:
815 | - Abstract so that the subclass is counted to handle object creation
816 | - Returns data type used within methods declare in the superclass
817 | - Isolates the code in superclass from knowing what kind of object is actually created
818 |
819 | **Efficient approach:** Currently, our Pizza Store is fine. However, it is very hard to keep the ingredients of the pizza in every store at different regions the same. For example, the New Your store would use another ingredients for the tomato sauce, the Chicago store also do so. This is when we need to do something to make our ingredients set more flexible across region.
820 | Because of the fact that New York would use one set of ingredients, Chicago would use another. It's time we need to create families of ingredients.
821 | First, we need to create an IngredientsFactory to create each set of ingredients. If our stores in every region have the same behavior, consider using an `abstract` class. In this case, an `interface` is good enough. Our shared factory would look like:
822 |
823 | ```java
824 | public interface PizzaIngredientFactory {
825 | public Dough createDough();
826 | public Sauce createSauce();
827 | public Cheese createCheese();
828 | public Veggies[] createVeggies();
829 | public Pepperoni createPepperoni();
830 | public Clams createClam();
831 | }
832 | ```
833 | Next, we need to:
834 | - Build factory for each region
835 | - Implement set of ingredients class to be used with the factory
836 | - Hook the new factories to current Pizza Store
837 |
838 | Let's take the New York style for an example:
839 | ```java
840 | public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
841 | public Dough createDough() {
842 | return new ThinCrustDough();
843 | }
844 | public Sauce createSauce() {
845 | return new MarinaraSauce();
846 | }
847 | public Cheese createCheese() {
848 | return new ReggianoCheese();
849 | }
850 | public Veggies[] createVeggies() {
851 | Veggies veggies[] = {
852 | new Garlic(),
853 | new Onion(),
854 | new Mushroom(),
855 | new RedPepper()
856 | };
857 | return veggies;
858 | }
859 | public Pepperoni createPepperoni() {
860 | return new SlicedPepperoni();
861 | }
862 | public Clams createClam() {
863 | return new FreshClams();
864 | }
865 | }
866 | ```
867 | Remember that all the classed that being created should be the concrete class of the return type :)
868 | After that, our Pizza class becomes:
869 |
870 | ```java
871 | public abstract class Pizza {
872 | String name;
873 | Dough dough;
874 | Sauce sauce;
875 | Veggies veggies[];
876 | Cheese cheese;
877 | Pepperoni pepperoni;
878 | Clams clam;
879 | abstract void prepare();
880 | void bake() {
881 | System.out.println(“Bake for 25 minutes at 350”);
882 | }
883 | void cut() {
884 | System.out.println(“Cutting the pizza into diagonal slices”);
885 | }
886 | void box() {
887 | System.out.println(“Place pizza in official PizzaStore box”);
888 | }
889 | }
890 | ```
891 | Now that we have an abstraction of Pizza. So clean! Let's take a look on it's concrete classes:
892 | ```java
893 | public class CheesePizza extends Pizza {
894 | PizzaIngredientFactory ingredientFactory;
895 | public CheesePizza(PizzaIngredientFactory ingredientFactory) {
896 | this.ingredientFactory = ingredientFactory;
897 | }
898 | void prepare() {
899 | System.out.println(“Preparing“ + name);
900 | dough = ingredientFactory.createDough();
901 | sauce = ingredientFactory.createSauce();
902 | cheese = ingredientFactory.createCheese();
903 | }
904 | }
905 |
906 |
907 | public class ClamPizza extends Pizza {
908 | PizzaIngredientFactory ingredientFactory;
909 | public ClamPizza(PizzaIngredientFactory ingredientFactory) {
910 | this.ingredientFactory = ingredientFactory;
911 | }
912 | void prepare() {
913 | System.out.println(“Preparing“ + name);
914 | dough = ingredientFactory.createDough();
915 | sauce = ingredientFactory.createSauce();
916 | cheese = ingredientFactory.createCheese();
917 | clam = ingredientFactory.createClam();
918 | }
919 | }
920 |
921 | ```
922 |
923 |
924 | **Conclusion:**
925 | - **The Factory Method Pattern**: defines an interface for creating object but let subclass decide which class to instantiate.
926 | - **Dependency Inversion Principle**: depends uppon abstractions. Do not depend on concrete classes
927 |
928 | > **Note**: Guildline to follow Dependency Inversion Principle:
929 | > - No variable should hold a reference to a concrete class (If use `new`, which means holding a reference to concrete class. Should delegate to a factory)
930 | > - No class should derive from concrete class (If we derive from concrete class, we depends on it. Only depends on abstractions like abstract class or interface)
931 | > - No method should override implemented method of base class (If we override implemented method, the base class wasn't really an abstraction anymore. Those implemented methods are meant to be shared by all subclasses)
932 |
933 | [Back to top](#top)
934 |
935 |
936 |
937 | # Singleton Pattern:
938 | **Get started:** We need to create an object to be used everywhere. Make sure this object is one-of-a-kind.
939 |
940 | **Naive approach:** Create a class as the diagram below. Because we only need our object is only initialized when we need it, then we check null before returning initialize it. So simple:
941 | ```mermaid
942 | classDiagram
943 | class Singleton{
944 | - uniqueInstance: Singleton
945 | +getInstance(): Singleton
946 | }
947 | ```
948 |
949 | ```java
950 | public class Singleton {
951 | private static Singleton uniqueInstance;
952 | // other useful instance variables here
953 | private Singleton() {}
954 | public static Singleton getInstance() {
955 | if (uniqueInstance == null) {
956 | uniqueInstance = new Singleton();
957 | }
958 | return uniqueInstance;
959 | }
960 | // other useful methods here
961 | }
962 | ```
963 | **Problem occurs:**
964 | - What if we have more than one place use the singleton at the same time? More than one thread access to properties of the Singleton.
965 | - How do we handle this case? Some threads would have some conditions for the properties from Singleton to make the program run properly. Value of a property might be modified by a process while another is about to use the previous value.
966 | - If we do not handle this case for multi threads, it would lead to the situation where one thread always run wrongly and never give us the expected behavior
967 |
968 | **Better approach:** We need to do something to make sure that 'if a thread is about to access singleton, every other threads that access before should done their job'.
969 | We can do this by using `synchronized` keyword in Java:
970 |
971 | ```java
972 | public class Singleton {
973 | private static Singleton uniqueInstance;
974 | // other useful instance variables here
975 | private Singleton() {}
976 | public static synchronized Singleton getInstance() {
977 | if (uniqueInstance == null) {
978 | uniqueInstance = new Singleton();
979 | }
980 | return uniqueInstance;
981 | }
982 | // other useful methods here
983 | }
984 | ```
985 | > **Note**: The `synchronized` is only relevent by the time we initlaized the object. When we already have the object, we do not need to synchronize this method. Looks like synchronized is unnedded overhead
986 |
987 | **Efficient approach**: We have 3 options to consider to make sure our Singleton object works properly for every cases including multithreading one.
988 | 1. Keep the `synchronized` and leave the current one as is if the object initalization is not expensive to your application
989 | 2. Move to an eagerly created instance rather than a lazily one.
990 | Using this approach, we rely on the JVM to create the unique instance of the Singleton when the class is loaded. The JVM guarantees that the instance will be created before any thread accesses the static uniqueInstance variable
991 | ```java
992 | public class Singleton {
993 | private static Singleton uniqueInstance = new Singleton();
994 | private Singleton() {}
995 | public static Singleton getInstance() {
996 | return uniqueInstance;
997 | }
998 | }
999 | ```
1000 | 3. Use “double-checked locking” to reduce the use of synchronization in getInstance()
1001 | With double-checked locking, we first check to see if an instance is created, and if not, THEN we
1002 | synchronize. This way, we only synchronize the first time through, just what we want
1003 | ```java
1004 | public class Singleton {
1005 | private volatile static Singleton uniqueInstance;
1006 | private Singleton() {}
1007 | public static Singleton getInstance() {
1008 | if (uniqueInstance == null) {
1009 | synchronized(Singleton.class) {
1010 | if (uniqueInstance == null) {
1011 | uniqueInstance = new Singleton();
1012 | }
1013 | }
1014 | }
1015 | return uniqueInstance;
1016 | }
1017 | }
1018 | ```
1019 | > **Note**: The volatile keyword ensures that multiple threads handle the uniqueInstance variable correctly when it is being initialized to the Singleton instance
1020 |
1021 | **Conclusion:**
1022 | - **The Singleton Pattern** : ensures a class has only one instance, and provides a global point of access to it
1023 |
1024 |
1025 | [Back to top](#top)
1026 |
1027 |
1028 |
1029 | # Command Pattern:
1030 | **Get started:** Given that we want to build an API to support a remote control to control our smart home devices. This API would allow the remote to interact with the classes provided by the devices vendor. In general, this control will have some slots, each slot would allow you to control a device. For each device, you can perform turn on, turn off and other actions.
1031 | The classes provided are something like:
1032 |
1033 | **Initial thought**: With OO Principles in our hands, our initial though is that we should do something to make sure that the remote does not know much about the details of how to turn on or turn off a light. It should request throught another helper to make it do it.
1034 | We also need to avoid if statements like `if slot1 == Light then turnOff() else if slot1 == GarageDoor then scrollDown()`. This approach will lead to lot of changes when we need to add more devices. More work and more bugs.
1035 |
1036 | **Approach:** Alright, now we have to do some thing to make the remote coltrol requests for what it want and another helper make the work done. This is quite similar to the way we request an order in restaurant. Let's take this as an example before we jump in to the pattern.
1037 | The order process looks like:
1038 | ```mermaid
1039 | flowchart LR
1040 | Customer-- createOrder -->Waitress --takeOrder, orderUp-->Cook--makeBurger, makeDrink -->Dish
1041 | ```
1042 | The waitress will receive order from customer, then bring it to the Cook, tell him to cook. After that, the cook will make the dishes following the list inside the order.
1043 | Back to our case, the remote control need to create requests to `another class` to execute, and inside the execute of `another class`, we will call the exact method of each class provided from vendors.
1044 | Let's take a look at this diagram:
1045 |
1046 | ```mermaid
1047 | classDiagram
1048 |
1049 | Receiver <-- Client
1050 | ConcreteCommand <-- Client
1051 | class Client{
1052 | }
1053 |
1054 | Receiver <-- ConcreteCommand
1055 | class Receiver{
1056 | }
1057 |
1058 | Command <-- Invoker
1059 | class Invoker{
1060 | }
1061 |
1062 | class Command{
1063 | <>
1064 | +execute()
1065 | +undo()
1066 | }
1067 | Command <.. ConcreteCommand
1068 | class ConcreteCommand{
1069 | +execute()
1070 | +undo()
1071 | }
1072 | ```
1073 | In general, this is how it works:
1074 |
1075 | ```mermaid
1076 | flowchart LR
1077 | Client-- createCommandObject, setCommand --> Invoker --execute--> Receiver
1078 | ```
1079 |
1080 | [Back to top](#top)
1081 |
1082 |
1083 | # Adapter and Facade Pattern:
1084 |
1085 |
1086 |
1087 |
1088 |
1089 |
--------------------------------------------------------------------------------