Skip to content

Commit 7d34320

Browse files
Merge pull request #20 from darbyluv2code/feature/add-command-pattern
Add Command Pattern
2 parents 43cdea0 + a89d1e4 commit 7d34320

File tree

11 files changed

+379
-0
lines changed

11 files changed

+379
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.luv2code</groupId>
8+
<artifactId>java-design-patterns</artifactId>
9+
<version>1.0</version>
10+
11+
<properties>
12+
<maven.compiler.source>25</maven.compiler.source>
13+
<maven.compiler.target>25</maven.compiler.target>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
17+
</project>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: Receiver
5+
*
6+
* Knows how to perform the actual lighting operations.
7+
* Has no knowledge of the Command pattern.
8+
*/
9+
public class Light {
10+
11+
private String location;
12+
13+
public Light(String location) {
14+
this.location = location;
15+
}
16+
17+
public String getLocation() {
18+
return location;
19+
}
20+
21+
public void turnOn() {
22+
System.out.println("[Device] " + location + " light -> ON");
23+
}
24+
25+
public void turnOff() {
26+
System.out.println("[Device] " + location + " light -> OFF");
27+
}
28+
29+
}
30+
31+
32+
33+
34+
35+
36+
37+
38+
39+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: ConcreteCommand
5+
*
6+
* Turns a Light off.
7+
* Undo turns the light on.
8+
*/
9+
public class LightOffCommand implements SmartHomeCommand {
10+
11+
private Light light;
12+
13+
public LightOffCommand(Light light) {
14+
this.light = light;
15+
}
16+
17+
@Override
18+
public void execute() {
19+
light.turnOff();
20+
}
21+
22+
@Override
23+
public void undo() {
24+
light.turnOn();
25+
}
26+
27+
@Override
28+
public String getDescription() {
29+
return "Turn " + light.getLocation() + " light OFF";
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: ConcreteCommand
5+
*
6+
* Turns a Light on.
7+
* Undo turns the light off.
8+
*/
9+
public class LightOnCommand implements SmartHomeCommand {
10+
11+
private Light light;
12+
13+
public LightOnCommand(Light light) {
14+
this.light = light;
15+
}
16+
17+
@Override
18+
public void execute() {
19+
light.turnOn();
20+
}
21+
22+
@Override
23+
public void undo() {
24+
light.turnOff();
25+
}
26+
27+
@Override
28+
public String getDescription() {
29+
return "Turn " + light.getLocation() + " light ON";
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: Client
5+
*
6+
* Demonstrates the Command pattern.
7+
* The RemoteControl (Invoker) is reused across all demos without modification.
8+
*/
9+
public class MainApp {
10+
11+
static void main() {
12+
13+
System.out.println("--- Demo 1: Smart Home Demo ---");
14+
runSmartHomeDemo();
15+
16+
System.out.println("\n--- Demo 2: Thermostat Demo ---");
17+
runThermostatDemo();
18+
19+
System.out.println("\n--- Demo 3: Pet Food Demo ---");
20+
runPetFoodDemo();
21+
}
22+
23+
private static void runPetFoodDemo() {
24+
25+
PetFoodDispenser petFoodDispenser = new PetFoodDispenser("Max");
26+
RemoteControl remoteControl = new RemoteControl();
27+
28+
remoteControl.pressButton(new PetFoodDispenserCommand(petFoodDispenser));
29+
30+
// Attempting undo
31+
remoteControl.pressUndo();
32+
}
33+
34+
private static void runThermostatDemo() {
35+
36+
Thermostat thermostat = new Thermostat(18);
37+
RemoteControl remoteControl = new RemoteControl();
38+
39+
remoteControl.pressButton(new ThermostatSetCommand(thermostat, 22));
40+
41+
System.out.println("\n-- Undoing temperature change ---");
42+
remoteControl.pressUndo();
43+
}
44+
45+
private static void runSmartHomeDemo() {
46+
47+
Light livingRoomLight = new Light("Living Room");
48+
RemoteControl remoteControl = new RemoteControl();
49+
50+
remoteControl.pressButton(new LightOnCommand(livingRoomLight));
51+
remoteControl.pressButton(new LightOffCommand(livingRoomLight));
52+
53+
System.out.println();
54+
remoteControl.printHistory();
55+
}
56+
}
57+
58+
59+
60+
61+
62+
63+
64+
65+
66+
67+
68+
69+
70+
71+
72+
73+
74+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: Receiver
5+
*
6+
* Knows how to dispense a single serving of pet food.
7+
* Has no knowledge of the Command pattern.
8+
*/
9+
public class PetFoodDispenser {
10+
11+
private String petName;
12+
13+
public PetFoodDispenser(String petName) {
14+
this.petName = petName;
15+
}
16+
17+
public void dispense() {
18+
System.out.println("[Device] Dispensing one serving for " + petName);
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: ConcreteCommand
5+
*
6+
* Dispenses a single serving of pet food.
7+
* This action is irreversible - undo does nothing.
8+
*/
9+
public class PetFoodDispenserCommand implements SmartHomeCommand {
10+
11+
private PetFoodDispenser petFoodDispenser;
12+
13+
public PetFoodDispenserCommand(PetFoodDispenser petFoodDispenser) {
14+
this.petFoodDispenser = petFoodDispenser;
15+
}
16+
17+
@Override
18+
public void execute() {
19+
petFoodDispenser.dispense();
20+
}
21+
22+
@Override
23+
public void undo() {
24+
System.out.println("[Command] Cannot undo: food already dispensed.");
25+
}
26+
27+
@Override
28+
public String getDescription() {
29+
return "Dispense pet food serving";
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
import java.util.ArrayDeque;
4+
import java.util.Deque;
5+
6+
/**
7+
* Role: Invoker
8+
*
9+
* Triggers commands and maintains a history stack for undo support.
10+
* Depends only on the SmartHomeCommand interface.
11+
*/
12+
public class RemoteControl {
13+
14+
private Deque<SmartHomeCommand> history = new ArrayDeque<>();
15+
16+
public void pressButton(SmartHomeCommand command) {
17+
if (command == null) {
18+
throw new IllegalArgumentException("Command cannot be null");
19+
}
20+
21+
command.execute();
22+
history.push(command);
23+
}
24+
25+
public void pressUndo() {
26+
if (history.isEmpty()) {
27+
System.out.println("[Remote] Nothing to undo.");
28+
}
29+
30+
SmartHomeCommand command = history.pop();
31+
System.out.println("[Remote] Undoing: " + command.getDescription());
32+
command.undo();
33+
}
34+
35+
public void printHistory() {
36+
System.out.println("[Remote] Command History (most recent first):");
37+
38+
if (history.isEmpty()) {
39+
System.out.println(" (empty)");
40+
} else {
41+
for (SmartHomeCommand tempCommand : history) {
42+
System.out.println(" - " + tempCommand.getDescription());
43+
}
44+
}
45+
}
46+
47+
}
48+
49+
50+
51+
52+
53+
54+
55+
56+
57+
58+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: Command
5+
*
6+
* Declares the contract for all smart home commands.
7+
* Every concrete command must support execute, undo and a description.
8+
*/
9+
public interface SmartHomeCommand {
10+
11+
void execute();
12+
13+
void undo();
14+
15+
String getDescription();
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.luv2code.designpatterns.behavioral.command;
2+
3+
/**
4+
* Role: Receiver
5+
*
6+
* Knows how to perform temperature changes.
7+
* Has no knowledge of the Command pattern.
8+
*/
9+
public class Thermostat {
10+
11+
private int temperatureCelsius;
12+
13+
public Thermostat(int temperatureCelsius) {
14+
this.temperatureCelsius = temperatureCelsius;
15+
}
16+
17+
public int getTemperatureCelsius() {
18+
return temperatureCelsius;
19+
}
20+
21+
public void setTemperatureCelsius(int temperatureCelsius) {
22+
System.out.println("[Device] Thermostat: " + this.temperatureCelsius
23+
+ "C -> " + temperatureCelsius + "C");
24+
this.temperatureCelsius = temperatureCelsius;
25+
}
26+
}

0 commit comments

Comments
 (0)