diff --git a/README.md b/README.md index 9e0034c..a5c2d18 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,32 @@ -# DesignPatternsJava9 -This repo consists Gang of Four Design patterns code on Java 9. Each branch in the repository has code of 1 design pattern. Switch repository to try out different design patterns. +# What is Decorator Design Pattern +Decorator pattern allows a user to add new functionality to an existing object without altering its structure.This pattern creates a decorator class which wraps the original class and provides additional functionality keeping the class methods signature intact. + +## Diagram +![Diagram](https://github.com/premaseem/DesignPatternsJava9/blob/decorator-pattern/diagrams/Decorator%20Pattern%20class%20diagram.jpeg "Diagram") + +![Diagram](https://github.com/premaseem/DesignPatternsJava9/blob/decorator-pattern/diagrams/4477491529_462d9dd985_b.jpeg "Diagram") + +![Diagram](https://github.com/premaseem/DesignPatternsJava9/blob/decorator-pattern/diagrams/Decorator%20pattern%20sequence%20diagram.png "Diagram") + +### When to use Decorator Design Pattern +When you want to get rid of too many sub classes by creating separate class for each combination. + +### Learn Design Patterns with Java by Aseem Jain +This repository contains working project code used in video Course by Packt Publication with title "Learn Design Patterns with Java " authored by "Aseem Jain". + +### Course link: +https://www.packtpub.com/application-development/learn-design-patterns-java-9-video + +### ![ http://in.linkedin.com/in/premaseem](https://github.com/premaseem/DesignPatternsJava9/blob/master/linkedin.png "http://in.linkedin.com/in/premaseem") Profile: http://in.linkedin.com/in/premaseem + +### Authors blog on design patterns: +https://premaseem.wordpress.com/category/computers/design-patterns/ + +### Software Design pattern community face book page: +https://www.facebook.com/DesignPatternGuru/ + +### Note: +* This code base will work on Java 9 and above versions. +* `diagrams` folders carry UML diagrams. +* `pattern` folder has code of primary example. +* `patternBonus` folder has code of secondary or bonus example. diff --git a/diagrams/4477491529_462d9dd985_b.jpeg b/diagrams/4477491529_462d9dd985_b.jpeg new file mode 100644 index 0000000..4addf66 Binary files /dev/null and b/diagrams/4477491529_462d9dd985_b.jpeg differ diff --git a/diagrams/Decorator Pattern class diagram.jpeg b/diagrams/Decorator Pattern class diagram.jpeg new file mode 100644 index 0000000..42a40e5 Binary files /dev/null and b/diagrams/Decorator Pattern class diagram.jpeg differ diff --git a/diagrams/Decorator pattern sequence diagram.png b/diagrams/Decorator pattern sequence diagram.png new file mode 100644 index 0000000..13b4b71 Binary files /dev/null and b/diagrams/Decorator pattern sequence diagram.png differ diff --git a/pattern/src/com/premaseem/Cake.java b/pattern/src/com/premaseem/Cake.java new file mode 100644 index 0000000..1efd4ad --- /dev/null +++ b/pattern/src/com/premaseem/Cake.java @@ -0,0 +1,79 @@ +package com.premaseem; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ +public abstract class Cake { + + abstract String getIngredients(); + abstract double getCost(); + +} + +class VanillaCake extends Cake { + + @Override + String getIngredients () { + return " Vanilla "; + } + + @Override + double getCost () { + return 2; + } +} + +class VanillaCakeWithCandyDecoration extends Cake { + + @Override + String getIngredients () { + return " Vanilla and Candy "; + } + + @Override + double getCost () { + return 2.4; + } +} + +class VanillaCakeWithCandyAndCartoonDecoration extends Cake { + + @Override + String getIngredients () { + return " Vanilla and candy and cartoon "; + } + + @Override + double getCost () { + return 5.4; + } +} + +class VanillaCakeWithCartoonDecoration extends Cake { + + @Override + String getIngredients () { + return " Vanilla and cartoon "; + } + + @Override + double getCost () { + return 4.4; + } +} + +class ChocolateCake extends Cake { + + @Override + String getIngredients () { + return " Chocolate "; + } + + @Override + double getCost () { + return 3; + } +} + diff --git a/pattern/src/com/premaseem/Client.java b/pattern/src/com/premaseem/Client.java index 15f05df..07fd179 100644 --- a/pattern/src/com/premaseem/Client.java +++ b/pattern/src/com/premaseem/Client.java @@ -4,10 +4,56 @@ @author: Aseem Jain @title: Design Patterns with Java 9 @link: https://premaseem.wordpress.com/category/computers/design-patterns/ -@copyright: 2018 Packt Publication */ + public class Client { public static void main (String[] args) { - System.out.println("Singleton cook example "); + System.out.println("Decorator Pattern example with Cake decoration project"); + + // Plain Object + Cake cake = new VanillaCake(); + System.out.println("Plain cake price without decorations - "+ cake.getCost()); + + // Decorated Object with addons + cake = new CandyDecoration(cake); + System.out.println("Cake price with Candy decoration - "+ cake.getCost()); + + // Decorated Object with addons + // Fun side, price of Cartoon decoration is more then cake itself :-) + cake = new CartoonDecoration(cake); + cake = new CartoonDecoration(cake); + System.out.println("Cake price with double Cartoon decoration - "+cake.getCost()); + + + /* TAKE AWAY: + 1. Lean code - as its not required to create class for each option + 2. Price can be calculated dynamically + 3. Performance improvement + 4. Loose coupling. + 5. Easy to update - price of can be updated at one place without touching other classes. + + */ + + /* OLD DISCARDED CODE + // with decoration + cake = new VanillaCakeWithCandyDecoration(); + System.out.println("Cake price with Candy decoration - "+ cake.getCost()); + + // with decoration + cake = new VanillaCakeWithCartoonDecoration(); + System.out.println("Cake price with Cartoon decoration - "+ cake.getCost()); + + // with multiple decorations + cake = new VanillaCakeWithCandyAndCartoonDecoration(); + System.out.println("Cake price with Candy and Cartoon decoration - "+ cake.getCost()); + */ + + /*Take Away from Bad Code: + 1. For each combination/ option there is a static class. + 2. With less options its ok but in real cake software time application will + blow out of proportion due to so many classes. + 3. Updating price of even one option will impact several classes. + */ + } } diff --git a/pattern/src/com/premaseem/Decoration.java b/pattern/src/com/premaseem/Decoration.java new file mode 100644 index 0000000..11b641c --- /dev/null +++ b/pattern/src/com/premaseem/Decoration.java @@ -0,0 +1,54 @@ +package com.premaseem; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ + +public abstract class Decoration extends Cake{ + Cake cake; + + @Override + String getIngredients () { + return "decoration using different addon items"; + } +} + +class CandyDecoration extends Decoration{ + + Cake baseCake; + + public CandyDecoration (Cake cake) { + baseCake = cake; + } + + @Override + double getCost () { + return baseCake.getCost() + .12; + } + + @Override + String getIngredients () { + return "decoration using candies"; + } +} + +class CartoonDecoration extends Decoration{ + + Cake baseCake; + + public CartoonDecoration (Cake cake) { + baseCake = cake; + } + + @Override + double getCost () { + return baseCake.getCost() + 2.32; + } + + @Override + String getIngredients () { + return "decoration using candies"; + } +} \ No newline at end of file diff --git a/patternBonus/src/com/premaseem/Client.java b/patternBonus/src/com/premaseem/Client.java deleted file mode 100644 index 15f05df..0000000 --- a/patternBonus/src/com/premaseem/Client.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.premaseem; - -/* -@author: Aseem Jain -@title: Design Patterns with Java 9 -@link: https://premaseem.wordpress.com/category/computers/design-patterns/ -@copyright: 2018 Packt Publication -*/ -public class Client { - public static void main (String[] args) { - System.out.println("Singleton cook example "); - } -} diff --git a/patternBonus/src/com/premaseem/client/ClientCoffeeBillingMachine.java b/patternBonus/src/com/premaseem/client/ClientCoffeeBillingMachine.java new file mode 100644 index 0000000..5a64618 --- /dev/null +++ b/patternBonus/src/com/premaseem/client/ClientCoffeeBillingMachine.java @@ -0,0 +1,65 @@ +package com.premaseem.client; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ + +import java.util.Scanner; + +import com.premaseem.decorator.AbstractCoffee; +import com.premaseem.decorator.addons.Chokos; +import com.premaseem.decorator.addons.Cream; +import com.premaseem.decorator.addons.Whip; +import com.premaseem.decorator.basecoffee.ColdCoffee; +import com.premaseem.decorator.basecoffee.HotCoffee; + +public class ClientCoffeeBillingMachine { + + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int repeatRunFlag = 1; + while (repeatRunFlag == 1) { + + System.out.println("Welcome to Coffee Billing Machine Project which uses Decorator Design pattern ... "); + + System.out.println("What kind of coffee would you like to have ? "); + System.out.println("Press 1 for Hot Coffee "); + System.out.println("Press 2 for Cold Coffee "); + Integer coffeeType = scan.nextInt(); + AbstractCoffee coffee; + if(coffeeType == 1){ + coffee = new HotCoffee(); + }else{ + coffee = new ColdCoffee(); + } + + System.out.println("Do you want Cream ? "); + System.out.println("Press 1 for YES and 0 for NO "); + + if(scan.nextInt() == 1){ + coffee = new Cream(coffee); + } + + System.out.println("Do you want Whip ? "); + System.out.println("Press 1 for YES and 0 for NO "); + if(scan.nextInt() == 1){ + coffee = new Whip(coffee); + } + + System.out.println("Do you want Chokos ? "); + System.out.println("Press 1 for YES and 0 for NO "); + if(scan.nextInt() == 1){ + coffee = new Chokos(coffee); + } + + System.out.println("Your final order is"); + System.out.println(coffee.getDescription()); + System.out.println("Total cost of order is " + coffee.getCost()); + System.out.println("\n $$$$$$$$$$$$$$$$$$$$ Thanks by Prem Aseem $$$$$$$$$$$$$$$$$$$$$$ \n "); + System.out.println("Do you want to Re-run this program - Press 1 for yes and 0 or other digits to EXIT "); + repeatRunFlag = scan.nextInt(); + } + } +} diff --git a/patternBonus/src/com/premaseem/decorator/AbstractCoffee.java b/patternBonus/src/com/premaseem/decorator/AbstractCoffee.java new file mode 100644 index 0000000..943ff64 --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/AbstractCoffee.java @@ -0,0 +1,26 @@ +package com.premaseem.decorator; + +public abstract class AbstractCoffee { + + String description = " This is HOT/COLD coffee and has xx xx "; + String name = "HOT/COLD coffee "; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public abstract Double getCost(); +} + diff --git a/patternBonus/src/com/premaseem/decorator/addons/AddonsOfCoffee.java b/patternBonus/src/com/premaseem/decorator/addons/AddonsOfCoffee.java new file mode 100644 index 0000000..ff4ceb5 --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/addons/AddonsOfCoffee.java @@ -0,0 +1,9 @@ +package com.premaseem.decorator.addons; + +import com.premaseem.decorator.AbstractCoffee; + +public abstract class AddonsOfCoffee extends AbstractCoffee { + +@Override +abstract public String getDescription(); +} diff --git a/patternBonus/src/com/premaseem/decorator/addons/Chokos.java b/patternBonus/src/com/premaseem/decorator/addons/Chokos.java new file mode 100644 index 0000000..50b8dba --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/addons/Chokos.java @@ -0,0 +1,23 @@ +package com.premaseem.decorator.addons; + +import com.premaseem.decorator.AbstractCoffee; + +public class Chokos extends AddonsOfCoffee { + + public AbstractCoffee coffee =null; + + public Chokos(AbstractCoffee abstractCoffee){ + this.coffee = abstractCoffee; + } + + @Override + public String getDescription() { + return coffee.getDescription() + " chocolate " ; + } + + @Override + public Double getCost() { + return coffee.getCost() + 0.17; + } + +} diff --git a/patternBonus/src/com/premaseem/decorator/addons/Cream.java b/patternBonus/src/com/premaseem/decorator/addons/Cream.java new file mode 100644 index 0000000..8d6e638 --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/addons/Cream.java @@ -0,0 +1,23 @@ +package com.premaseem.decorator.addons; + +import com.premaseem.decorator.AbstractCoffee; + +public class Cream extends AddonsOfCoffee { + + public AbstractCoffee coffee =null; + + public Cream(AbstractCoffee abstractCoffee){ + this.coffee = abstractCoffee; + } + + @Override + public String getDescription() { + return coffee.getDescription() + " cream " ; + } + + @Override + public Double getCost() { + return coffee.getCost() + 0.15; + } + +} diff --git a/patternBonus/src/com/premaseem/decorator/addons/Whip.java b/patternBonus/src/com/premaseem/decorator/addons/Whip.java new file mode 100644 index 0000000..1aa3846 --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/addons/Whip.java @@ -0,0 +1,23 @@ +package com.premaseem.decorator.addons; + +import com.premaseem.decorator.AbstractCoffee; + +public class Whip extends AddonsOfCoffee { + + public AbstractCoffee coffee =null; + + public Whip(AbstractCoffee abstractCoffee){ + this.coffee = abstractCoffee; + } + + @Override + public String getDescription() { + return coffee.getDescription() + " whip " ; + } + + @Override + public Double getCost() { + return coffee.getCost() + 0.28; + } + +} diff --git a/patternBonus/src/com/premaseem/decorator/basecoffee/ColdCoffee.java b/patternBonus/src/com/premaseem/decorator/basecoffee/ColdCoffee.java new file mode 100644 index 0000000..ffb20dd --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/basecoffee/ColdCoffee.java @@ -0,0 +1,16 @@ +package com.premaseem.decorator.basecoffee; + +import com.premaseem.decorator.AbstractCoffee; + +public class ColdCoffee extends AbstractCoffee { + + public ColdCoffee (){ + setName("Cold Coffee "); + setDescription("Cold coffee with - "); + } + + @Override + public Double getCost() { + return 22.0; + } +} diff --git a/patternBonus/src/com/premaseem/decorator/basecoffee/HotCoffee.java b/patternBonus/src/com/premaseem/decorator/basecoffee/HotCoffee.java new file mode 100644 index 0000000..41196b5 --- /dev/null +++ b/patternBonus/src/com/premaseem/decorator/basecoffee/HotCoffee.java @@ -0,0 +1,18 @@ +package com.premaseem.decorator.basecoffee; + +import com.premaseem.decorator.AbstractCoffee; + +public class HotCoffee extends AbstractCoffee { + + public HotCoffee (){ + setName("Hot Coffee "); + setDescription(" Hot coffee with - "); + } + + + @Override + public Double getCost() { + return 10.0; + } + +}