Skip to content

Commit 30ac97f

Browse files
committed
docs: update Command documentation
1 parent 8471c93 commit 30ac97f

File tree

1 file changed

+144
-113
lines changed

1 file changed

+144
-113
lines changed

command/README.md

Lines changed: 144 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ title: Command
33
category: Behavioral
44
language: en
55
tag:
6-
- Gang of Four
6+
- Gang of Four
77
---
88

99
## Also known as
1010

11-
Action, Transaction
11+
* Action
12+
* Transaction
1213

1314
## Intent
1415

15-
Encapsulate a request as an object, thereby letting you parameterize clients with different
16-
requests, queue or log requests, and support undoable operations.
16+
The Command design pattern encapsulates a request as an object, thereby allowing for parameterization of clients with
17+
queues, requests, and operations. It also allows for the support of undoable operations.
1718

1819
## Explanation
20+
1921
Real-world example
2022

2123
> There is a wizard casting spells on a goblin. The spells are executed on the goblin one by one.
@@ -37,155 +39,158 @@ Wikipedia says
3739
Here's the sample code with wizard and goblin. Let's start from the `Wizard` class.
3840

3941
```java
42+
4043
@Slf4j
4144
public class Wizard {
4245

43-
private final Deque<Runnable> undoStack = new LinkedList<>();
44-
private final Deque<Runnable> redoStack = new LinkedList<>();
46+
private final Deque<Runnable> undoStack = new LinkedList<>();
47+
private final Deque<Runnable> redoStack = new LinkedList<>();
4548

46-
public Wizard() {}
49+
public Wizard() {
50+
}
4751

48-
public void castSpell(Runnable runnable) {
49-
runnable.run();
50-
undoStack.offerLast(runnable);
51-
}
52+
public void castSpell(Runnable runnable) {
53+
runnable.run();
54+
undoStack.offerLast(runnable);
55+
}
5256

53-
public void undoLastSpell() {
54-
if (!undoStack.isEmpty()) {
55-
var previousSpell = undoStack.pollLast();
56-
redoStack.offerLast(previousSpell);
57-
previousSpell.run();
57+
public void undoLastSpell() {
58+
if (!undoStack.isEmpty()) {
59+
var previousSpell = undoStack.pollLast();
60+
redoStack.offerLast(previousSpell);
61+
previousSpell.run();
62+
}
5863
}
59-
}
6064

61-
public void redoLastSpell() {
62-
if (!redoStack.isEmpty()) {
63-
var previousSpell = redoStack.pollLast();
64-
undoStack.offerLast(previousSpell);
65-
previousSpell.run();
65+
public void redoLastSpell() {
66+
if (!redoStack.isEmpty()) {
67+
var previousSpell = redoStack.pollLast();
68+
undoStack.offerLast(previousSpell);
69+
previousSpell.run();
70+
}
6671
}
67-
}
6872

69-
@Override
70-
public String toString() {
71-
return "Wizard";
72-
}
73+
@Override
74+
public String toString() {
75+
return "Wizard";
76+
}
7377
}
7478
```
7579

7680
Next, we have the goblin who's the target of the spells.
7781

