@@ -3,19 +3,21 @@ title: Command
33category : Behavioral
44language : en
55tag :
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+
1921Real-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
3739Here's the sample code with wizard and goblin. Let's start from the ` Wizard ` class.
3840
3941``` java
42+
4043@Slf4j
4144public 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
7680Next, we have the goblin who's the target of the spells.
7781
7882``` java
83+
7984@Slf4j
8085public 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
110115public 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
135140Finally, 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
153158Here ' 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
179184Here' 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]
197202Use 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