diff --git a/README.md b/README.md index 9e0034c..3b8da8b 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 Command Design Pattern +Command encapsulate all information needed to perform an action. It allows the requester of a particular action to be decoupled from the object that performs the action. + +## Diagram +![Diagram](https://github.com/premaseem/DesignPatternsJava9/blob/command-pattern/diagrams/Command%20Design%20Pattern%20class%20diagram.jpeg "Diagram") + +![Diagram](https://github.com/premaseem/DesignPatternsJava9/blob/command-pattern/diagrams/Command-Design-Pattern-general%20-%20Page%201.png "Diagram") + +![Diagram](https://github.com/premaseem/DesignPatternsJava9/blob/command-pattern/diagrams/command%20sequence%20diagram.png "Diagram") + +### When to use Command Design Pattern +The invoker should be decoupled from the object handling the invocation. + +### 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/Command Design Pattern class diagram.jpeg b/diagrams/Command Design Pattern class diagram.jpeg new file mode 100644 index 0000000..0b4ed1d Binary files /dev/null and b/diagrams/Command Design Pattern class diagram.jpeg differ diff --git a/diagrams/Command-Design-Pattern-general - Page 1.png b/diagrams/Command-Design-Pattern-general - Page 1.png new file mode 100644 index 0000000..4039e14 Binary files /dev/null and b/diagrams/Command-Design-Pattern-general - Page 1.png differ diff --git a/diagrams/command sequence diagram.png b/diagrams/command sequence diagram.png new file mode 100644 index 0000000..9e5eb6f Binary files /dev/null and b/diagrams/command sequence diagram.png differ diff --git a/pattern/src/com/premaseem/Client.java b/pattern/src/com/premaseem/Client.java index 15f05df..2c38869 100644 --- a/pattern/src/com/premaseem/Client.java +++ b/pattern/src/com/premaseem/Client.java @@ -1,13 +1,55 @@ package com.premaseem; +import java.util.Scanner; + /* @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 "); + Scanner scanInput = new Scanner(System.in); + System.out.println("Light switch Project using COMMAND DESIGN PATTERN \n "); + + /** After implementing Command design pattern **/ + + // All available Commands will be created and init by command factory + CommandFactory cf = CommandFactory.init(); + + // Will list all commands which can be executed + cf.listCommands(); + + // Commands can be added and listed dynamically with ZERO code changes in client side + System.out.println("Master - what command you want to execute "); + String command = scanInput.next(); + + // Actual execution of command will happen + cf.executeCommand(command); + + /** Lessons Learnt - AFTER CODE + # New commands can be added dynamically with ease + # Client is loosely coupled and have no knowledge of encapsulated commands + # Zero code changed needed at client when new commands are added + */ + + + /** BEFORE CODE + // Assume you will invoke a method to execute turn on method + if (command.equalsIgnoreCase("LightOn")){ + System.out.println("Light turned on"); + } + else if (command.equalsIgnoreCase("LightOff")){ + System.out.println("Light turned off"); + } + else { + System.out.println(command+ " Command not found"); + } + + // Lessons Learnt - BEFORE CODE + // Lots of if else ladder + // Commands cannot be added Dynamically + // Code is tightly coupled, no separation of responsibility + */ } } diff --git a/pattern/src/com/premaseem/Command.java b/pattern/src/com/premaseem/Command.java new file mode 100644 index 0000000..038047c --- /dev/null +++ b/pattern/src/com/premaseem/Command.java @@ -0,0 +1,14 @@ +package com.premaseem; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ +/** + * The Command functional interface. + */ +@FunctionalInterface +public interface Command { + public void execute(); +} diff --git a/pattern/src/com/premaseem/CommandFactory.java b/pattern/src/com/premaseem/CommandFactory.java new file mode 100644 index 0000000..e1e8572 --- /dev/null +++ b/pattern/src/com/premaseem/CommandFactory.java @@ -0,0 +1,47 @@ +package com.premaseem; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +public final class CommandFactory { + private final Map commands; + + private CommandFactory() { + commands = new HashMap<>(); + } + + public void addCommand(final String name, final Command command) { + commands.put(name, command); + } + + public void executeCommand(String name) { + if (commands.containsKey(name)) { + commands.get(name).execute(); + }else{ + System.out.println(name+ " Command not found"); + } + } + + public void listCommands() { + System.out.println("Available commands: " + commands.keySet().stream().collect(Collectors.joining(", "))); + } + + /* Factory pattern */ + public static CommandFactory init() { + final CommandFactory cf = new CommandFactory(); + + // commands are added here using lambdas. + // It is also possible to dynamically add commands without editing the code. + cf.addCommand("LightOn", () -> System.out.println("Light turned on")); + cf.addCommand("LightOff", () -> System.out.println("Light turned off")); + + return cf; + } +} 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/commandPattern/ClientForRemoteControl.java b/patternBonus/src/com/premaseem/commandPattern/ClientForRemoteControl.java new file mode 100644 index 0000000..c2195bd --- /dev/null +++ b/patternBonus/src/com/premaseem/commandPattern/ClientForRemoteControl.java @@ -0,0 +1,41 @@ +package com.premaseem.commandPattern; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ + +import java.util.Scanner; + +public class ClientForRemoteControl { + + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int repeatRunFlag = 1; + RemoteControl remote = new RemoteControl(); + RemoteControlLoader loader = new RemoteControlLoader(remote); + loader.load(); + while (repeatRunFlag == 1) { + + System.out.println("This is the Client Main Command Pattern with Home Automation system "); + + System.out.println("Loading the remote with approviate commands and mapping them in slots ... "); + + System.out.println("Please press the any command between 0 to 10 for operation "); + System.out.println("Remember 11 is for Master off, \n 0 is for UNDO and \n 10 is undomacro mode"); + + + int remoteButtonNumber = scan.nextInt(); + remote.remoteButtonPress(remoteButtonNumber); + + 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 "); + try { + repeatRunFlag = scan.nextInt(); + } catch (Exception e) { + repeatRunFlag = 0; + } + } + } +} diff --git a/patternBonus/src/com/premaseem/commandPattern/Command.java b/patternBonus/src/com/premaseem/commandPattern/Command.java new file mode 100644 index 0000000..6c092c3 --- /dev/null +++ b/patternBonus/src/com/premaseem/commandPattern/Command.java @@ -0,0 +1,236 @@ +package com.premaseem.commandPattern; + +import java.util.Arrays; +import java.util.List; + +public interface Command { + public void execute (); + public void undo (); +} + + +class MasterOffcommand implements Command{ + List commandMacro; + public MasterOffcommand(Command... commands){ + commandMacro = Arrays.asList(commands); + } + + @Override + public void execute() { + for(Command cmd: commandMacro ){ + System.out.println("putting off "+ cmd.getClass().getSimpleName() ); + cmd.execute(); + } + + } + + @Override + public void undo() { + } +} + +class UndocommandMacro implements Command{ + RemoteControl remoteControl; + + public UndocommandMacro(RemoteControl Command){ + this.remoteControl = Command; + } + + @Override + public void execute() { + for(Command cmd: remoteControl.getCommandMacro() ){ + System.out.println("Undoing "+ cmd.getClass().getSimpleName() ); + cmd.undo(); + } + } + + @Override + public void undo() { + for(Command cmd: remoteControl.getCommandMacro() ) + cmd.undo(); + } +} + +class Undocommand implements Command{ + Command Lastcommand; + RemoteControl remoteControl; + + public Undocommand(RemoteControl Command){ + this.remoteControl = Command; + } + + @Override + public void execute() { + System.out.println(remoteControl.getLastCommand()); + remoteControl.getLastCommand().undo(); + } + + @Override + public void undo() { + remoteControl.getLastCommand().undo(); + } +} + + +class LightON implements Command{ + Light light; + public LightON(Light light){ + this.light = light; + } + @Override + public void execute() { + light.turnON(); + } + + @Override + public void undo() { + light.turnOFF(); + } +} + +class LightOFF implements Command{ + Light light; + public LightOFF(Light light){ + this.light = light; + } + @Override + public void execute() { + light.turnOFF(); + } + + @Override + public void undo() { + light.turnON(); + } +} + +class FanOFF implements Command{ + Fan device; + public FanOFF(Fan device){ + this.device = device; + } + @Override + public void execute() { + device.turnOFF(); + } + + @Override + public void undo() { + device.turnHIGH(); + } +} + +class FanLOW implements Command{ + Fan device; + public FanLOW(Fan device){ + this.device = device; + } + @Override + public void execute() { + device.turnLOW(); + } + + @Override + public void undo() { + device.turnHIGH(); + } +} + +class FanMEDIUM implements Command{ + Fan device; + public FanMEDIUM(Fan device){ + this.device = device; + } + @Override + public void execute() { + device.turnMED(); + } + + @Override + public void undo() { + device.turnHIGH(); + } +} + +class FanHIGH implements Command{ + Fan device; + public FanHIGH(Fan device){ + this.device = device; + } + @Override + public void execute() { + device.turnHIGH(); + } + + @Override + public void undo() { + device.turnOFF(); + } +} + + +class TVON implements Command{ + TV device; + public TVON(TV device){ + this.device = device; + } + @Override + public void execute() { + device.turnON(); + } + + @Override + public void undo() { + device.turnOFF(); + } +} + +class TVOFF implements Command{ + TV device; + public TVOFF(TV device){ + this.device = device; + } + @Override + public void execute() { + device.turnOFF(); + } + + @Override + public void undo() { + device.turnON(); + } +} + +class TVChannelUP implements Command{ + TV device; + public TVChannelUP(TV device){ + this.device = device; + } + @Override + public void execute() { + device.channelUP();; + } + + @Override + public void undo() { + device.channelDOWN(); + } +} + +class TVChannelDOWN implements Command{ + TV device; + public TVChannelDOWN(TV device){ + this.device = device; + } + @Override + public void execute() { + device.channelDOWN(); + } + + @Override + public void undo() { + device.channelUP(); + } +} + + diff --git a/patternBonus/src/com/premaseem/commandPattern/Device.java b/patternBonus/src/com/premaseem/commandPattern/Device.java new file mode 100644 index 0000000..d7274f2 --- /dev/null +++ b/patternBonus/src/com/premaseem/commandPattern/Device.java @@ -0,0 +1,83 @@ +package com.premaseem.commandPattern; + +/* +@author: Aseem Jain +@title: Design Patterns with Java 9 +@link: https://premaseem.wordpress.com/category/computers/design-patterns/ +*/ +public interface Device { + void turnOFF(); +} + + +// There are several 3rd component or devices. They would ack as reciever of the command. Each command object would wrap them. +class Light implements Device { + void turnON() { + System.out.println("Turn ON Light"); + } + + public void turnOFF() { + System.out.println("Turn OFF Light"); + } +} + +class Fan implements Device { + + public enum speed{ + OFF,LOW,MED,HIGH + } + speed fanSpeed; + + public void turnOFF() { + fanSpeed = speed.OFF; + System.out.println("Turn OFF FAN"); + } + void turnLOW() { + fanSpeed = speed.LOW; + System.out.println("Turn OFF FAN"); + } + void turnMED() { + fanSpeed = speed.MED; + System.out.println("Turn OFF FAN"); + } + void turnHIGH() { + fanSpeed = speed.HIGH; + System.out.println("Turn OFF FAN"); + } + +} + +class TV implements Device { + void turnON() { + System.out.println("Turn ON TV"); + } + + public void turnOFF () { + System.out.println("Turn OFF TV"); + } + void channelUP() { + System.out.println("Channel UP TV"); + } + + void channelDOWN() { + System.out.println("Channel Down TV"); + } + +} + +class MusicSystem implements Device { + void turnON() { + System.out.println("Turn ON Music System"); + } + + public void turnOFF () { + System.out.println("Turn OFF Music System"); + } + void volumeUP() { + System.out.println("Volume up Music System"); + } + + void volumeDOWN() { + System.out.println("Volume down Music System"); + } +} diff --git a/patternBonus/src/com/premaseem/commandPattern/RemoteControl.java b/patternBonus/src/com/premaseem/commandPattern/RemoteControl.java new file mode 100644 index 0000000..7a888ea --- /dev/null +++ b/patternBonus/src/com/premaseem/commandPattern/RemoteControl.java @@ -0,0 +1,35 @@ +package com.premaseem.commandPattern; + +import java.util.ArrayList; +import java.util.List; + +public class RemoteControl { + + List slots = new ArrayList(15); + Command lastCommand; + List commandMacro = new ArrayList(3); + + public List getCommandMacro() { + return commandMacro; + } + + public Command getLastCommand() { + return lastCommand; + } + + public void setLastCommand(Command lastCommand) { + this.lastCommand = lastCommand; + } + + public void setCommandOnSlot( int i,Command cmd) { + slots.add(i, cmd); + } + + public void remoteButtonPress(int keyNumber){ + Command command = slots.get(keyNumber); + command.execute(); + setLastCommand(command); + commandMacro.add(command); + } +} + diff --git a/patternBonus/src/com/premaseem/commandPattern/RemoteControlLoader.java b/patternBonus/src/com/premaseem/commandPattern/RemoteControlLoader.java new file mode 100644 index 0000000..d242748 --- /dev/null +++ b/patternBonus/src/com/premaseem/commandPattern/RemoteControlLoader.java @@ -0,0 +1,37 @@ +package com.premaseem.commandPattern; + +public class RemoteControlLoader { + + RemoteControl remote; + + public RemoteControlLoader(RemoteControl remote) { + this.remote = remote; + } + + public void load() { + // Create instance of 3rd party devices + Light light = new Light(); + Fan fan = new Fan(); + TV tv = new TV(); + +// Command cmd = new LightON(light); + remote.setCommandOnSlot(0,new Undocommand(remote)); + remote.setCommandOnSlot(1,new LightON(light)); + LightOFF lightOff = new LightOFF(light); + remote.setCommandOnSlot(2,lightOff); + FanOFF fanOff = new FanOFF(fan); + remote.setCommandOnSlot(3,fanOff); + remote.setCommandOnSlot(4,new FanLOW(fan)); + remote.setCommandOnSlot(5,new FanMEDIUM(fan)); + remote.setCommandOnSlot(6,new FanHIGH(fan)); + remote.setCommandOnSlot(7,new TVON(tv)); + TVOFF tvOff = new TVOFF(tv); + remote.setCommandOnSlot(8,tvOff); + remote.setCommandOnSlot(9,new TVChannelUP(tv)); + remote.setCommandOnSlot(10,new UndocommandMacro(remote)); + remote.setCommandOnSlot(11,new MasterOffcommand(lightOff,fanOff,tvOff)); + + + } +} +