7882
```java
83+
7984
@Slf4j
8085
public abstract class Target {
8186

82-
private Size size;
87+
private Size size;
8388

84-
private Visibility visibility;
89+
private Visibility visibility;
8590

86-
public Size getSize() {
87-
return size;
88-
}
91+
public Size getSize() {
92+
return size;
93+
}
8994

90-
public void setSize(Size size) {
91-
this.size = size;
92-
}
95+
public void setSize(Size size) {
96+
this.size = size;
97+
}
9398

94-
public Visibility getVisibility() {
95-
return visibility;
96-
}
99+
public Visibility getVisibility() {
100+
return visibility;
101+
}
97102

98-
public void setVisibility(Visibility visibility) {
99-
this.visibility = visibility;
100-
}
103+
public void setVisibility(Visibility visibility) {
104+
this.visibility = visibility;
105+
}
101106

102-
@Override
103-
public abstract String toString();
107+
@Override
108+
public abstract String toString();
104109

105-
public void printStatus() {
106-
LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility());
107-
}
110+
public void printStatus() {
111+
LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility());
112+
}
108113
}
109114

110115
public class Goblin extends Target {
111116

112-
public Goblin() {
113-
setSize(Size.NORMAL);
114-
setVisibility(Visibility.VISIBLE);
115-
}
116-
117-
@Override
118-
public String toString() {
119-
return "Goblin";
120-
}
121-
122-
public void changeSize() {
123-
var oldSize = getSize() == Size.NORMAL ? Size.SMALL : Size.NORMAL;
124-
setSize(oldSize);
125-
}
126-
127-
public void changeVisibility() {
128-
var visible = getVisibility() == Visibility.INVISIBLE
129-
? Visibility.VISIBLE : Visibility.INVISIBLE;
130-
setVisibility(visible);
131-
}
117+
public Goblin() {
118+
setSize(Size.NORMAL);
119+
setVisibility(Visibility.VISIBLE);
120+
}
121+
122+
@Override
123+
public String toString() {
124+
return "Goblin";
125+
}
126+
127+
public void changeSize() {
128+
var oldSize = getSize() == Size.NORMAL ? Size.SMALL : Size.NORMAL;
129+
setSize(oldSize);
130+
}
131+
132+
public void changeVisibility() {
133+
var visible = getVisibility() == Visibility.INVISIBLE
134+
? Visibility.VISIBLE : Visibility.INVISIBLE;
135+
setVisibility(visible);
136+
}
132137
}
133138
```
134139

135140
Finally, we have the wizard in the main function casting spells.
136141

137142
```java
138-
public static void main(String[] args) {
139-
var wizard = new Wizard();
140-
var goblin = new Goblin();
143+
public static void main(String[]args){
144+
var wizard=new Wizard();
145+
var goblin=new Goblin();
141146

142-
// casts shrink/unshrink spell
143-
wizard.castSpell(goblin::changeSize);
147+
// casts shrink/unshrink spell
148+
wizard.castSpell(goblin::changeSize);
144149

145-
// casts visible/invisible spell
146-
wizard.castSpell(goblin::changeVisibility);
150+
// casts visible/invisible spell
151+
wizard.castSpell(goblin::changeVisibility);
147152

148-
// undo and redo casts
149-
wizard.undoLastSpell();
150-
wizard.redoLastSpell();
153+
// undo and redo casts
154+
wizard.undoLastSpell();
155+
wizard.redoLastSpell();
151156
```
152157

153158
Here's the whole example in action.
154159
155160
```java
156-
var wizard = new Wizard();
157-
var goblin = new Goblin();
161+
var wizard=new Wizard();
162+
var goblin=new Goblin();
158163
159-
goblin.printStatus();
160-
wizard.castSpell(goblin::changeSize);
161-
goblin.printStatus();
164+
goblin.printStatus();
165+
wizard.castSpell(goblin::changeSize);
166+
goblin.printStatus();
162167
163-
wizard.castSpell(goblin::changeVisibility);
164-
goblin.printStatus();
168+
wizard.castSpell(goblin::changeVisibility);
169+
goblin.printStatus();
165170
166-
wizard.undoLastSpell();
167-
goblin.printStatus();
171+
wizard.undoLastSpell();
172+
goblin.printStatus();
168173
169-
wizard.undoLastSpell();
170-
goblin.printStatus();
174+
wizard.undoLastSpell();
175+
goblin.printStatus();
171176
172-
wizard.redoLastSpell();
173-
goblin.printStatus();
177+
wizard.redoLastSpell();
178+
goblin.printStatus();
174179
175-
wizard.redoLastSpell();
176-
goblin.printStatus();
180+
wizard.redoLastSpell();
181+
goblin.printStatus();
177182
```
178183
179184
Here's the program output:
180185

181186
```java
182-
Goblin, [size=normal] [visibility=visible]
183-
Goblin, [size=small] [visibility=visible]
184-
Goblin, [size=small] [visibility=invisible]
185-
Goblin, [size=small] [visibility=visible]
186-
Goblin, [size=normal] [visibility=visible]
187-
Goblin, [size=small] [visibility=visible]
188-
Goblin, [size=small] [visibility=invisible]
187+
Goblin,[size=normal][visibility=visible]
188+
Goblin,[size=small][visibility=visible]
189+
Goblin,[size=small][visibility=invisible]
190+
Goblin,[size=small][visibility=visible]
191+
Goblin,[size=normal][visibility=visible]
192+
Goblin,[size=small][visibility=visible]
193+
Goblin,[size=small][visibility=invisible]
189194
```
190195

