├── .doc
├── 01-strategy-pattern.png
├── 02-observer-pattern.png
├── 03-decorator-pattern.png
├── 04-abstract-factory-pattern.png
├── 04-factory-method-pattern.png
├── 05-singleton-pattern.png
├── 06-command-pattern.png
├── 07-adapter-pattern.png
├── 07-facade-pattern.png
├── 07-principle-of-least-knowledge-1.png
├── 07-principle-of-least-knowledge-2.png
├── 08-hollywood-principle.png
├── 08-template-method-pattern.png
├── 09-composite-pattern.png
├── 09-iterator-pattern.png
├── 09-menu-requirement.png
├── 09-tree-structure.png
├── 10-class-diagram.png
├── 10-state-diagram.png
├── 11-protection-proxy.png
├── 11-proxy-pattern.png
├── 11-remote-proxy.png
├── 11-virtual-proxy.png
└── 12-mvc-pattern.png
├── .gitignore
├── 01-strategy
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── intro
│ ├── DuckSimulator.java
│ ├── algorithm
│ ├── implementation
│ │ ├── FlyWithRockets.java
│ │ ├── FlyWithWings.java
│ │ ├── MuteQuack.java
│ │ ├── Quack.java
│ │ └── Squeak.java
│ └── interfaces
│ │ ├── IFlyBehavior.java
│ │ └── IQuackBehavior.java
│ └── model
│ ├── Duck.java
│ ├── MallardDuck.java
│ └── RubberDuck.java
├── 02-observer
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── observerpattern
│ ├── WeatherStation.java
│ ├── observer
│ ├── CurrentConditionsDisplay.java
│ ├── ForecastDisplay.java
│ ├── HeatIndexDisplay.java
│ ├── IDisplayElement.java
│ ├── IObserver.java
│ └── StatisticsDisplay.java
│ └── subject
│ ├── ISubject.java
│ └── WeatherData.java
├── 03-decorator
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── decoratorpattern
│ ├── StarbuzzCoffee.java
│ ├── component
│ ├── Beverage.java
│ ├── DarkRoast.java
│ ├── Decaf.java
│ ├── Espresso.java
│ └── HouseBlend.java
│ └── decorator
│ ├── CondimentDecorator.java
│ ├── Mocha.java
│ ├── Soy.java
│ ├── SteamedMilk.java
│ └── Whip.java
├── 04-factory
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── factorypattern
│ ├── PizzaTestDrive.java
│ ├── creator
│ ├── ingredient
│ │ ├── ChicagoIngredientFactory.java
│ │ ├── IPizzaIngredientFactory.java
│ │ └── NYPizzaIngredientFactory.java
│ └── pizza
│ │ ├── ChicagoPizzaStore.java
│ │ ├── NYPizzaStore.java
│ │ ├── PizzaStore.java
│ │ └── PizzaType.java
│ └── product
│ ├── ingredient
│ ├── BlackOlives.java
│ ├── EggPlant.java
│ ├── FreshClams.java
│ ├── FrozenClams.java
│ ├── Garlic.java
│ ├── ICheese.java
│ ├── IClams.java
│ ├── IDough.java
│ ├── IPepperoni.java
│ ├── ISauce.java
│ ├── IVeggies.java
│ ├── MarinaraSauce.java
│ ├── MozzarellaCheese.java
│ ├── Mushroom.java
│ ├── Onion.java
│ ├── PlumTomatoSauce.java
│ ├── RedPepper.java
│ ├── ReggianoCheese.java
│ ├── SlicedPepperoni.java
│ ├── Spinach.java
│ ├── ThickCrustDough.java
│ └── ThinCrustDough.java
│ └── pizza
│ ├── CheesePizza.java
│ ├── ClamPizza.java
│ └── Pizza.java
├── 05-singleton
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── singletonpattern
│ ├── ChocolateBoiler.java
│ └── ChocolateBoilerController.java
├── 06-command
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── commandpattern
│ ├── Location.java
│ ├── RemoteControl.java
│ ├── RemoteControlTest.java
│ ├── RemoteControlTestWithMacro.java
│ ├── RemoteControlTestWithUndo.java
│ ├── command
│ ├── CeilingFanCommand.java
│ ├── CeilingFanHighCommand.java
│ ├── CeilingFanLowCommand.java
│ ├── CeilingFanMediumCommand.java
│ ├── CeilingFanOffCommand.java
│ ├── GarageDoorDownCommand.java
│ ├── GarageDoorUpCommand.java
│ ├── HottubOffCommand.java
│ ├── HottubOnCommand.java
│ ├── ICommand.java
│ ├── LightOffCommand.java
│ ├── LightOnCommand.java
│ ├── MacroCommand.java
│ ├── NoCommand.java
│ ├── StereoOffCommand.java
│ └── StereoOnWithCDCommand.java
│ └── receiver
│ ├── CeilingFan.java
│ ├── GarageDoor.java
│ ├── Hottub.java
│ ├── Light.java
│ └── Stereo.java
├── 07-adapter-facade
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ ├── adapterpattern
│ ├── Duck.java
│ ├── DuckAdapter.java
│ ├── DuckTestDrive.java
│ ├── MallardDuck.java
│ ├── Turkey.java
│ ├── TurkeyAdapter.java
│ └── WildTurkey.java
│ └── facadepattern
│ ├── Amplifier.java
│ ├── CdPlayer.java
│ ├── HomeTheaterFacade.java
│ ├── HomeTheaterTestDrive.java
│ ├── PopcornPopper.java
│ ├── Projector.java
│ ├── Screen.java
│ ├── StreamingPlayer.java
│ ├── TheaterLights.java
│ └── Tuner.java
├── 08-template-method
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── templatemethod
│ ├── beveragetest
│ ├── BeverageTestDrive.java
│ ├── CaffeineBeverage.java
│ ├── Coffee.java
│ ├── GetUserInputUtil.java
│ └── Tea.java
│ └── ducksorttest
│ ├── Duck.java
│ └── DuckSortTestDrive.java
├── 09-iterator-composite
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── iteratorcomposite
│ ├── composite
│ ├── Menu.java
│ ├── MenuComponent.java
│ ├── MenuItem.java
│ ├── MenuTestDrive.java
│ └── Waitress.java
│ └── iterator
│ ├── CafeMenu.java
│ ├── DinerMenu.java
│ ├── DinerMenuIterator.java
│ ├── Menu.java
│ ├── MenuItem.java
│ ├── MenuTestDrive.java
│ ├── PancakeHouseMenu.java
│ └── Waitress.java
├── 10-state
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── statepattern
│ ├── GumballMachineTestDrive.java
│ ├── context
│ └── GumballMachine.java
│ └── state
│ ├── GumballMachineState.java
│ ├── HasQuarterState.java
│ ├── NoQuarterState.java
│ ├── SoldOutState.java
│ ├── SoldState.java
│ └── WinnerState.java
├── 11-proxy
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── proxypattern
│ ├── protectionproxy
│ ├── MatchMakingTestDrive.java
│ ├── handler
│ │ ├── NonOwnerInvocationHandler.java
│ │ └── OwnerInvocationHandler.java
│ ├── proxy
│ │ └── PersonProxy.java
│ └── subject
│ │ ├── Person.java
│ │ └── PersonImpl.java
│ └── remoteproxy
│ ├── GumballMachineTestDrive.java
│ ├── GumballMonitorTestDrive.java
│ ├── context
│ ├── GumballMachine.java
│ ├── GumballMachineRemote.java
│ └── GumballMonitor.java
│ └── state
│ ├── GumballMachineState.java
│ ├── HasQuarterState.java
│ ├── NoQuarterState.java
│ ├── SoldOutState.java
│ ├── SoldState.java
│ └── WinnerState.java
├── 12-compound
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── example
│ └── compound
│ ├── DuckSimulator.java
│ ├── DuckSimulatorTestDrive.java
│ ├── action
│ └── Quackable.java
│ ├── adapter
│ └── GooseAdapter.java
│ ├── animal
│ ├── duck
│ │ ├── DuckCall.java
│ │ ├── Flock.java
│ │ ├── MallardDuck.java
│ │ ├── RedheadDuck.java
│ │ └── RubberDuck.java
│ └── goose
│ │ └── Goose.java
│ ├── decorator
│ └── QuackCounter.java
│ ├── factory
│ ├── AbstractDuckFactory.java
│ ├── CountingDuckFactory.java
│ └── DuckFactory.java
│ ├── observer
│ ├── Observer.java
│ └── Quackologist.java
│ └── subject
│ ├── Observable.java
│ └── QuackObservable.java
├── README.md
└── pom.xml
/.doc/01-strategy-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/01-strategy-pattern.png
--------------------------------------------------------------------------------
/.doc/02-observer-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/02-observer-pattern.png
--------------------------------------------------------------------------------
/.doc/03-decorator-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/03-decorator-pattern.png
--------------------------------------------------------------------------------
/.doc/04-abstract-factory-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/04-abstract-factory-pattern.png
--------------------------------------------------------------------------------
/.doc/04-factory-method-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/04-factory-method-pattern.png
--------------------------------------------------------------------------------
/.doc/05-singleton-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/05-singleton-pattern.png
--------------------------------------------------------------------------------
/.doc/06-command-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/06-command-pattern.png
--------------------------------------------------------------------------------
/.doc/07-adapter-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/07-adapter-pattern.png
--------------------------------------------------------------------------------
/.doc/07-facade-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/07-facade-pattern.png
--------------------------------------------------------------------------------
/.doc/07-principle-of-least-knowledge-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/07-principle-of-least-knowledge-1.png
--------------------------------------------------------------------------------
/.doc/07-principle-of-least-knowledge-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/07-principle-of-least-knowledge-2.png
--------------------------------------------------------------------------------
/.doc/08-hollywood-principle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/08-hollywood-principle.png
--------------------------------------------------------------------------------
/.doc/08-template-method-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/08-template-method-pattern.png
--------------------------------------------------------------------------------
/.doc/09-composite-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/09-composite-pattern.png
--------------------------------------------------------------------------------
/.doc/09-iterator-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/09-iterator-pattern.png
--------------------------------------------------------------------------------
/.doc/09-menu-requirement.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/09-menu-requirement.png
--------------------------------------------------------------------------------
/.doc/09-tree-structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/09-tree-structure.png
--------------------------------------------------------------------------------
/.doc/10-class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/10-class-diagram.png
--------------------------------------------------------------------------------
/.doc/10-state-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/10-state-diagram.png
--------------------------------------------------------------------------------
/.doc/11-protection-proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/11-protection-proxy.png
--------------------------------------------------------------------------------
/.doc/11-proxy-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/11-proxy-pattern.png
--------------------------------------------------------------------------------
/.doc/11-remote-proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/11-remote-proxy.png
--------------------------------------------------------------------------------
/.doc/11-virtual-proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/11-virtual-proxy.png
--------------------------------------------------------------------------------
/.doc/12-mvc-pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinhQuan992/design-patterns/e3fa3cc0b10145ad2a43e47a474a3a655cd4b113/.doc/12-mvc-pattern.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.iml
3 | target/
--------------------------------------------------------------------------------
/01-strategy/README.md:
--------------------------------------------------------------------------------
1 | # THE STRATEGY PATTERN
2 |
3 | ## 1. The Problem
4 | You are making a Duck Simulator application. Started, all of your ducks had only two behaviors: `swim` and `display`.
5 |
6 | Currently, your customers want your ducks to be able to `fly` and `quack`. However, the `fly` behavior varies among your ducks:
7 |
8 | - Some ducks typically fly with two wings.
9 | - Some special ducks fly with many rockets.
10 | - Some other ducks can not fly.
11 |
12 | The same problem occurs with the `quack` behavior. How will you deal with it?
13 |
14 | ## 2. The Definition of Strategy Pattern
15 |
16 | **The Strategy Pattern** defines a family of algorithms,
17 | encapsulates each one, and makes them interchangeable.
18 | Strategy lets the algorithm vary independently from
19 | clients that use it.
20 |
21 | ## 3. Demo Diagram
22 |
23 | 
--------------------------------------------------------------------------------
/01-strategy/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 01-strategy
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/DuckSimulator.java:
--------------------------------------------------------------------------------
1 | package org.example.intro;
2 |
3 | import org.example.intro.algorithm.implementation.FlyWithRockets;
4 | import org.example.intro.algorithm.implementation.FlyWithWings;
5 | import org.example.intro.algorithm.implementation.MuteQuack;
6 | import org.example.intro.algorithm.implementation.Quack;
7 | import org.example.intro.algorithm.implementation.Squeak;
8 | import org.example.intro.model.Duck;
9 | import org.example.intro.model.MallardDuck;
10 | import org.example.intro.model.RubberDuck;
11 |
12 | public class DuckSimulator {
13 | public static void main(String[] args) {
14 | FlyWithWings flyWithWings = new FlyWithWings();
15 | FlyWithRockets flyWithRockets = new FlyWithRockets();
16 |
17 | Quack quack = new Quack();
18 | Squeak squeak = new Squeak();
19 | MuteQuack muteQuack = new MuteQuack();
20 |
21 | MallardDuck mallardDuck = new MallardDuck(flyWithWings, quack);
22 | performActions(mallardDuck);
23 |
24 | System.out.println();
25 |
26 | RubberDuck rubberDuck = new RubberDuck(flyWithRockets, squeak);
27 | performActions(rubberDuck);
28 |
29 | // Change rubberDuck's quack behavior at runtime
30 | rubberDuck.setQuackBehavior(muteQuack);
31 | System.out.println("\nRubber Duck's quack behavior has been changed");
32 | performActions(rubberDuck);
33 | }
34 |
35 | private static void performActions(Duck duck) {
36 | duck.display();
37 | duck.swim();
38 | duck.performFly();
39 | duck.performQuack();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/implementation/FlyWithRockets.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.implementation;
2 |
3 | import org.example.intro.algorithm.interfaces.IFlyBehavior;
4 |
5 | public class FlyWithRockets implements IFlyBehavior {
6 | @Override
7 | public void fly() {
8 | System.out.println("I fly with two rockets. Hahaha!!!");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/implementation/FlyWithWings.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.implementation;
2 |
3 | import org.example.intro.algorithm.interfaces.IFlyBehavior;
4 |
5 | public class FlyWithWings implements IFlyBehavior {
6 | @Override
7 | public void fly() {
8 | System.out.println("I'm a duck flying with two wings!");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/implementation/MuteQuack.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.implementation;
2 |
3 | import org.example.intro.algorithm.interfaces.IQuackBehavior;
4 |
5 | public class MuteQuack implements IQuackBehavior {
6 | @Override
7 | public void quack() {
8 | System.out.println("...");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/implementation/Quack.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.implementation;
2 |
3 | import org.example.intro.algorithm.interfaces.IQuackBehavior;
4 |
5 | public class Quack implements IQuackBehavior {
6 | @Override
7 | public void quack() {
8 | System.out.println("Quack...Quack...Quack...");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/implementation/Squeak.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.implementation;
2 |
3 | import org.example.intro.algorithm.interfaces.IQuackBehavior;
4 |
5 | public class Squeak implements IQuackBehavior {
6 | @Override
7 | public void quack() {
8 | System.out.println("Squeak...Squeak...Squeak...");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/interfaces/IFlyBehavior.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.interfaces;
2 |
3 | public interface IFlyBehavior {
4 | void fly();
5 | }
6 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/algorithm/interfaces/IQuackBehavior.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.algorithm.interfaces;
2 |
3 | public interface IQuackBehavior {
4 | void quack();
5 | }
6 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/model/Duck.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.model;
2 |
3 | import org.example.intro.algorithm.interfaces.IFlyBehavior;
4 | import org.example.intro.algorithm.interfaces.IQuackBehavior;
5 |
6 | public abstract class Duck {
7 | private IFlyBehavior flyBehavior;
8 | private IQuackBehavior quackBehavior;
9 |
10 | public Duck(IFlyBehavior flyBehavior, IQuackBehavior quackBehavior) {
11 | this.flyBehavior = flyBehavior;
12 | this.quackBehavior = quackBehavior;
13 | }
14 |
15 | public abstract void display();
16 |
17 | public void swim() {
18 | System.out.println("I'm a duck. I can swim!!!");
19 | }
20 |
21 | // DELEGATE its flying behavior
22 | public void performFly() {
23 | flyBehavior.fly();
24 | }
25 |
26 | // DELEGATE its quack behavior
27 | public void performQuack() {
28 | quackBehavior.quack();
29 | }
30 |
31 | public void setFlyBehavior(IFlyBehavior flyBehavior) {
32 | this.flyBehavior = flyBehavior;
33 | }
34 |
35 | public void setQuackBehavior(IQuackBehavior quackBehavior) {
36 | this.quackBehavior = quackBehavior;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/model/MallardDuck.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.model;
2 |
3 | import org.example.intro.algorithm.interfaces.IFlyBehavior;
4 | import org.example.intro.algorithm.interfaces.IQuackBehavior;
5 | import org.example.intro.model.Duck;
6 |
7 | public class MallardDuck extends Duck {
8 | public MallardDuck(IFlyBehavior flyBehavior, IQuackBehavior quackBehavior) {
9 | super(flyBehavior, quackBehavior);
10 | }
11 |
12 | @Override
13 | public void display() {
14 | System.out.println("I'm a real Mallard Duck!");
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/01-strategy/src/main/java/org/example/intro/model/RubberDuck.java:
--------------------------------------------------------------------------------
1 | package org.example.intro.model;
2 |
3 | import org.example.intro.algorithm.interfaces.IFlyBehavior;
4 | import org.example.intro.algorithm.interfaces.IQuackBehavior;
5 |
6 | public class RubberDuck extends Duck{
7 | public RubberDuck(IFlyBehavior flyBehavior, IQuackBehavior quackBehavior) {
8 | super(flyBehavior, quackBehavior);
9 | }
10 |
11 | @Override
12 | public void display() {
13 | System.out.println("Hello World! I'm a cute rubber duck!!!");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/02-observer/README.md:
--------------------------------------------------------------------------------
1 | # THE OBSERVER PATTERN
2 | ## Keeping your Objects in the Know
3 |
4 | ## 1. The Problem
5 |
6 | Your team has been selected to build a Weather Monitoring application for the Weather-O-Rama company.
7 |
8 | Currently, Weather-O-Rama's developers provide your team with the `WeatherData` object, which talks to their physical Weather Station to get updated weather data: `temperature`, `humidity`, and `pressure`.
9 |
10 | Based on the contract, your team needs to build three display elements to show on display devices:
11 | - Current Conditions (show the weather data values).
12 | - Weather Statistics.
13 | - A simple Forecast.
14 |
15 | Each display element gets weather data, calculating according to their business and delivering the result on devices.
16 |
17 | The CEO of Weather-O-Rama also wants their application to expand quickly by **allowing other third parties to build their own displays**.
18 |
19 | How will your team build this application? Don't forget that Weather-O-Rama's Weather Station may provide more types of weather data in the future.
20 |
21 | ## 2. The Definition of Observer Pattern
22 | 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.
23 |
24 | ## 3. Demo Diagram
25 | 
26 |
27 | ## 4. Makes use of OO Design Principles
28 |
29 | (Head First Design Patterns, 2nd Edition, pages 54 and 75)
30 |
31 | **Encapsulate what varies**
32 |
33 | The thing that varies in the Observer Pattern is the **state** of the Subject and the **number** and **types** of Observers. With this pattern, you can vary the objects that are dependent on the state of the Subject, without having to change that Subject.
34 |
35 | **Program to an interface, not an implementation**
36 |
37 | Both the Subject and Observers use interfaces. The Subject keeps track of objects implementing the Observer interface, while the Observers register with, and get notified by, the Subject interface.
38 |
39 | **Favor composition over inheritance**
40 |
41 | The Observer Pattern uses composition to compose any number of Observers with their Subject. These relationships aren't set up by some kind of inheritance hierarchy. They are set up at runtime by composition.
42 |
43 | **Strive for loosely coupled designs between objects that interact**
44 |
45 | - The only thing the subject knows about an observer is that it implements a certain interface (the Observer interface).
46 | - We can add new observers at any time.
47 | - We never need to modify the subject to add new types of observers.
48 | - We can reuse subjects or observers independently of each other.
49 | - Changes to either the subject or an observer will not affect the other.
--------------------------------------------------------------------------------
/02-observer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 02-observer
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/WeatherStation.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern;
2 |
3 | import org.example.observerpattern.observer.CurrentConditionsDisplay;
4 | import org.example.observerpattern.observer.ForecastDisplay;
5 | import org.example.observerpattern.observer.HeatIndexDisplay;
6 | import org.example.observerpattern.observer.StatisticsDisplay;
7 | import org.example.observerpattern.subject.WeatherData;
8 |
9 | public class WeatherStation {
10 | public static void main(String[] args) {
11 | WeatherData weatherData = new WeatherData();
12 |
13 | new CurrentConditionsDisplay(weatherData);
14 | new StatisticsDisplay(weatherData);
15 | new ForecastDisplay(weatherData);
16 | HeatIndexDisplay heatIndexDisplay = new HeatIndexDisplay(weatherData);
17 |
18 | weatherData.setMeasurements(80, 65, 30.4f);
19 | System.out.println();
20 | weatherData.setMeasurements(82, 70, 29.2f);
21 | System.out.println();
22 | weatherData.removeObserver(heatIndexDisplay);
23 | weatherData.setMeasurements(78, 90, 29.2f);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/observer/CurrentConditionsDisplay.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.observer;
2 |
3 | import org.example.observerpattern.subject.WeatherData;
4 |
5 | public class CurrentConditionsDisplay implements IObserver, IDisplayElement {
6 | private final WeatherData weatherData;
7 | private float temperature;
8 | private float humidity;
9 |
10 | public CurrentConditionsDisplay(WeatherData weatherData) {
11 | this.weatherData = weatherData;
12 | weatherData.registerObserver(this);
13 | }
14 |
15 | @Override
16 | public void update() {
17 | this.temperature = weatherData.getTemperature();
18 | this.humidity = weatherData.getHumidity();
19 | display();
20 | }
21 |
22 | @Override
23 | public void display() {
24 | System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/observer/ForecastDisplay.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.observer;
2 |
3 | import org.example.observerpattern.subject.WeatherData;
4 |
5 | public class ForecastDisplay implements IObserver, IDisplayElement {
6 | private final WeatherData weatherData;
7 | private float currentPressure = 29.9f;
8 | private float lastPressure;
9 |
10 | public ForecastDisplay(WeatherData weatherData) {
11 | this.weatherData = weatherData;
12 | weatherData.registerObserver(this);
13 | }
14 |
15 | @Override
16 | public void update() {
17 | lastPressure = currentPressure;
18 | currentPressure = weatherData.getPressure();
19 | display();
20 | }
21 |
22 | @Override
23 | public void display() {
24 | System.out.print("Forecast: ");
25 | if (currentPressure > lastPressure) {
26 | System.out.println("Improving weather on the way");
27 | } else if (currentPressure == lastPressure) {
28 | System.out.println("More of the same");
29 | } else {
30 | System.out.println("Watch out for cooler, rainy weather");
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/observer/HeatIndexDisplay.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.observer;
2 |
3 | import org.example.observerpattern.subject.WeatherData;
4 |
5 | public class HeatIndexDisplay implements IObserver, IDisplayElement {
6 | private final WeatherData weatherData;
7 | private float temperature;
8 | private float relativeHumidity;
9 |
10 | public HeatIndexDisplay(WeatherData weatherData) {
11 | this.weatherData = weatherData;
12 | weatherData.registerObserver(this);
13 | }
14 |
15 | private float computeHeatIndex(float t, float rh) {
16 | return (float)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) +
17 | (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) +
18 | (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
19 | (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *
20 | (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
21 | (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
22 | 0.000000000843296 * (t * t * rh * rh * rh)) -
23 | (0.0000000000481975 * (t * t * t * rh * rh * rh)));
24 | }
25 |
26 | @Override
27 | public void update() {
28 | this.temperature = weatherData.getTemperature();
29 | this.relativeHumidity = weatherData.getHumidity();
30 | display();
31 | }
32 |
33 | @Override
34 | public void display() {
35 | System.out.printf("Heat index is %.5f\n", computeHeatIndex(temperature, relativeHumidity));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/observer/IDisplayElement.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.observer;
2 |
3 | public interface IDisplayElement {
4 | void display();
5 | }
6 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/observer/IObserver.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.observer;
2 |
3 | public interface IObserver {
4 | void update();
5 | }
6 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/observer/StatisticsDisplay.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.observer;
2 |
3 | import org.example.observerpattern.subject.WeatherData;
4 |
5 | public class StatisticsDisplay implements IObserver, IDisplayElement {
6 | private final WeatherData weatherData;
7 | private float maxTemperature = 0.0f;
8 | private float minTemperature = 200;
9 | private float temperatureSum = 0.0f;
10 | private int numberOfReadings;
11 |
12 | public StatisticsDisplay(WeatherData weatherData) {
13 | this.weatherData = weatherData;
14 | weatherData.registerObserver(this);
15 | }
16 |
17 | @Override
18 | public void update() {
19 | float temp = weatherData.getTemperature();
20 | temperatureSum += temp;
21 | numberOfReadings++;
22 | if (temp > maxTemperature) {
23 | maxTemperature = temp;
24 | }
25 | if (temp < minTemperature) {
26 | minTemperature = temp;
27 | }
28 | display();
29 | }
30 |
31 | @Override
32 | public void display() {
33 | System.out.printf("Avg/Max/Min temperature: %.1f/%.1f/%.1f%n", temperatureSum / numberOfReadings, maxTemperature, minTemperature);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/subject/ISubject.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.subject;
2 |
3 | import org.example.observerpattern.observer.IObserver;
4 |
5 | public interface ISubject {
6 | void registerObserver(IObserver observer);
7 | void removeObserver(IObserver observer);
8 | void notifyObservers();
9 | }
10 |
--------------------------------------------------------------------------------
/02-observer/src/main/java/org/example/observerpattern/subject/WeatherData.java:
--------------------------------------------------------------------------------
1 | package org.example.observerpattern.subject;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import lombok.Getter;
6 | import org.example.observerpattern.observer.IObserver;
7 |
8 | @Getter
9 | public class WeatherData implements ISubject {
10 | private final List observers;
11 | private float temperature;
12 | private float humidity;
13 | private float pressure;
14 |
15 | public WeatherData() {
16 | observers = new ArrayList<>();
17 | }
18 |
19 | @Override
20 | public void registerObserver(IObserver observer) {
21 | observers.add(observer);
22 | }
23 |
24 | @Override
25 | public void removeObserver(IObserver observer) {
26 | observers.remove(observer);
27 | }
28 |
29 | @Override
30 | public void notifyObservers() {
31 | for (IObserver observer : observers) {
32 | observer.update();
33 | }
34 | }
35 |
36 | public void measurementsChanged() {
37 | notifyObservers();
38 | }
39 |
40 | public void setMeasurements(float temperature, float humidity, float pressure) {
41 | this.temperature = temperature;
42 | this.humidity = humidity;
43 | this.pressure = pressure;
44 | measurementsChanged();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/03-decorator/README.md:
--------------------------------------------------------------------------------
1 | # THE DECORATOR PATTERN
2 | ## Decorating Objects
3 |
4 | ## 1. The Problem
5 |
6 | The owner of Starbuzz Coffee needs to build an order system for his coffee store chain. According to his business, each coffee store serves lots of coffee types. They also provide many condiments used with each cup of coffee. Each order's total cost is based on which kind of coffee and how many condiments the customer orders. How will you build a system that meets his requirements?
7 |
8 | ## 2. The Definition of Decorator Pattern
9 |
10 | **The Decorator Pattern** attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
11 |
12 | ## 3. Demo Diagram
13 |
14 | 
--------------------------------------------------------------------------------
/03-decorator/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 03-decorator
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/StarbuzzCoffee.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern;
2 |
3 | import org.example.decoratorpattern.component.Beverage;
4 | import org.example.decoratorpattern.component.DarkRoast;
5 | import org.example.decoratorpattern.component.Espresso;
6 | import org.example.decoratorpattern.component.HouseBlend;
7 | import org.example.decoratorpattern.decorator.Mocha;
8 | import org.example.decoratorpattern.decorator.Soy;
9 | import org.example.decoratorpattern.decorator.Whip;
10 |
11 | public class StarbuzzCoffee {
12 | public static void main(String[] args) {
13 | String outputFormat = "%s $%.2f%n";
14 | Beverage espresso = new Espresso();
15 | System.out.printf(outputFormat, espresso.getDescription(), espresso.cost());
16 |
17 | // TODO: improve the way of creating decorated objects by using Factory or Builder pattern
18 | Beverage darkRoast = new DarkRoast();
19 | darkRoast = new Mocha(darkRoast);
20 | darkRoast = new Mocha(darkRoast);
21 | darkRoast = new Whip(darkRoast);
22 | System.out.printf(outputFormat, darkRoast.getDescription(), darkRoast.cost());
23 |
24 | Beverage houseBlend = new HouseBlend();
25 | houseBlend = new Soy(houseBlend);
26 | houseBlend = new Mocha(houseBlend);
27 | houseBlend = new Whip(houseBlend);
28 | System.out.printf(outputFormat, houseBlend.getDescription(), houseBlend.cost());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/component/Beverage.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.component;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public abstract class Beverage {
7 | protected String description = "Unknown Beverage";
8 |
9 | public abstract double cost();
10 | }
11 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/component/DarkRoast.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.component;
2 |
3 | public class DarkRoast extends Beverage {
4 | public DarkRoast() {
5 | description = "Dark Roast Coffee";
6 | }
7 |
8 | @Override
9 | public double cost() {
10 | return .99;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/component/Decaf.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.component;
2 |
3 | public class Decaf extends Beverage {
4 | public Decaf() {
5 | description = "Decaf Coffee";
6 | }
7 |
8 | @Override
9 | public double cost() {
10 | return 1.05;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/component/Espresso.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.component;
2 |
3 | public class Espresso extends Beverage {
4 | public Espresso() {
5 | description = "Espresso";
6 | }
7 |
8 | @Override
9 | public double cost() {
10 | return 1.99;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/component/HouseBlend.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.component;
2 |
3 | public class HouseBlend extends Beverage {
4 | public HouseBlend() {
5 | description = "House Blend Coffee";
6 | }
7 |
8 | @Override
9 | public double cost() {
10 | return .89;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/decorator/CondimentDecorator.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.decorator;
2 |
3 | import org.example.decoratorpattern.component.Beverage;
4 |
5 | public abstract class CondimentDecorator extends Beverage {
6 | protected Beverage beverage;
7 |
8 | public CondimentDecorator(Beverage beverage) {
9 | this.beverage = beverage;
10 | }
11 |
12 | public abstract String getDescription();
13 | }
14 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/decorator/Mocha.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.decorator;
2 |
3 | import org.example.decoratorpattern.component.Beverage;
4 |
5 | public class Mocha extends CondimentDecorator {
6 | public Mocha(Beverage beverage) {
7 | super(beverage);
8 | }
9 |
10 | @Override
11 | public double cost() {
12 | return beverage.cost() + .20;
13 | }
14 |
15 | @Override
16 | public String getDescription() {
17 | return beverage.getDescription() + ", Mocha";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/decorator/Soy.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.decorator;
2 |
3 | import org.example.decoratorpattern.component.Beverage;
4 |
5 | public class Soy extends CondimentDecorator {
6 | public Soy(Beverage beverage) {
7 | super(beverage);
8 | }
9 |
10 | @Override
11 | public double cost() {
12 | return beverage.cost() + .15;
13 | }
14 |
15 | @Override
16 | public String getDescription() {
17 | return beverage.getDescription() + ", Soy";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/decorator/SteamedMilk.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.decorator;
2 |
3 | import org.example.decoratorpattern.component.Beverage;
4 |
5 | public class SteamedMilk extends CondimentDecorator {
6 | public SteamedMilk(Beverage beverage) {
7 | super(beverage);
8 | }
9 |
10 | @Override
11 | public double cost() {
12 | return beverage.cost() + .10;
13 | }
14 |
15 | @Override
16 | public String getDescription() {
17 | return beverage.getDescription() + ", Steamed Milk";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/03-decorator/src/main/java/org/example/decoratorpattern/decorator/Whip.java:
--------------------------------------------------------------------------------
1 | package org.example.decoratorpattern.decorator;
2 |
3 | import org.example.decoratorpattern.component.Beverage;
4 |
5 | public class Whip extends CondimentDecorator {
6 | public Whip(Beverage beverage) {
7 | super(beverage);
8 | }
9 |
10 | @Override
11 | public double cost() {
12 | return beverage.cost() + .10;
13 | }
14 |
15 | @Override
16 | public String getDescription() {
17 | return beverage.getDescription() + ", Whip";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/04-factory/README.md:
--------------------------------------------------------------------------------
1 | # THE FACTORY PATTERN
2 | ## Baking with OO Goodness
3 | ## 1. The Problem
4 |
5 | You have a Pizza Store that sells many types of pizza, such as Cheese, Clam, etc. You want to open many branches in other regions to expand your business. The problem is that the people in each area have different tastes in pizza. For example, people in New York love pizza with thin-crust dough, marinara sauce, and Reggiano cheese, while others in Chicago love pizza with thick-crust dough, plum-tomato sauce, and Mozzarella cheese.
6 |
7 | To solve this problem, you allow each regional branch to use different ingredients according to the neighborhood's taste. However, you want all branches to follow the original procedure of making a pizza:
8 | - Bake for 25 minutes at 350.
9 | - Cutting the pizza into diagonal slices.
10 | - Place the pizza in the official PizzaStore box.
11 |
12 | What will you do to make your plan come true?
13 |
14 | ## 2. Two Factory Patterns
15 | ### 2.1. The Factory Method Pattern
16 |
17 | **The Factory Method Pattern** defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
18 |
19 | ### 2.2. The Abstract Factory Pattern
20 |
21 | **The Abstract Factory Pattern** provides an interface for creating families of related or dependent objects without specifying their concrete classes.
22 |
23 | ### 2.3. Factory Method and Abstract Factory compared
24 |
25 | 
26 |
27 | 
--------------------------------------------------------------------------------
/04-factory/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 04-factory
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/PizzaTestDrive.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern;
2 |
3 | import org.example.factorypattern.product.pizza.Pizza;
4 | import org.example.factorypattern.creator.pizza.ChicagoPizzaStore;
5 | import org.example.factorypattern.creator.pizza.NYPizzaStore;
6 | import org.example.factorypattern.creator.pizza.PizzaStore;
7 | import org.example.factorypattern.creator.pizza.PizzaType;
8 |
9 | public class PizzaTestDrive {
10 | public static void main(String[] args) {
11 | PizzaStore nyStore = new NYPizzaStore();
12 | PizzaStore chicagoStore = new ChicagoPizzaStore();
13 |
14 | Pizza pizza = nyStore.orderPizza(PizzaType.CHEESE);
15 | System.out.println("Ethan ordered a " + pizza.getName() + "\n");
16 |
17 | pizza = chicagoStore.orderPizza(PizzaType.CLAM);
18 | System.out.println("Joel ordered a " + pizza.getName() + "\n");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/ingredient/ChicagoIngredientFactory.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.ingredient;
2 |
3 | import java.util.List;
4 | import org.example.factorypattern.product.ingredient.BlackOlives;
5 | import org.example.factorypattern.product.ingredient.EggPlant;
6 | import org.example.factorypattern.product.ingredient.FrozenClams;
7 | import org.example.factorypattern.product.ingredient.ICheese;
8 | import org.example.factorypattern.product.ingredient.IClams;
9 | import org.example.factorypattern.product.ingredient.IDough;
10 | import org.example.factorypattern.product.ingredient.IPepperoni;
11 | import org.example.factorypattern.product.ingredient.ISauce;
12 | import org.example.factorypattern.product.ingredient.IVeggies;
13 | import org.example.factorypattern.product.ingredient.MozzarellaCheese;
14 | import org.example.factorypattern.product.ingredient.PlumTomatoSauce;
15 | import org.example.factorypattern.product.ingredient.SlicedPepperoni;
16 | import org.example.factorypattern.product.ingredient.Spinach;
17 | import org.example.factorypattern.product.ingredient.ThickCrustDough;
18 |
19 | public class ChicagoIngredientFactory implements IPizzaIngredientFactory {
20 | @Override
21 | public IDough createDough() {
22 | return new ThickCrustDough();
23 | }
24 |
25 | @Override
26 | public ISauce createSauce() {
27 | return new PlumTomatoSauce();
28 | }
29 |
30 | @Override
31 | public ICheese createCheese() {
32 | return new MozzarellaCheese();
33 | }
34 |
35 | @Override
36 | public List createVeggies() {
37 | return List.of(new EggPlant(), new Spinach(), new BlackOlives());
38 | }
39 |
40 | @Override
41 | public IPepperoni createPepperoni() {
42 | return new SlicedPepperoni();
43 | }
44 |
45 | @Override
46 | public IClams createClam() {
47 | return new FrozenClams();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/ingredient/IPizzaIngredientFactory.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.ingredient;
2 |
3 | import java.util.List;
4 | import org.example.factorypattern.product.ingredient.ICheese;
5 | import org.example.factorypattern.product.ingredient.IClams;
6 | import org.example.factorypattern.product.ingredient.IDough;
7 | import org.example.factorypattern.product.ingredient.IPepperoni;
8 | import org.example.factorypattern.product.ingredient.ISauce;
9 | import org.example.factorypattern.product.ingredient.IVeggies;
10 |
11 | public interface IPizzaIngredientFactory {
12 | IDough createDough();
13 | ISauce createSauce();
14 | ICheese createCheese();
15 | List createVeggies();
16 | IPepperoni createPepperoni();
17 | IClams createClam();
18 | }
19 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/ingredient/NYPizzaIngredientFactory.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.ingredient;
2 |
3 | import java.util.List;
4 | import org.example.factorypattern.product.ingredient.FreshClams;
5 | import org.example.factorypattern.product.ingredient.Garlic;
6 | import org.example.factorypattern.product.ingredient.ICheese;
7 | import org.example.factorypattern.product.ingredient.IClams;
8 | import org.example.factorypattern.product.ingredient.IDough;
9 | import org.example.factorypattern.product.ingredient.IPepperoni;
10 | import org.example.factorypattern.product.ingredient.ISauce;
11 | import org.example.factorypattern.product.ingredient.IVeggies;
12 | import org.example.factorypattern.product.ingredient.MarinaraSauce;
13 | import org.example.factorypattern.product.ingredient.Mushroom;
14 | import org.example.factorypattern.product.ingredient.Onion;
15 | import org.example.factorypattern.product.ingredient.RedPepper;
16 | import org.example.factorypattern.product.ingredient.ReggianoCheese;
17 | import org.example.factorypattern.product.ingredient.SlicedPepperoni;
18 | import org.example.factorypattern.product.ingredient.ThinCrustDough;
19 |
20 | public class NYPizzaIngredientFactory implements IPizzaIngredientFactory {
21 | @Override
22 | public IDough createDough() {
23 | return new ThinCrustDough();
24 | }
25 |
26 | @Override
27 | public ISauce createSauce() {
28 | return new MarinaraSauce();
29 | }
30 |
31 | @Override
32 | public ICheese createCheese() {
33 | return new ReggianoCheese();
34 | }
35 |
36 | @Override
37 | public List createVeggies() {
38 | return List.of(new Garlic(), new Onion(), new Mushroom(), new RedPepper());
39 | }
40 |
41 | @Override
42 | public IPepperoni createPepperoni() {
43 | return new SlicedPepperoni();
44 | }
45 |
46 | @Override
47 | public IClams createClam() {
48 | return new FreshClams();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/pizza/ChicagoPizzaStore.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.pizza;
2 |
3 | import org.example.factorypattern.creator.ingredient.ChicagoIngredientFactory;
4 | import org.example.factorypattern.creator.ingredient.IPizzaIngredientFactory;
5 | import org.example.factorypattern.product.pizza.CheesePizza;
6 | import org.example.factorypattern.product.pizza.ClamPizza;
7 | import org.example.factorypattern.product.pizza.Pizza;
8 |
9 | public class ChicagoPizzaStore extends PizzaStore {
10 | @Override
11 | protected Pizza createPizza(PizzaType type) {
12 | Pizza pizza = null;
13 | IPizzaIngredientFactory ingredientFactory = new ChicagoIngredientFactory();
14 |
15 | if (type.equals(PizzaType.CHEESE)) {
16 | pizza = new CheesePizza(ingredientFactory);
17 | pizza.setName("Chicago Style Cheese Pizza");
18 | } else if (type.equals(PizzaType.CLAM)) {
19 | pizza = new ClamPizza(ingredientFactory);
20 | pizza.setName("Chicago Style Clam Pizza");
21 | }
22 |
23 | return pizza;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/pizza/NYPizzaStore.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.pizza;
2 |
3 | import org.example.factorypattern.creator.ingredient.IPizzaIngredientFactory;
4 | import org.example.factorypattern.creator.ingredient.NYPizzaIngredientFactory;
5 | import org.example.factorypattern.product.pizza.CheesePizza;
6 | import org.example.factorypattern.product.pizza.ClamPizza;
7 | import org.example.factorypattern.product.pizza.Pizza;
8 |
9 | public class NYPizzaStore extends PizzaStore {
10 | @Override
11 | protected Pizza createPizza(PizzaType type) {
12 | Pizza pizza = null;
13 | IPizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
14 |
15 | if (type.equals(PizzaType.CHEESE)) {
16 | pizza = new CheesePizza(ingredientFactory);
17 | pizza.setName("New York Style Cheese Pizza");
18 | } else if (type.equals(PizzaType.CLAM)) {
19 | pizza = new ClamPizza(ingredientFactory);
20 | pizza.setName("New York Style Clam Pizza");
21 | }
22 |
23 | return pizza;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/pizza/PizzaStore.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.pizza;
2 |
3 | import org.example.factorypattern.product.pizza.Pizza;
4 |
5 | public abstract class PizzaStore {
6 | protected abstract Pizza createPizza(PizzaType type);
7 |
8 | public Pizza orderPizza(PizzaType type) {
9 | Pizza pizza = createPizza(type);
10 |
11 | pizza.prepare();
12 | pizza.bake();
13 | pizza.cut();
14 | pizza.box();
15 |
16 | return pizza;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/creator/pizza/PizzaType.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.creator.pizza;
2 |
3 | public enum PizzaType {
4 | CHEESE, VEGGIE, CLAM, PEPPERONI
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/BlackOlives.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class BlackOlives implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Black Olives";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/EggPlant.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class EggPlant implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Egg Plant";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/FreshClams.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class FreshClams implements IClams {
4 | @Override
5 | public String toString() {
6 | return "Fresh Clams";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/FrozenClams.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class FrozenClams implements IClams {
4 | @Override
5 | public String toString() {
6 | return "Frozen Clams";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/Garlic.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class Garlic implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Garlic";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/ICheese.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public interface ICheese {
4 | String toString();
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/IClams.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public interface IClams {
4 | String toString();
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/IDough.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public interface IDough {
4 | String toString();
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/IPepperoni.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public interface IPepperoni {
4 | String toString();
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/ISauce.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public interface ISauce {
4 | String toString();
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/IVeggies.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public interface IVeggies {
4 | String toString();
5 | }
6 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/MarinaraSauce.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class MarinaraSauce implements ISauce {
4 | @Override
5 | public String toString() {
6 | return "Marinara Sauce";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/MozzarellaCheese.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class MozzarellaCheese implements ICheese {
4 | @Override
5 | public String toString() {
6 | return "Mozzarella Cheese";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/Mushroom.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class Mushroom implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Mushroom";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/Onion.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class Onion implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Onion";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/PlumTomatoSauce.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class PlumTomatoSauce implements ISauce {
4 | @Override
5 | public String toString() {
6 | return "Plum Tomato Sauce";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/RedPepper.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class RedPepper implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Red Pepper";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/ReggianoCheese.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class ReggianoCheese implements ICheese {
4 | @Override
5 | public String toString() {
6 | return "Reggiano Cheese";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/SlicedPepperoni.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class SlicedPepperoni implements IPepperoni {
4 | @Override
5 | public String toString() {
6 | return "Sliced Pepperoni";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/Spinach.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class Spinach implements IVeggies {
4 | @Override
5 | public String toString() {
6 | return "Spinach";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/ThickCrustDough.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class ThickCrustDough implements IDough {
4 | @Override
5 | public String toString() {
6 | return "Thick Crust Dough";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/ingredient/ThinCrustDough.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.ingredient;
2 |
3 | public class ThinCrustDough implements IDough {
4 | @Override
5 | public String toString() {
6 | return "Thin Crust Dough";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/pizza/CheesePizza.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.pizza;
2 |
3 | import org.example.factorypattern.creator.ingredient.IPizzaIngredientFactory;
4 |
5 | public class CheesePizza extends Pizza {
6 | public CheesePizza(IPizzaIngredientFactory ingredientFactory) {
7 | super(ingredientFactory);
8 | }
9 |
10 | @Override
11 | public void prepare() {
12 | System.out.println("Preparing " + name);
13 | dough = ingredientFactory.createDough();
14 | sauce = ingredientFactory.createSauce();
15 | cheese = ingredientFactory.createCheese();
16 | showIngredients();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/pizza/ClamPizza.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.pizza;
2 |
3 | import org.example.factorypattern.creator.ingredient.IPizzaIngredientFactory;
4 |
5 | public class ClamPizza extends Pizza {
6 | public ClamPizza(IPizzaIngredientFactory ingredientFactory) {
7 | super(ingredientFactory);
8 | }
9 |
10 | @Override
11 | public void prepare() {
12 | System.out.println("Preparing " + name);
13 | dough = ingredientFactory.createDough();
14 | sauce = ingredientFactory.createSauce();
15 | veggies = ingredientFactory.createVeggies();
16 | cheese = ingredientFactory.createCheese();
17 | clam = ingredientFactory.createClam();
18 | showIngredients();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/04-factory/src/main/java/org/example/factorypattern/product/pizza/Pizza.java:
--------------------------------------------------------------------------------
1 | package org.example.factorypattern.product.pizza;
2 |
3 | import java.util.List;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 | import org.example.factorypattern.creator.ingredient.IPizzaIngredientFactory;
7 | import org.example.factorypattern.product.ingredient.ICheese;
8 | import org.example.factorypattern.product.ingredient.IClams;
9 | import org.example.factorypattern.product.ingredient.IDough;
10 | import org.example.factorypattern.product.ingredient.IPepperoni;
11 | import org.example.factorypattern.product.ingredient.ISauce;
12 | import org.example.factorypattern.product.ingredient.IVeggies;
13 |
14 | @Getter
15 | @Setter
16 | public abstract class Pizza {
17 | protected IPizzaIngredientFactory ingredientFactory;
18 | protected String name;
19 |
20 | protected IDough dough;
21 | protected ISauce sauce;
22 | protected List veggies;
23 | protected ICheese cheese;
24 | protected IPepperoni pepperoni;
25 | protected IClams clam;
26 |
27 | public Pizza(IPizzaIngredientFactory ingredientFactory) {
28 | this.ingredientFactory = ingredientFactory;
29 | }
30 |
31 | public abstract void prepare();
32 |
33 | public final void showIngredients() {
34 | System.out.println("Ingredients:");
35 | if (dough != null) {
36 | System.out.println("\tDough: " + dough);
37 | }
38 | if (sauce != null) {
39 | System.out.println("\tSauce: " + sauce);
40 | }
41 | if (veggies != null && !veggies.isEmpty()) {
42 | List veggiesInString = veggies.stream().map(IVeggies::toString).toList();
43 | System.out.println("\tVeggies: " + String.join(", ", veggiesInString));
44 | }
45 | if (cheese != null) {
46 | System.out.println("\tCheese: " + cheese);
47 | }
48 | if (pepperoni != null) {
49 | System.out.println("\tPepperoni: " + pepperoni);
50 | }
51 | if (clam != null) {
52 | System.out.println("\tClam: " + clam);
53 | }
54 | }
55 |
56 | public void bake() {
57 | System.out.println("Bake for 25 minutes at 350");
58 | }
59 |
60 | public void cut() {
61 | System.out.println("Cutting the pizza into diagonal slices");
62 | }
63 |
64 | public void box() {
65 | System.out.println("Place pizza in official PizzaStore box");
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/05-singleton/README.md:
--------------------------------------------------------------------------------
1 | # THE SINGLETON PATTERN
2 | ## One-of-a-Kind Objects
3 | ## 1. The Definition of Singleton Pattern
4 |
5 | **The Singleton Pattern** ensures a class has only one instance, and provides a global access point of access to it.
6 |
7 | ## 2. Demo Diagram
8 | 
9 |
--------------------------------------------------------------------------------
/05-singleton/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 05-singleton
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/05-singleton/src/main/java/org/example/singletonpattern/ChocolateBoiler.java:
--------------------------------------------------------------------------------
1 | package org.example.singletonpattern;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public class ChocolateBoiler {
7 | private boolean empty;
8 | private boolean boiled;
9 | private static ChocolateBoiler instance;
10 |
11 | private ChocolateBoiler() {
12 | empty = true;
13 | boiled = false;
14 | }
15 |
16 | // If we don't use the 'synchronized' key word here,
17 | // we can get different boiler objects in multi-threading
18 | public static synchronized ChocolateBoiler getInstance() {
19 | if (instance == null) {
20 | System.out.println("Creating unique instance of ChocolateBoiler");
21 | instance = new ChocolateBoiler();
22 | }
23 | System.out.println("Returning unique instance of ChocolateBoiler");
24 | return instance;
25 | }
26 |
27 | public void fill() {
28 | if (isEmpty()) {
29 | empty = false;
30 | boiled = false;
31 | System.out.println("Fill the boiler with a milk/chocolate mixture");
32 | }
33 | }
34 |
35 | public void boil() {
36 | if (!isEmpty() && !isBoiled()) {
37 | boiled = true;
38 | System.out.println("Bring the contents to a boil");
39 | }
40 | }
41 |
42 | public void drain() {
43 | if (!isEmpty() && isBoiled()) {
44 | empty = true;
45 | System.out.println("Drain the boiled milk and chocolate");
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/05-singleton/src/main/java/org/example/singletonpattern/ChocolateBoilerController.java:
--------------------------------------------------------------------------------
1 | package org.example.singletonpattern;
2 |
3 | public class ChocolateBoilerController {
4 | private static final long SLEEP_TIME = 2000;
5 |
6 | public static void main(String[] args) {
7 | ChocolateBoilerRunnable runnable0 = new ChocolateBoilerRunnable();
8 | Thread chocolateBoilerThread0 = new Thread(runnable0, "Thread 0");
9 |
10 | ChocolateBoilerRunnable runnable1 = new ChocolateBoilerRunnable();
11 | Thread chocolateBoilerThread1 = new Thread(runnable1, "Thread 1");
12 |
13 | chocolateBoilerThread0.start();
14 |
15 | chocolateBoilerThread1.start();
16 | }
17 |
18 | private static class ChocolateBoilerRunnable implements Runnable {
19 | @Override
20 | public void run() {
21 | String threadName = Thread.currentThread().getName();
22 | System.out.println(threadName + " starts");
23 | try {
24 | Thread.sleep(SLEEP_TIME);
25 | ChocolateBoiler chocolateBoiler = ChocolateBoiler.getInstance();
26 | Thread.sleep(SLEEP_TIME);
27 | chocolateBoiler.fill();
28 | Thread.sleep(SLEEP_TIME);
29 | chocolateBoiler.boil();
30 | Thread.sleep(SLEEP_TIME);
31 | chocolateBoiler.drain();
32 | Thread.sleep(SLEEP_TIME);
33 | System.out.println(threadName + " used " + chocolateBoiler);
34 | } catch (InterruptedException ex) {
35 | ex.printStackTrace();
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/06-command/README.md:
--------------------------------------------------------------------------------
1 | # THE COMMAND PATTERN
2 | ## Encapsulating Invocation
3 | ## 1. The Problem
4 |
5 | Bill Thompson, CEO of Home Automation or Bust, Inc., wants you to design the API for their new Home Automation Remote Control.
6 |
7 | The remote control features seven programmable slots (each can be assigned to a different household device) along with corresponding on/off buttons for each. It also has a global undo button.
8 |
9 | Bill's company cooperates with many vendors providing Java classes to control home automation devices such as lights, fans, stereos, etc.
10 |
11 | Your work is to create an API for programming the remote so that each slot can be assigned to control a device or set of devices. Note that the remote control must be able to handle any future devices that their vendors may supply.
12 |
13 | ## 2. The Definition of Command Pattern
14 |
15 | **The Command Pattern** encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
16 |
17 | ## 3. Demo Diagram
18 | 
19 |
--------------------------------------------------------------------------------
/06-command/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 06-command
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/Location.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern;
2 |
3 | public enum Location {
4 | LIVING_ROOM("Living Room"),
5 | KITCHEN("Kitchen"),
6 | GARAGE("Garage");
7 |
8 | private final String location;
9 |
10 | Location(String location) {
11 | this.location = location;
12 | }
13 |
14 | @Override
15 | public String toString() {
16 | return location;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/RemoteControl.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern;
2 |
3 | import java.util.List;
4 | import java.util.Stack;
5 | import org.example.commandpattern.command.ICommand;
6 | import org.example.commandpattern.command.NoCommand;
7 |
8 | public class RemoteControl {
9 | private final ICommand[] onCommands;
10 | private final ICommand[] offCommands;
11 | private final Stack previousCommands;
12 |
13 | public RemoteControl() {
14 | onCommands = new ICommand[7];
15 | offCommands = new ICommand[7];
16 |
17 | ICommand noCommand = new NoCommand();
18 | for (int i = 0; i < 7; i++) {
19 | onCommands[i] = noCommand;
20 | offCommands[i] = noCommand;
21 | }
22 |
23 | previousCommands = new Stack<>();
24 | previousCommands.push(noCommand);
25 | }
26 |
27 | public void setCommand(int slot, ICommand onCommand, ICommand offCommand) {
28 | onCommands[slot] = onCommand;
29 | offCommands[slot] = offCommand;
30 | }
31 |
32 | public void onButtonWasPushed(int slot) {
33 | onCommands[slot].execute();
34 | previousCommands.push(onCommands[slot]);
35 | }
36 |
37 | public void offButtonWasPushed(int slot) {
38 | offCommands[slot].execute();
39 | previousCommands.push(offCommands[slot]);
40 | }
41 |
42 | public void undoButtonWasPushed() {
43 | if (previousCommands.peek() instanceof NoCommand) {
44 | System.out.println("No actions left to undo");
45 | }
46 | previousCommands.pop().undo();
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | StringBuilder stringBuilder = new StringBuilder("\n-------- Remote Control --------\n");
52 | String slotDescriptionFormat = "[Slot %d] %s\t%s\n";
53 | for (int i = 0; i < onCommands.length; i++) {
54 | stringBuilder.append(String.format(slotDescriptionFormat,
55 | i, onCommands[i].getClass().getSimpleName(), offCommands[i].getClass().getSimpleName()));
56 | }
57 | stringBuilder
58 | .append("[Undo]\t")
59 | .append(showPreviousCommands())
60 | .append("\n");
61 | return stringBuilder.toString();
62 | }
63 |
64 | private String showPreviousCommands() {
65 | List previousCommandsInString = previousCommands
66 | .stream()
67 | .map(command -> command.getClass().getSimpleName())
68 | .toList();
69 | return String.join(", ", previousCommandsInString);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/RemoteControlTest.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern;
2 |
3 | import org.example.commandpattern.command.CeilingFanOffCommand;
4 | import org.example.commandpattern.command.CeilingFanHighCommand;
5 | import org.example.commandpattern.command.GarageDoorDownCommand;
6 | import org.example.commandpattern.command.GarageDoorUpCommand;
7 | import org.example.commandpattern.command.LightOffCommand;
8 | import org.example.commandpattern.command.LightOnCommand;
9 | import org.example.commandpattern.command.StereoOffCommand;
10 | import org.example.commandpattern.command.StereoOnWithCDCommand;
11 | import org.example.commandpattern.receiver.CeilingFan;
12 | import org.example.commandpattern.receiver.GarageDoor;
13 | import org.example.commandpattern.receiver.Light;
14 | import org.example.commandpattern.receiver.Stereo;
15 |
16 | public class RemoteControlTest {
17 | public static void main(String[] args) {
18 | // Create an Invoker
19 | RemoteControl remoteControl = new RemoteControl();
20 |
21 | // Create all Receivers
22 | Light livingRoomLight = new Light(Location.LIVING_ROOM);
23 | Light kitchenLight = new Light(Location.KITCHEN);
24 | CeilingFan ceilingFan = new CeilingFan(Location.LIVING_ROOM);
25 | GarageDoor garageDoor = new GarageDoor(Location.GARAGE);
26 | Stereo stereo = new Stereo(Location.LIVING_ROOM);
27 |
28 | // Create all Commands
29 | LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
30 | LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
31 | LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
32 | LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);
33 |
34 | CeilingFanHighCommand ceilingFanOn = new CeilingFanHighCommand(ceilingFan);
35 | CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);
36 |
37 | GarageDoorUpCommand garageDoorUp = new GarageDoorUpCommand(garageDoor);
38 | GarageDoorDownCommand garageDoorDown = new GarageDoorDownCommand(garageDoor);
39 |
40 | StereoOnWithCDCommand stereoOnWithCD = new StereoOnWithCDCommand(stereo);
41 | StereoOffCommand stereoOff = new StereoOffCommand(stereo);
42 |
43 | // Load all commands into the Invoker
44 | remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
45 | remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
46 | remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff);
47 | remoteControl.setCommand(3, garageDoorUp, garageDoorDown);
48 | remoteControl.setCommand(4, stereoOnWithCD, stereoOff);
49 |
50 | System.out.println(remoteControl);
51 |
52 | for (int i = 0; i < 7; i++) {
53 | remoteControl.onButtonWasPushed(i);
54 | remoteControl.offButtonWasPushed(i);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/RemoteControlTestWithMacro.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern;
2 |
3 | import org.example.commandpattern.command.HottubOffCommand;
4 | import org.example.commandpattern.command.HottubOnCommand;
5 | import org.example.commandpattern.command.ICommand;
6 | import org.example.commandpattern.command.LightOffCommand;
7 | import org.example.commandpattern.command.LightOnCommand;
8 | import org.example.commandpattern.command.MacroCommand;
9 | import org.example.commandpattern.command.StereoOffCommand;
10 | import org.example.commandpattern.command.StereoOnWithCDCommand;
11 | import org.example.commandpattern.receiver.Hottub;
12 | import org.example.commandpattern.receiver.Light;
13 | import org.example.commandpattern.receiver.Stereo;
14 |
15 | public class RemoteControlTestWithMacro {
16 | public static void main(String[] args) {
17 | RemoteControl remoteControl = new RemoteControl();
18 |
19 | Light light = new Light(Location.LIVING_ROOM);
20 | Stereo stereo = new Stereo(Location.LIVING_ROOM);
21 | Hottub hottub = new Hottub();
22 |
23 | LightOnCommand lightOnCommand = new LightOnCommand(light);
24 | LightOffCommand lightOffCommand = new LightOffCommand(light);
25 | StereoOnWithCDCommand stereoOnWithCDCommand = new StereoOnWithCDCommand(stereo);
26 | StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
27 | HottubOnCommand hottubOnCommand = new HottubOnCommand(hottub);
28 | HottubOffCommand hottubOffCommand = new HottubOffCommand(hottub);
29 |
30 | ICommand[] partyOnCommands = { lightOnCommand, stereoOnWithCDCommand, hottubOnCommand };
31 | ICommand[] partyOffCommands = { lightOffCommand, stereoOffCommand, hottubOffCommand };
32 |
33 | MacroCommand partyOnMacro = new MacroCommand(partyOnCommands);
34 | MacroCommand partyOffMacro = new MacroCommand(partyOffCommands);
35 |
36 | remoteControl.setCommand(0, partyOnMacro, partyOffMacro);
37 |
38 | System.out.println(remoteControl);
39 | System.out.println("--- Pushing Macro On ---");
40 | remoteControl.onButtonWasPushed(0);
41 | System.out.println("--- Pushing Macro Off ---");
42 | remoteControl.offButtonWasPushed(0);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/RemoteControlTestWithUndo.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern;
2 |
3 | import org.example.commandpattern.command.CeilingFanHighCommand;
4 | import org.example.commandpattern.command.CeilingFanMediumCommand;
5 | import org.example.commandpattern.command.CeilingFanOffCommand;
6 | import org.example.commandpattern.receiver.CeilingFan;
7 |
8 | public class RemoteControlTestWithUndo {
9 | public static void main(String[] args) {
10 | RemoteControl remoteControl = new RemoteControl();
11 |
12 | CeilingFan ceilingFan = new CeilingFan(Location.LIVING_ROOM);
13 |
14 | CeilingFanHighCommand ceilingFanHighCommand = new CeilingFanHighCommand(ceilingFan);
15 | CeilingFanMediumCommand ceilingFanMediumCommand = new CeilingFanMediumCommand(ceilingFan);
16 | CeilingFanOffCommand ceilingFanOffCommand = new CeilingFanOffCommand(ceilingFan);
17 |
18 | remoteControl.setCommand(0, ceilingFanMediumCommand, ceilingFanOffCommand);
19 | remoteControl.setCommand(1, ceilingFanHighCommand, ceilingFanOffCommand);
20 |
21 | remoteControl.onButtonWasPushed(0);
22 | remoteControl.offButtonWasPushed(0);
23 | System.out.println(remoteControl);
24 | remoteControl.undoButtonWasPushed();
25 |
26 | remoteControl.onButtonWasPushed(1);
27 | System.out.println(remoteControl);
28 | remoteControl.undoButtonWasPushed();
29 | remoteControl.undoButtonWasPushed();
30 | remoteControl.undoButtonWasPushed();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/CeilingFanCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.CeilingFan;
4 |
5 | public abstract class CeilingFanCommand implements ICommand {
6 | protected final CeilingFan ceilingFan;
7 | protected int previousSpeed;
8 |
9 | public CeilingFanCommand(CeilingFan ceilingFan) {
10 | this.ceilingFan = ceilingFan;
11 | }
12 |
13 | @Override
14 | public void undo() {
15 | if (previousSpeed == CeilingFan.HIGH) {
16 | ceilingFan.high();
17 | } else if (previousSpeed == CeilingFan.MEDIUM) {
18 | ceilingFan.medium();
19 | } else if (previousSpeed == CeilingFan.LOW) {
20 | ceilingFan.low();
21 | } else {
22 | ceilingFan.off();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/CeilingFanHighCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.CeilingFan;
4 |
5 | public class CeilingFanHighCommand extends CeilingFanCommand {
6 |
7 | public CeilingFanHighCommand(CeilingFan ceilingFan) {
8 | super(ceilingFan);
9 | }
10 |
11 | @Override
12 | public void execute() {
13 | previousSpeed = ceilingFan.getSpeed();
14 | ceilingFan.high();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/CeilingFanLowCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.CeilingFan;
4 |
5 | public class CeilingFanLowCommand extends CeilingFanCommand {
6 | public CeilingFanLowCommand(CeilingFan ceilingFan) {
7 | super(ceilingFan);
8 | }
9 |
10 | @Override
11 | public void execute() {
12 | previousSpeed = ceilingFan.getSpeed();
13 | ceilingFan.low();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/CeilingFanMediumCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.CeilingFan;
4 |
5 | public class CeilingFanMediumCommand extends CeilingFanCommand {
6 | public CeilingFanMediumCommand(CeilingFan ceilingFan) {
7 | super(ceilingFan);
8 | }
9 |
10 | @Override
11 | public void execute() {
12 | previousSpeed = ceilingFan.getSpeed();
13 | ceilingFan.medium();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/CeilingFanOffCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.CeilingFan;
4 |
5 | public class CeilingFanOffCommand extends CeilingFanCommand {
6 | public CeilingFanOffCommand(CeilingFan ceilingFan) {
7 | super(ceilingFan);
8 | }
9 |
10 | @Override
11 | public void execute() {
12 | previousSpeed = ceilingFan.getSpeed();
13 | ceilingFan.off();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/GarageDoorDownCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.GarageDoor;
4 |
5 | public class GarageDoorDownCommand implements ICommand {
6 | private final GarageDoor garageDoor;
7 |
8 | public GarageDoorDownCommand(GarageDoor garageDoor) {
9 | this.garageDoor = garageDoor;
10 | }
11 | @Override
12 | public void execute() {
13 | garageDoor.down();
14 | }
15 |
16 | @Override
17 | public void undo() {
18 | garageDoor.up();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/GarageDoorUpCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.GarageDoor;
4 |
5 | public class GarageDoorUpCommand implements ICommand {
6 | private final GarageDoor garageDoor;
7 |
8 | public GarageDoorUpCommand(GarageDoor garageDoor) {
9 | this.garageDoor = garageDoor;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | garageDoor.up();
15 | }
16 |
17 | @Override
18 | public void undo() {
19 | garageDoor.down();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/HottubOffCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.Hottub;
4 |
5 | public class HottubOffCommand implements ICommand {
6 | private final Hottub hottub;
7 |
8 | public HottubOffCommand(Hottub hottub) {
9 | this.hottub = hottub;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | hottub.setTemperature(98);
15 | hottub.off();
16 | }
17 |
18 | @Override
19 | public void undo() {
20 | hottub.on();
21 | hottub.setTemperature(104);
22 | hottub.circulate();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/HottubOnCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.Hottub;
4 |
5 | public class HottubOnCommand implements ICommand {
6 | private final Hottub hottub;
7 |
8 | public HottubOnCommand(Hottub hottub) {
9 | this.hottub = hottub;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | hottub.on();
15 | hottub.setTemperature(104);
16 | hottub.circulate();
17 | }
18 |
19 | @Override
20 | public void undo() {
21 | hottub.off();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/ICommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | public interface ICommand {
4 | void execute();
5 | void undo();
6 | }
7 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/LightOffCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.Light;
4 |
5 | public class LightOffCommand implements ICommand {
6 | private final Light light;
7 |
8 | public LightOffCommand(Light light) {
9 | this.light = light;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | light.off();
15 | }
16 |
17 | @Override
18 | public void undo() {
19 | light.on();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/LightOnCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.Light;
4 |
5 | public class LightOnCommand implements ICommand {
6 | private final Light light;
7 |
8 | public LightOnCommand(Light light) {
9 | this.light = light;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | light.on();
15 | }
16 |
17 | @Override
18 | public void undo() {
19 | light.off();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/MacroCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | public class MacroCommand implements ICommand {
4 | private final ICommand[] commands;
5 |
6 | public MacroCommand(ICommand[] commands) {
7 | this.commands = commands;
8 | }
9 |
10 | @Override
11 | public void execute() {
12 | for (ICommand command : commands) {
13 | command.execute();
14 | }
15 | }
16 |
17 | @Override
18 | public void undo() {
19 | for (int i = commands.length - 1; i >= 0; i--) {
20 | commands[i].undo();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/NoCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | public class NoCommand implements ICommand {
4 |
5 | @Override
6 | public void execute() {
7 | }
8 |
9 | @Override
10 | public void undo() {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/StereoOffCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.Stereo;
4 |
5 | public class StereoOffCommand implements ICommand {
6 | private final Stereo stereo;
7 |
8 | public StereoOffCommand(Stereo stereo) {
9 | this.stereo = stereo;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | stereo.off();
15 | }
16 |
17 | @Override
18 | public void undo() {
19 | stereo.on();
20 | stereo.setCD();
21 | stereo.setVolume(11);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/command/StereoOnWithCDCommand.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.command;
2 |
3 | import org.example.commandpattern.receiver.Stereo;
4 |
5 | public class StereoOnWithCDCommand implements ICommand {
6 | private final Stereo stereo;
7 |
8 | public StereoOnWithCDCommand(Stereo stereo) {
9 | this.stereo = stereo;
10 | }
11 |
12 | @Override
13 | public void execute() {
14 | stereo.on();
15 | stereo.setCD();
16 | stereo.setVolume(11);
17 | }
18 |
19 | @Override
20 | public void undo() {
21 | stereo.off();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/receiver/CeilingFan.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.receiver;
2 |
3 | import org.example.commandpattern.Location;
4 |
5 | public class CeilingFan {
6 | private final Location location;
7 | private int level;
8 |
9 | public static final int HIGH = 3;
10 | public static final int MEDIUM = 2;
11 | public static final int LOW = 1;
12 | public static final int OFF = 0;
13 |
14 | public CeilingFan(Location location) {
15 | this.location = location;
16 | }
17 |
18 | public void high() {
19 | // turns the ceiling fan on to high
20 | level = HIGH;
21 | System.out.println(location + " ceiling fan is on high");
22 |
23 | }
24 |
25 | public void medium() {
26 | // turns the ceiling fan on to medium
27 | level = MEDIUM;
28 | System.out.println(location + " ceiling fan is on medium");
29 | }
30 |
31 | public void low() {
32 | // turns the ceiling fan on to low
33 | level = LOW;
34 | System.out.println(location + " ceiling fan is on low");
35 | }
36 |
37 | public void off() {
38 | // turns the ceiling fan off
39 | level = 0;
40 | System.out.println(location + " ceiling fan is off");
41 | }
42 |
43 | public int getSpeed() {
44 | return level;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/receiver/GarageDoor.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.receiver;
2 |
3 | import org.example.commandpattern.Location;
4 |
5 | public class GarageDoor {
6 | private final Location location;
7 |
8 | public GarageDoor(Location location) {
9 | this.location = location;
10 | }
11 |
12 | public void up() {
13 | System.out.println(location + " garage door is Open");
14 | }
15 |
16 | public void down() {
17 | System.out.println(location + " garage door is Closed");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/receiver/Hottub.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.receiver;
2 |
3 | public class Hottub {
4 | private boolean on;
5 | private int temperature;
6 |
7 | public Hottub() {}
8 |
9 | public void on() {
10 | on = true;
11 | }
12 |
13 | public void off() {
14 | on = false;
15 | }
16 |
17 | public void circulate() {
18 | if (on) {
19 | System.out.println("Hottub is bubbling!");
20 | }
21 | }
22 |
23 | public void setTemperature(int temperature) {
24 | if (temperature > this.temperature) {
25 | System.out.println("Hottub is heating to a steaming " + temperature + " degrees");
26 | }
27 | else {
28 | System.out.println("Hottub is cooling to " + temperature + " degrees");
29 | }
30 | this.temperature = temperature;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/receiver/Light.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.receiver;
2 |
3 | import org.example.commandpattern.Location;
4 |
5 | public class Light {
6 | private final Location location;
7 |
8 | public Light(Location location) {
9 | this.location = location;
10 | }
11 |
12 | public void on() {
13 | System.out.println(location + " light is on");
14 | }
15 |
16 | public void off() {
17 | System.out.println(location + " light is off");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/06-command/src/main/java/org/example/commandpattern/receiver/Stereo.java:
--------------------------------------------------------------------------------
1 | package org.example.commandpattern.receiver;
2 |
3 | import org.example.commandpattern.Location;
4 |
5 | public class Stereo {
6 | private final Location location;
7 |
8 | public Stereo(Location location) {
9 | this.location = location;
10 | }
11 |
12 | public void on() {
13 | System.out.println(location + " stereo is on");
14 | }
15 |
16 | public void off() {
17 | System.out.println(location + " stereo is off");
18 | }
19 |
20 | public void setCD() {
21 | System.out.println(location + " stereo is set for CD input");
22 | }
23 |
24 | public void setDVD() {
25 | System.out.println(location + " stereo is set for DVD input");
26 | }
27 |
28 | public void setRadio() {
29 | System.out.println(location + " stereo is set for Radio");
30 | }
31 |
32 | public void setVolume(int volume) {
33 | // code to set the volume
34 | // valid range: 1-11 (after all 11 is better than 10, right?)
35 | System.out.println(location + " stereo volume set to " + volume);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/07-adapter-facade/README.md:
--------------------------------------------------------------------------------
1 | # THE ADAPTER AND FACADE PATTERNS
2 | ## Being Adaptive
3 | ## 1. The Adapter Pattern
4 | ### 1.1. Definition
5 |
6 | **The Adapter Pattern** converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
7 |
8 | ### 1.2. Class Diagram
9 | 
10 |
11 | ## 2. The Facade Pattern
12 | ### 2.1. Definition
13 |
14 | **The Facade Pattern** provides a unified interface to a set of interfaces in a subsytem. Facade defines a higher-level interface that makes the subsystem easier to use.
15 |
16 | ### 2.2. Class Diagram
17 | 
18 |
19 | ## 3. Demonstrates the "Principle of Least Knowledge"
20 | 
21 | 
22 |
--------------------------------------------------------------------------------
/07-adapter-facade/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 07-adapter-facade
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/Duck.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | public interface Duck {
4 | void quack();
5 | void fly();
6 | }
7 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/DuckAdapter.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | import java.util.Random;
4 |
5 | public class DuckAdapter implements Turkey {
6 | private final Duck duck;
7 | private final Random random;
8 |
9 | public DuckAdapter(Duck duck) {
10 | this.duck = duck;
11 | random = new Random();
12 | }
13 |
14 | @Override
15 | public void gobble() {
16 | duck.quack();
17 | }
18 |
19 | @Override
20 | public void fly() {
21 | if (random.nextInt(5) == 0) {
22 | duck.fly();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/DuckTestDrive.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | public class DuckTestDrive {
4 | public static void main(String[] args) {
5 | Duck mallardDuck = new MallardDuck();
6 | Turkey turkey = new WildTurkey();
7 | Duck turkeyAdapter = new TurkeyAdapter(turkey);
8 | Turkey duckAdapter = new DuckAdapter(mallardDuck);
9 |
10 | System.out.println("The Turkey says...");
11 | turkey.gobble();
12 | turkey.fly();
13 |
14 | System.out.println("\nThe Duck says...");
15 | testDuck(mallardDuck);
16 |
17 | System.out.println("\nThe TurkeyAdapter says...");
18 | testDuck(turkeyAdapter);
19 |
20 | System.out.println("\nThe DuckAdapter says...");
21 | duckAdapter.gobble();
22 | duckAdapter.fly();
23 | }
24 |
25 | private static void testDuck(Duck duck) {
26 | duck.quack();
27 | duck.fly();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/MallardDuck.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | public class MallardDuck implements Duck {
4 | @Override
5 | public void quack() {
6 | System.out.println("Quack Quack");
7 | }
8 |
9 | @Override
10 | public void fly() {
11 | System.out.println("I'm flying");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/Turkey.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | public interface Turkey {
4 | void gobble();
5 | void fly();
6 | }
7 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/TurkeyAdapter.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | public class TurkeyAdapter implements Duck {
4 | private final Turkey turkey;
5 |
6 | public TurkeyAdapter(Turkey turkey) {
7 | this.turkey = turkey;
8 | }
9 |
10 | @Override
11 | public void quack() {
12 | turkey.gobble();
13 | }
14 |
15 | @Override
16 | public void fly() {
17 | for (int i = 0; i < 5; i++) {
18 | turkey.fly();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/adapterpattern/WildTurkey.java:
--------------------------------------------------------------------------------
1 | package org.example.adapterpattern;
2 |
3 | public class WildTurkey implements Turkey {
4 | @Override
5 | public void gobble() {
6 | System.out.println("Gobble Gobble");
7 | }
8 |
9 | @Override
10 | public void fly() {
11 | System.out.println("I'm flying a short distance");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/Amplifier.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 |
6 | @RequiredArgsConstructor
7 | @Getter
8 | public class Amplifier {
9 | private final String description;
10 | private Tuner tuner;
11 | private StreamingPlayer player;
12 |
13 | public void on() {
14 | System.out.println(description + " on");
15 | }
16 |
17 | public void off() {
18 | System.out.println(description + " off");
19 | }
20 |
21 | public void setStereoSound() {
22 | System.out.println(description + " stereo mode on");
23 | }
24 |
25 | public void setSurroundSound() {
26 | System.out.println(description + " surround sound on (5 speakers, 1 subwoofer)");
27 | }
28 |
29 | public void setVolume(int level) {
30 | System.out.println(description + " setting volume to " + level);
31 | }
32 |
33 | public void setTuner(Tuner tuner) {
34 | System.out.println(description + " setting tuner to " + tuner);
35 | this.tuner = tuner;
36 | }
37 |
38 | public void setPlayer(StreamingPlayer player) {
39 | System.out.println(description + " setting Streaming player to " + player);
40 | this.player = player;
41 | }
42 |
43 | public String toString() {
44 | return description;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/CdPlayer.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 |
6 | @RequiredArgsConstructor
7 | @Getter
8 | public class CdPlayer {
9 | private final String description;
10 | private int currentTrack;
11 | private String title;
12 |
13 | public void on() {
14 | System.out.println(description + " on");
15 | }
16 |
17 | public void off() {
18 | System.out.println(description + " off");
19 | }
20 |
21 | public void eject() {
22 | title = null;
23 | System.out.println(description + " eject");
24 | }
25 |
26 | public void play(String title) {
27 | this.title = title;
28 | currentTrack = 0;
29 | System.out.println(description + " playing \"" + title + "\"");
30 | }
31 |
32 | public void play(int track) {
33 | if (title == null) {
34 | System.out.println(description + " can't play track " + currentTrack +
35 | ", no cd inserted");
36 | } else {
37 | currentTrack = track;
38 | System.out.println(description + " playing track " + currentTrack);
39 | }
40 | }
41 |
42 | public void stop() {
43 | currentTrack = 0;
44 | System.out.println(description + " stopped");
45 | }
46 |
47 | public void pause() {
48 | System.out.println(description + " paused \"" + title + "\"");
49 | }
50 |
51 | public String toString() {
52 | return description;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/HomeTheaterFacade.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.RequiredArgsConstructor;
4 |
5 | @RequiredArgsConstructor
6 | public class HomeTheaterFacade {
7 | private final Amplifier amp;
8 | private final Tuner tuner;
9 | private final StreamingPlayer player;
10 | private final Projector projector;
11 | private final Screen screen;
12 | private final TheaterLights lights;
13 | private final PopcornPopper popper;
14 |
15 | public void watchMovie(String movie) {
16 | System.out.println("Get ready to watch a movie...");
17 | popper.on();
18 | popper.pop();
19 | lights.dim(10);
20 | screen.down();
21 | projector.on();
22 | projector.wideScreenMode();
23 | amp.on();
24 | amp.setPlayer(player);
25 | amp.setSurroundSound();
26 | amp.setVolume(5);
27 | player.on();
28 | player.play(movie);
29 | }
30 |
31 |
32 | public void endMovie() {
33 | System.out.println("Shutting movie theater down...");
34 | popper.off();
35 | lights.on();
36 | screen.up();
37 | projector.off();
38 | amp.off();
39 | player.stop();
40 | player.off();
41 | }
42 |
43 | public void listenToRadio(double frequency) {
44 | System.out.println("Tuning in the airwaves...");
45 | tuner.on();
46 | tuner.setFrequency(frequency);
47 | amp.on();
48 | amp.setVolume(5);
49 | amp.setTuner(tuner);
50 | }
51 |
52 | public void endRadio() {
53 | System.out.println("Shutting down the tuner...");
54 | tuner.off();
55 | amp.off();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/HomeTheaterTestDrive.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | public class HomeTheaterTestDrive {
4 | public static void main(String[] args) {
5 | Amplifier amp = new Amplifier("Amplifier");
6 | Tuner tuner = new Tuner("AM/FM Tuner");
7 | StreamingPlayer player = new StreamingPlayer("Streaming Player");
8 | Projector projector = new Projector("Projector");
9 | TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
10 | Screen screen = new Screen("Theater Screen");
11 | PopcornPopper popper = new PopcornPopper("Popcorn Popper");
12 |
13 | HomeTheaterFacade homeTheater =
14 | new HomeTheaterFacade(amp, tuner, player, projector, screen, lights, popper);
15 |
16 | homeTheater.watchMovie("Raiders of the Lost Ark");
17 | homeTheater.endMovie();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/PopcornPopper.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.RequiredArgsConstructor;
4 |
5 | @RequiredArgsConstructor
6 | public class PopcornPopper {
7 | private final String description;
8 |
9 | public void on() {
10 | System.out.println(description + " on");
11 | }
12 |
13 | public void off() {
14 | System.out.println(description + " off");
15 | }
16 |
17 | public void pop() {
18 | System.out.println(description + " popping popcorn!");
19 | }
20 |
21 | public String toString() {
22 | return description;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/Projector.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.RequiredArgsConstructor;
4 |
5 | @RequiredArgsConstructor
6 | public class Projector {
7 | private final String description;
8 |
9 | public void on() {
10 | System.out.println(description + " on");
11 | }
12 |
13 | public void off() {
14 | System.out.println(description + " off");
15 | }
16 |
17 | public void wideScreenMode() {
18 | System.out.println(description + " in widescreen mode (16x9 aspect ratio)");
19 | }
20 |
21 | public void tvMode() {
22 | System.out.println(description + " in tv mode (4x3 aspect ratio)");
23 | }
24 |
25 | public String toString() {
26 | return description;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/Screen.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.RequiredArgsConstructor;
4 |
5 | @RequiredArgsConstructor
6 | public class Screen {
7 | private final String description;
8 |
9 | public void up() {
10 | System.out.println(description + " going up");
11 | }
12 |
13 | public void down() {
14 | System.out.println(description + " going down");
15 | }
16 |
17 | public String toString() {
18 | return description;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/StreamingPlayer.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 |
6 | @RequiredArgsConstructor
7 | @Getter
8 | public class StreamingPlayer {
9 | private final String description;
10 | private int currentChapter;
11 | private String movie;
12 |
13 | public void on() {
14 | System.out.println(description + " on");
15 | }
16 |
17 | public void off() {
18 | System.out.println(description + " off");
19 | }
20 |
21 | public void play(String movie) {
22 | this.movie = movie;
23 | currentChapter = 0;
24 | System.out.println(description + " playing \"" + movie + "\"");
25 | }
26 |
27 | public void play(int chapter) {
28 | if (movie == null) {
29 | System.out.println(description + " can't play chapter " + chapter + " no movie selected");
30 | } else {
31 | currentChapter = chapter;
32 | System.out.println(description + " playing chapter " + currentChapter + " of \"" + movie + "\"");
33 | }
34 | }
35 |
36 | public void stop() {
37 | currentChapter = 0;
38 | System.out.println(description + " stopped \"" + movie + "\"");
39 | }
40 |
41 | public void pause() {
42 | System.out.println(description + " paused \"" + movie + "\"");
43 | }
44 |
45 | public void setTwoChannelAudio() {
46 | System.out.println(description + " set two channel audio");
47 | }
48 |
49 | public void setSurroundAudio() {
50 | System.out.println(description + " set surround audio");
51 | }
52 |
53 | public String toString() {
54 | return description;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/TheaterLights.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.RequiredArgsConstructor;
4 |
5 | @RequiredArgsConstructor
6 | public class TheaterLights {
7 | private final String description;
8 |
9 | public void on() {
10 | System.out.println(description + " on");
11 | }
12 |
13 | public void off() {
14 | System.out.println(description + " off");
15 | }
16 |
17 | public void dim(int level) {
18 | System.out.println(description + " dimming to " + level + "%");
19 | }
20 |
21 | public String toString() {
22 | return description;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/07-adapter-facade/src/main/java/org/example/facadepattern/Tuner.java:
--------------------------------------------------------------------------------
1 | package org.example.facadepattern;
2 |
3 | import lombok.RequiredArgsConstructor;
4 |
5 | @RequiredArgsConstructor
6 | public class Tuner {
7 | private final String description;
8 |
9 | public void on() {
10 | System.out.println(description + " on");
11 | }
12 |
13 | public void off() {
14 | System.out.println(description + " off");
15 | }
16 |
17 | public void setFrequency(double frequency) {
18 | System.out.println(description + " setting frequency to " + frequency);
19 | }
20 |
21 | public void setAm() {
22 | System.out.println(description + " setting AM mode");
23 | }
24 |
25 | public void setFm() {
26 | System.out.println(description + " setting FM mode");
27 | }
28 |
29 | public String toString() {
30 | return description;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/08-template-method/README.md:
--------------------------------------------------------------------------------
1 | # THE TEMPLATE METHOD PATTERN
2 | ## Encapsulating Algorithms
3 | ## 1. The Problem
4 |
5 | Starbuzz Coffee has a training manual for their baristas to prepare beverages for customers.
6 |
7 | The Starbuzz Coffee Recipe includes these steps:
8 | 1. Boil some water
9 | 2. Brew coffee in boiling water
10 | 3. Pour coffee into a cup
11 | 4. Add sugar and milk.
12 |
13 | The Starbuzz Tea Recipe includes these steps:
14 | 1. Boil some water
15 | 2. Steep tea in boiling water
16 | 3. Pour the tea into a cup
17 | 4. Add lemon
18 |
19 | You need to write some code for creating coffee and tea. Note that the recipe for coffee looks a lot like the tea recipe. Moreover, some customers don't like sugar and milk in their cups of coffee, and others don't want any lemons in their cups of tea.
20 |
21 | ## 2. The Definition of Template Method Pattern
22 |
23 | **The Template Method Pattern** defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
24 |
25 | ## 3. Demo Diagram
26 |
27 | 
28 |
29 | ## 4. Methods in the Template Method's Abstract Class
30 |
31 | - The template method's abstract class may define **concrete methods**, **abstract methods** and **hooks**.
32 | - **Abstract methods** are implemented by subclasses.
33 | - **Hooks** are methods that do nothing or default behavior in the abstract class, but may be **overridden** in the subclass to provide its own functionality.
34 | - To prevent subclasses from changing the algorithm in the template method, declare the template method as `final`.
35 |
36 | ## 5. Explain the Hollywood Principle
37 |
38 | 
39 |
--------------------------------------------------------------------------------
/08-template-method/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 08-template-method
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/beveragetest/BeverageTestDrive.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.beveragetest;
2 |
3 | public class BeverageTestDrive {
4 | public static void main(String[] args) {
5 | CaffeineBeverage tea = new Tea();
6 | CaffeineBeverage coffee = new Coffee();
7 |
8 | System.out.println("\nMaking tea...");
9 | tea.prepareRecipe();
10 |
11 | System.out.println("\nMaking coffee...");
12 | coffee.prepareRecipe();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/beveragetest/CaffeineBeverage.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.beveragetest;
2 |
3 | public abstract class CaffeineBeverage {
4 | final void prepareRecipe() {
5 | boilWater();
6 | brew();
7 | pourInCup();
8 | if (customerWantsCondiments()) {
9 | addCondiments();
10 | }
11 | }
12 |
13 | abstract void brew();
14 |
15 | abstract void addCondiments();
16 |
17 | final void boilWater() {
18 | System.out.println("Boiling water");
19 | }
20 |
21 | final void pourInCup() {
22 | System.out.println("Pouring into cup");
23 | }
24 |
25 | // This is a hook method. A subclass can override this to provide its own functionality.
26 | boolean customerWantsCondiments() {
27 | return true;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/beveragetest/Coffee.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.beveragetest;
2 |
3 | public class Coffee extends CaffeineBeverage {
4 | @Override
5 | void brew() {
6 | System.out.println("Dripping Coffee through filter");
7 | }
8 |
9 | @Override
10 | void addCondiments() {
11 | System.out.println("Adding Sugar and Milk");
12 | }
13 |
14 | // Overrides the hook and provides its own functionality
15 | @Override
16 | boolean customerWantsCondiments() {
17 | String answer = GetUserInputUtil.getUserInput("Would you like milk and sugar with your coffee");
18 | return answer.toLowerCase().startsWith("y");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/beveragetest/GetUserInputUtil.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.beveragetest;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 |
7 | public class GetUserInputUtil {
8 | public static String getUserInput(String message) {
9 | String answer = null;
10 | System.out.print(message + " (y/n)? ");
11 | BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
12 |
13 | try {
14 | answer = input.readLine();
15 | } catch (IOException e) {
16 | System.err.println("IO error trying to read your answer");
17 | }
18 |
19 | if (answer == null) {
20 | return "n";
21 | }
22 | return answer;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/beveragetest/Tea.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.beveragetest;
2 |
3 | public class Tea extends CaffeineBeverage {
4 | @Override
5 | void brew() {
6 | System.out.println("Steeping the Tea");
7 | }
8 |
9 | @Override
10 | void addCondiments() {
11 | System.out.println("Adding Lemon");
12 | }
13 |
14 | // Overrides the hook and provides its own functionality
15 | @Override
16 | boolean customerWantsCondiments() {
17 | String answer = GetUserInputUtil.getUserInput("Would you like lemon with your tea");
18 | return answer.toLowerCase().startsWith("y");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/ducksorttest/Duck.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.ducksorttest;
2 |
3 | public class Duck implements Comparable {
4 | private final String name;
5 | private final int weight;
6 |
7 | public Duck(String name, int weight) {
8 | this.name = name;
9 | this.weight = weight;
10 | }
11 |
12 | @Override
13 | public String toString() {
14 | return String.format("%s weighs %d", name, weight);
15 | }
16 |
17 | @Override
18 | public int compareTo(Duck otherDuck) {
19 | return Integer.compare(weight, otherDuck.weight);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/08-template-method/src/main/java/org/example/templatemethod/ducksorttest/DuckSortTestDrive.java:
--------------------------------------------------------------------------------
1 | package org.example.templatemethod.ducksorttest;
2 |
3 | import java.util.Arrays;
4 |
5 | public class DuckSortTestDrive {
6 | public static void main(String[] args) {
7 | Duck[] ducks = {
8 | new Duck("Daffy", 8),
9 | new Duck("Dewey", 2),
10 | new Duck("Howard", 7),
11 | new Duck("Louie", 2),
12 | new Duck("Donald", 10),
13 | new Duck("Huey", 2)
14 | };
15 |
16 | System.out.println("Before sorting:");
17 | display(ducks);
18 |
19 | Arrays.sort(ducks);
20 |
21 | System.out.println("\nAfter sorting:");
22 | display(ducks);
23 | }
24 |
25 | private static void display(Duck[] ducks) {
26 | for (Duck duck : ducks) {
27 | System.out.println(duck);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/09-iterator-composite/README.md:
--------------------------------------------------------------------------------
1 | # THE ITERATOR AND COMPOSITE PATTERNS
2 | ## Well-Managed Collections
3 | ## 1. The Iterator Pattern
4 | ### 1.1. The Problem
5 |
6 | Objectville Diner and Objectville Pancake House is merging into one business, so they need to integrate their two menu implementations. However, a slight problem occurs.
7 |
8 | The Objectville Diner uses an `Array` to store the menu items, while the Objectville Pancake House stores their menu items in an `ArrayList`. Neither of them is willing to change their implementations because they have too much code that depends on those implementations.
9 |
10 | How would you help them to solve this problem?
11 |
12 | ### 1.2. The Definition of Iterator Pattern
13 |
14 | **The Iterator Pattern** provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
15 |
16 | ### 1.3. Demo Diagram
17 |
18 | 
19 |
20 | ## 2. The Composite Pattern
21 | ### 2.1. The Problem
22 |
23 | Come back to the above menus. They want to make their menus more flexible to contain even sub-menus, not only menu items. See the picture below for a demonstration. How will you structure their code to meet this requirement?
24 |
25 | 
26 |
27 | ### 2.2. The Definition of Composite Pattern
28 |
29 | **The Composite Pattern** allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
30 |
31 | 
32 |
33 | ### 2.3. Demo Diagram
34 |
35 | 
36 |
--------------------------------------------------------------------------------
/09-iterator-composite/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | design-patterns
7 | org.example
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | 09-iterator-composite
13 |
14 |
15 | 17
16 | 17
17 |
18 |
19 |
--------------------------------------------------------------------------------
/09-iterator-composite/src/main/java/org/example/iteratorcomposite/composite/Menu.java:
--------------------------------------------------------------------------------
1 | package org.example.iteratorcomposite.composite;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class Menu extends MenuComponent {
7 | private final List menuComponents = new ArrayList<>();
8 | private final String name;
9 | private final String description;
10 |
11 | public Menu(String name, String description) {
12 | this.name = name;
13 | this.description = description;
14 | }
15 |
16 | @Override
17 | public void add(MenuComponent menuComponent) {
18 | menuComponents.add(menuComponent);
19 | }
20 |
21 | @Override
22 | public void remove(MenuComponent menuComponent) {
23 | menuComponents.remove(menuComponent);
24 | }
25 |
26 | @Override
27 | public MenuComponent getChild(int i) {
28 | return menuComponents.get(i);
29 | }
30 |
31 | @Override
32 | public String getName() {
33 | return name;
34 | }
35 |
36 | @Override
37 | public String getDescription() {
38 | return description;
39 | }
40 |
41 | @Override
42 | public void print() {
43 | System.out.print("\n" + getName());
44 | System.out.println(", " + getDescription());
45 | System.out.println("---------------------");
46 |
47 | for (MenuComponent menuComponent : menuComponents) {
48 | menuComponent.print();
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/09-iterator-composite/src/main/java/org/example/iteratorcomposite/composite/MenuComponent.java:
--------------------------------------------------------------------------------
1 | package org.example.iteratorcomposite.composite;
2 |
3 | public abstract class MenuComponent {
4 | public void add(MenuComponent menuComponent) {
5 | throw new UnsupportedOperationException();
6 | }
7 | public void remove(MenuComponent menuComponent) {
8 | throw new UnsupportedOperationException();
9 | }
10 | public MenuComponent getChild(int i) {
11 | throw new UnsupportedOperationException();
12 | }
13 |
14 | public String getName() {
15 | throw new UnsupportedOperationException();
16 | }
17 | public String getDescription() {
18 | throw new UnsupportedOperationException();
19 | }
20 | public double getPrice() {
21 | throw new UnsupportedOperationException();
22 | }
23 | public boolean isVegetarian() {
24 | throw new UnsupportedOperationException();
25 | }
26 |
27 | public void print() {
28 | throw new UnsupportedOperationException();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/09-iterator-composite/src/main/java/org/example/iteratorcomposite/composite/MenuItem.java:
--------------------------------------------------------------------------------
1 | package org.example.iteratorcomposite.composite;
2 |
3 | public class MenuItem extends MenuComponent {
4 | private final String name;
5 | private final String description;
6 | private final boolean vegetarian;
7 | private final double price;
8 |
9 | public MenuItem(String name, String description, boolean vegetarian, double price) {
10 | this.name = name;
11 | this.description = description;
12 | this.vegetarian = vegetarian;
13 | this.price = price;
14 | }
15 |
16 | @Override
17 | public String getName() {
18 | return name;
19 | }
20 |
21 | @Override
22 | public String getDescription() {
23 | return description;
24 | }
25 |
26 | @Override
27 | public boolean isVegetarian() {
28 | return vegetarian;
29 | }
30 |
31 | @Override
32 | public double getPrice() {
33 | return price;
34 | }
35 |
36 | @Override
37 | public void print() {
38 | System.out.print(" " + getName());
39 | if (isVegetarian()) {
40 | System.out.print("(v)");
41 | }
42 | System.out.println(", " + getPrice());
43 | System.out.println(" -- " + getDescription());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/09-iterator-composite/src/main/java/org/example/iteratorcomposite/composite/MenuTestDrive.java:
--------------------------------------------------------------------------------
1 | package org.example.iteratorcomposite.composite;
2 |
3 | public class MenuTestDrive {
4 | public static void main(String[] args) {
5 | MenuComponent pancakeHouseMenu =
6 | new Menu("PANCAKE HOUSE MENU", "Breakfast");
7 | MenuComponent dinerMenu =
8 | new Menu("DINER MENU", "Lunch");
9 | MenuComponent cafeMenu =
10 | new Menu("CAFE MENU", "Dinner");
11 | MenuComponent dessertMenu =
12 | new Menu("DESSERT MENU", "Dessert of course!");
13 | MenuComponent coffeeMenu =
14 | new Menu("COFFEE MENU", "Stuff to go with your afternoon coffee");
15 |
16 | MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");
17 |
18 | allMenus.add(pancakeHouseMenu);
19 | allMenus.add(dinerMenu);
20 | allMenus.add(cafeMenu);
21 |
22 | pancakeHouseMenu.add(new MenuItem(
23 | "K&B's Pancake Breakfast",
24 | "Pancakes with scrambled eggs and toast",
25 | true,
26 | 2.99));
27 | pancakeHouseMenu.add(new MenuItem(
28 | "Regular Pancake Breakfast",
29 | "Pancakes with fried eggs, sausage",
30 | false,
31 | 2.99));
32 | pancakeHouseMenu.add(new MenuItem(
33 | "Blueberry Pancakes",
34 | "Pancakes made with fresh blueberries, and blueberry syrup",
35 | true,
36 | 3.49));
37 | pancakeHouseMenu.add(new MenuItem(
38 | "Waffles",
39 | "Waffles with your choice of blueberries or strawberries",
40 | true,
41 | 3.59));
42 |
43 | dinerMenu.add(new MenuItem(
44 | "Vegetarian BLT",
45 | "(Fakin') Bacon with lettuce & tomato on whole wheat",
46 | true,
47 | 2.99));
48 | dinerMenu.add(new MenuItem(
49 | "BLT",
50 | "Bacon with lettuce & tomato on whole wheat",
51 | false,
52 | 2.99));
53 | dinerMenu.add(new MenuItem(
54 | "Soup of the day",
55 | "A bowl of the soup of the day, with a side of potato salad",
56 | false,
57 | 3.29));
58 | dinerMenu.add(new MenuItem(
59 | "Hot Dog",
60 | "A hot dog, with saurkraut, relish, onions, topped with cheese",
61 | false,
62 | 3.05));
63 | dinerMenu.add(new MenuItem(
64 | "Steamed Veggies and Brown Rice",
65 | "Steamed vegetables over brown rice",
66 | true,
67 | 3.99));
68 | dinerMenu.add(new MenuItem(
69 | "Pasta",
70 | "Spaghetti with marinara sauce, and a slice of sourdough bread",
71 | true,
72 | 3.89));
73 |
74 | dinerMenu.add(dessertMenu);
75 |
76 | dessertMenu.add(new MenuItem(
77 | "Apple Pie",
78 | "Apple pie with a flakey crust, topped with vanilla icecream",
79 | true,
80 | 1.59));
81 | dessertMenu.add(new MenuItem(
82 | "Cheesecake",
83 | "Creamy New York cheesecake, with a chocolate graham crust",
84 | true,
85 | 1.99));
86 | dessertMenu.add(new MenuItem(
87 | "Sorbet",
88 | "A scoop of raspberry and a scoop of lime",
89 | true,
90 | 1.89));
91 |
92 | cafeMenu.add(new MenuItem(
93 | "Veggie Burger and Air Fries",
94 | "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
95 | true,
96 | 3.99));
97 | cafeMenu.add(new MenuItem(
98 | "Soup of the day",
99 | "A cup of the soup of the day, with a side salad",
100 | false,
101 | 3.69));
102 | cafeMenu.add(new MenuItem(
103 | "Burrito",
104 | "A large burrito, with whole pinto beans, salsa, guacamole",
105 | true,
106 | 4.29));
107 |
108 | cafeMenu.add(coffeeMenu);
109 |
110 | coffeeMenu.add(new MenuItem(
111 | "Coffee Cake",
112 | "Crumbly cake topped with cinnamon and walnuts",
113 | true,
114 | 1.59));
115 | coffeeMenu.add(new MenuItem(
116 | "Bagel",
117 | "Flavors include sesame, poppyseed, cinnamon raisin, pumpkin",
118 | false,
119 | 0.69));
120 | coffeeMenu.add(new MenuItem(
121 | "Biscotti",
122 | "Three almond or hazelnut biscotti cookies",
123 | true,
124 | 0.89));
125 |
126 | Waitress waitress = new Waitress(allMenus);
127 |
128 | waitress.printMenu();
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/09-iterator-composite/src/main/java/org/example/iteratorcomposite/composite/Waitress.java:
--------------------------------------------------------------------------------
1 | package org.example.iteratorcomposite.composite;
2 |
3 | public class Waitress {
4 | private final MenuComponent allMenus;
5 |
6 | public Waitress(MenuComponent allMenus) {
7 | this.allMenus = allMenus;
8 | }
9 |
10 | public void printMenu() {
11 | allMenus.print();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/09-iterator-composite/src/main/java/org/example/iteratorcomposite/iterator/CafeMenu.java:
--------------------------------------------------------------------------------
1 | package org.example.iteratorcomposite.iterator;
2 |
3 | import java.util.HashMap;
4 | import java.util.Iterator;
5 | import java.util.Map;
6 |
7 | public class CafeMenu implements Menu {
8 | private final Map menuItems = new HashMap<>();
9 |
10 | public CafeMenu() {
11 | addItem("Veggie Burger and Air Fries",
12 | "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
13 | true, 3.99);
14 | addItem("Soup of the day",
15 | "A cup of the soup of the day, with a side salad",
16 | false, 3.69);
17 | addItem("Burrito",
18 | "A large burrito, with whole pinto beans, salsa, guacamole",
19 | true, 4.29);
20 | }
21 |
22 | public void addItem(String name, String description, boolean vegetarian, double price) {
23 | MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
24 | menuItems.put(name, menuItem);
25 | }
26 |
27 | @Override
28 | public Iterator