191196
## Class diagram
@@ -197,40 +202,66 @@ Goblin, [size=small] [visibility=invisible]
197202
Use the Command pattern when you want to:
198203

199204
* Parameterize objects by an action to perform. You can express such parameterization in a
200-
procedural language with a callback function, that is, a function that's registered somewhere to be
201-
called at a later point. Commands are an object-oriented replacement for callbacks.
205+
procedural language with a callback function, that is, a function that's registered somewhere to be
206+
called at a later point. Commands are an object-oriented replacement for callbacks.
202207
* Specify, queue, and execute requests at different times. A Command object can have a life
203-
independent of the original request. If the receiver of a request can be represented in an address
204-
space-independent way, then you can transfer a command object for the request to a different process
205-
and fulfill the request there.
208+
independent of the original request. If the receiver of a request can be represented in an address
209+
space-independent way, then you can transfer a command object for the request to a different process
210+
and fulfill the request there.
206211
* Support undo. The Command's execute operation can store state for reversing its effects in the
207-
command itself. The Command interface must have an added un-execute operation that reverses the
208-
effects of a previous call to execute. The executed commands are stored in a history list.
209-
Unlimited-level undo and redo functionality is achieved by traversing this list backward and forward
212+
command itself. The Command interface must have an added un-execute operation that reverses the
213+
effects of a previous call to execute. The executed commands are stored in a history list.
214+
Unlimited-level undo and redo functionality is achieved by traversing this list backward and forward
210215
calling un-execute and execute, respectively.
211216
* Support logging changes so that they can be reapplied in case of a system crash. By augmenting the
212-
Command interface with load and store operations, you can keep a persistent log of changes.
213-
Recovering from a crash involves reloading logged commands from the disk and re-executing them with
214-
the execute operation.
217+
Command interface with load and store operations, you can keep a persistent log of changes.
218+
Recovering from a crash involves reloading logged commands from the disk and re-executing them with
219+
the execute operation.
215220
* Structure a system around high-level operations build on primitive operations. Such a structure is
216-
common in information systems that support transactions. A transaction encapsulates a set of data
217-
changes. The Command pattern offers a way to model transactions. Commands have a common interface,
218-
letting you invoke all transactions the same way. The pattern also makes it easy to extend the
219-
system with new transactions.
221+
common in information systems that support transactions. A transaction encapsulates a set of data
222+
changes. The Command pattern offers a way to model transactions. Commands have a common interface,
223+
letting you invoke all transactions the same way. The pattern also makes it easy to extend the
224+
system with new transactions.
220225
* Keep a history of requests.
221226
* Implement callback functionality.
222227
* Implement the undo functionality.
223228

224229
## Known uses
225230

231+
* GUI Buttons and menu items in desktop applications.
232+
* Operations in database systems and transactional systems that support rollback.
233+
* Macro recording in applications like text editors and spreadsheets.
226234
* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
227235
* [org.junit.runners.model.Statement](https://github.com/junit-team/junit4/blob/master/src/main/java/org/junit/runners/model/Statement.java)
228236
* [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
229237
* [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html)
230238

239+
## Consequences
240+
241+
Benefits:
242+
243+
* Decouples the object that invokes the operation from the one that knows how to perform it.
244+
* It's easy to add new Commands, because you don't have to change existing classes.
245+
* You can assemble a set of commands into a composite command.
246+
247+
Trade-offs:
248+
249+
* Increases the number of classes for each individual command.
250+
* Can complicate the design by adding multiple layers between senders and receivers.
251+
252+
## Related Patterns
253+
254+
* [Composite](https://java-design-patterns.com/patterns/composite/): Commands can be composed using the Composite
255+
pattern
256+
to create macro commands.
257+
* [Memento](https://java-design-patterns.com/patterns/memento/): Can be used for implementing undo mechanisms.
258+
* [Observer](https://java-design-patterns.com/patterns/observer/): The pattern can be observed for changes that trigger
259+
commands.
260+
231261
## Credits
232262

233263
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
234264
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
235265
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
236266
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)
267+
* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PFUqSY)

0 commit comments

Comments
 (0)