Talk:Command pattern
This is the talk page for discussing improvements to the Command pattern article. This is not a forum for general discussion of the article's subject. |
Article policies
|
Find sources: Google (books · news · scholar · free images · WP refs) · FENS · JSTOR · TWL |
![]() | This article is rated Start-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||||||||||||
|
Is the example helpful?
[edit]I'm a little worried that the example code here just isn't helpful. As written, the extra indirection of objects with an execute() method serves no purpose. It would be better to have an example that features some sort of queue (or scheduler or whatever you want to call it) so that the asynchronous aspect of the command execution is emphasised, i.e. the command gets run possibly some time after it is invoked, and the invoker might be in a different thread to the receiver. —Preceding unsigned comment added by 81.105.217.34 (talk) 15:42, 20 April 2010 (UTC)
Sub-pattern of Command and ConcreteCommand?
[edit]What is called the sub-pattern consisting of only Command interface and class ConcreteCommand? This is an important pattern in itself, without the transactional additions, which can effectively replace function objects and allow lambda calculus to be translated to Java code.
88.112.121.61 (talk) 23:29, 9 March 2010 (UTC)
Python examples
[edit]I'm not sure if Python is the best language to use for Design Pattern examples. Perhaps the main examples should be in a common language like Visual Basic or Java and there should be separate pages for examples in less popular languages. I'm not a Java programmer so I can't make this change. I would be happy to provide Delphi or C# examples.
- I agree. In the real world, Python would use closures for those examples. Particularly, statements like "Generic code that operates on command objects can be powerful and flexible while providing a simple API.", in the context of Python, sound absurd: how are they simpler or more powerful than plain callable objects?
- (Arguably, the "Command Pattern" would begin to make sense in Python once you start using it to handle undo functionality and such, as described on the C2 wiki page. However, none of the examples in the article do that kind of thing.)
- Tangentially, this article could probably be much improved by a comparison with closures --Piet Delport 10:06, 1 June 2006 (UTC)
- In an FP language, you would use closures and curried functions for everything mentioned here, including the undo stack. What's left, however, still follows the command pattern, even though it is no longer object-oriented. A curried function is a function whose argument list is generated at runtime (usually with a function named "apply"). A Common Lisp version of the C++ example demonstrates this:
(defun ingredient (amount what)
(format t " * Add ~a of ~a~%" amount what)) ;; FORMAT is Lisp's printf.
(defun step (action time)
(format t " * ~a for ~a~%" action time))
(defvar *recipe* `((,#'ingredient "2 tablespoons" "vegetable oil")
(,#'ingredient "3 cups" "rice")
(,#'step "Stir-fry" "3-4 minutes")
(,#'ingredient "4 ounces" "peas")
(,#'ingredient "1 teaspoon" "soy sauce")))
(loop for command in *recipe* do
(apply (car command) (cdr command)))
It does basically everything that the C++ version does. Since sending data to STDOUT is not an undoable operation in principle, no undo function was provided. However, it is conceivable to associate each function and its arguments with an undo counterpart, using a hash table:
(defvar *undo* (make-hash-table :test 'equalp))
;; The setf calls define HOW to undo an operation. Each undo
;; operation is keyed to the function it undoes, and takes
;; the same arguments as the original function.
(setf (gethash #'ingredient *undo*)
(lambda (&rest args) (format t "FORGET I SAID THAT!!!~%")))
(setf (gethash #'step *undo*)
(lambda (&rest args) (format t "FORGET I SAID THAT!!!~%")))
;; The undo function invokes the undo-function defined for
;; a command, with the argument list of the command.
(defun undo (command)
(apply (gethash (car command) *undo*)
(cdr command)))
98.31.54.35 (talk) 23:47, 5 July 2008 (UTC)
- You know... removing this example was a mistake. The C++ example is unhelpful. The Python example was working code.
- If Python is less popular than Java, a good fix would be to rewrite the example in Java. (Duh.)
- As for the idea that Python programmers would use closures for this... well, it strikes me as kinda weird. I doubt many would. Python isn't Scheme. In Python, using an object is more flexible. You can add a priority and change the threadpool to understand priority. You can modify the object after it's created. You can examine the fields. You can find ways to merge similar objects. You can serialize it. You can populate it one field at a time (as in a wizard). And so on.
- So while your objections may be sound, deleting the example was not the right action. I'm putting it back and I challenge you to improve upon it. --Jorend 13:50, 2 April 2007 (UTC)
- Here is an example written in java, but I'm not 100% sure it is good enough. I'm posting it here. Requires jre 1.5 or later, working example ( but meaningless )
- with Callable<E>
package org.designPatterns.command;
import java.util.concurrent.Callable;
/**
- Contains 2 numbers and returns their sum on call()
- /
public class SumCommand implements Callable<Integer> {
- private int param1; // both have default value of 0
- private int param2;
- public SumCommand() {
- /* do nothing in this case */
- }
- /**
- Fully initializes the inner state of the object
- @param param1
- @param param1
- /
- public SumCommand(int param1, int param2){
- this.param1 = param1;
- this.param2 = param2;
- }
- /**
- @return param1+param2
- /
- public Integer call() throws Exception {
- /* big delay due to some operations */
- Thread.sleep(1000);
- return param1+param2;
- }
- /* getters and setters omited ...*/
- /* ... */
}
- with Runnable
package org.designPatterns.command;
/**
- holds an integer and increments it with a given value every time the run method is called
- /
public class IncrementCommand implements Runnable {
- private int value;
- private int incrementer;
- public IncrementCommand(int value, int incrementer){
- this.value = value;
- this.incrementer = incrementer;
- }
- /**
- The operation of this Command affects an object contained in it, it DOES NOT return a value
- /
- public void run() {
- /* big delay due to some operations */
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (this) {
- this.value+=incrementer;
- }
- }
- public int getValue() {
- return value;
- }
}
- Main method for demonstrating both of them:
package org.designPatterns.command;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
- This class demonstrates usage of the command classes with and without thread pool
- /
public class Main {
- public static void main(String[] args) throws Exception {
- /* simple example with callable, expected 9:*/
- System.out.println( "new SumCommand(4,5).call() : " + new SumCommand(4,5).call() );
- /* and setting up the command object */
- IncrementCommand ac = new IncrementCommand( 5,1 );
- ac.run();
- System.out.println( "new IncrementCommand( 5,1 ); after run() :"+ac.getValue() );
- /*with Thread pool:*/
- IncrementCommand aggregator = new IncrementCommand(3,2);
- SumCommand summator = new SumCommand(3,6);
- Future<Integer> res1;
- Future<IncrementCommand> res2;
- ExecutorService executor = new ThreadPoolExecutor(2,6,100l,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>() );
- /*one call*/
- res1 = executor.submit(summator); /*Callable*/
- res2 = executor.submit(aggregator, aggregator); /*Runnable*/
- /* DO SOMETHING ELSE TIMETAKING HERE */
- System.out.println("expects (3+6) = 9: "+res1.get());
- System.out.println("expects ( 3+ 2) = 5 :"+res2.get().getValue());
- executor.shutdown();
- executor.awaitTermination(10, TimeUnit.SECONDS);
- }
}
P.S. No idea how to make it appear correctly formated :( Oubless 09:48, 19 September 2007 (UTC)
Link to P of EAA : UnitOfWorks
[edit]The link to martin's fowler website, which redirect to a description of the UnitOfWork pattern does not seems appropriate. Are you sure that UnitOfWork is connected to the command pattern ? If so, some text should explain the link... —The preceding unsigned comment was added by 195.68.44.148 (talk) 14:31, 26 April 2007 (UTC).
Programming Code
[edit]Since the subject is a topic in computer science, the general explanations should not use a specific programming languages (Java, Python, or whatever) but should be written in pseudocode. Actual code examples (in many languages, preferably) can be shown at the end of the article. Inquam 07:56, 7 November 2007 (UTC)
C++ example
[edit]I added a simple c++ example. Let me know what you think.--Michael miceli (talk) 22:32, 7 April 2008 (UTC)
- I realise this is entirely the subject of the argument above, but I'm not sure C++ is optimal for this; there's a lot of stuff that can be difficult to understand in it. Seems as though Python, which would perhaps lead to a terser example, isn't well-loved either. Would re-writing in Java (it's OO and as ubiquitous as they come) make sense? Scala would make this look great but it's not used by anyone :( --zootm (talk) 11:31, 5 June 2008 (UTC)
- Look at how byzantine the Java example above is, then ask that question again. COBOL was once ubiquitous, too. 98.31.54.35 (talk) 01:40, 6 July 2008 (UTC)
- Super late reply: Given that the comparable C++ example would be only more complex it seems a bad thing to contrast with, though. Java was the suggestion since it seems to be widely used on here, something simpler might be better, but C++ ain't that. --zootm (talk) 12:53, 2 September 2009 (UTC)
- I don't see why it is bad to include a C++ example... it might not be simple or explain the pattern easily, but wouldn't it be helpful for people who are wishing to implement this pattern in C++? Crhopkins (talk) 15:49, 5 January 2010 (UTC)
- It's a slippery slope. Look at the histories of any of the Design Pattern pages to see these patterns in every language imaginable. See Talk:Design_pattern_(computer_science)#Extraneous_Examples for my thread that lead to massive cleanup. I'm all for having endless examples in everyone's favorite languages somewhere, like Wikibooks, and having these pages link to them, but these Wikipedia pages should get across the idea of the pattern, not be an implementation cookbook. If it helps the explanation to have multiple languages, then by all means, but in general one language is more than enough. Much as I've never actually used Java, I like it for these example because it is widely-used, strongly-typed, and has garbage collection. With a language without strong typing, many design patterns are harder to follow (because no abstract iterface is needed); the raison d'être of some design patterns even depends on abstract interfaces, so while I love Python for algorithm examples (where working Python is almost as easy to follow as pseudocode), Python is often not a good example language for classic OO design patterns. Similarly, a language without garbage collection (like C++) adds complexity to examples that isn't necessary. While COBOL was once ubiquitous, and while Java will probably never be the dominant language, Java is the most-used language with the features for which the Gang-of-Four Design Patterns were created, not to mention both came out in the same year (1995, fifteen years ago(!); the age of the Pentium Pro). (Similarly, RAII is best exemplified in C++, with its deterministic scope-based destruction.) —Ben FrantzDale (talk) 14:45, 6 January 2010 (UTC)
Image wrong?
[edit]![](http://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Command_Design_Pattern_Class_Diagram.png/200px-Command_Design_Pattern_Class_Diagram.png)
In Command Design Pattern Class Diagram.png
's current version, there is a UML comment on the Receiver class that reads: At some time asks to execute the command. Invoker has exactly the same comment. Why should a Receiver execute commands on it self? Thanks, --134.91.225.10 (talk) 12:40, 17 October 2008 (UTC) (User:Abdull)
- Problem still exists. The text at the Receiver should be something like "Is sometimes asked to be executed" or "Will be executed some time". —Preceding unsigned comment added by 141.52.232.84 (talk) 16:23, 23 February 2010 (UTC)
- Is fixed now. --Abdull (talk) 16:40, 11 March 2013 (UTC)
Criticism of Switch is ambiguous
[edit]I'm not sure I understand the point of the criticism of the switch. The switch is the implementation of the command's invoker. When the article claims the switch itself should not be aware of any lamp details, is it claiming that the invoker shouldn't be aware of any lamp details? Or is it saying that the switch isn't a good example of an invoker, because a good switch class has an additional restriction that an invoker doesn't need? If I'm reading this article, I don't need to know if the switch class is a good way to model a circuit, I need to know what constitutes a good invoker when the command pattern is used. —MiguelM (talk) 22:39, 21 June 2010 (UTC)
Bad article !
[edit]The example is from javaworld (http://www.javaworld.com/javatips/jw-javatip68.html). Someone said about that:"Nice article, but violates basic principles of reknown OO expert". You can read in GoF: "It's easy to add new Commands, because you don't have to change existing classes". In your example you don't have to define the interface Command. Suppose you want to command a 3-state receiver. You have to change the code in PressSwitch and Switch classes. Maybe is better to copy from GoF !. 86.107.49.197 (talk) 18:14, 29 December 2010 (UTC)
javascript example
[edit]storeAndExecute only execute in javascript, it doesn't store...
/* The Invoker function */
var Switch = function(){
this.storeAndExecute = function(command){
command.execute();
}
}
78.153.242.236 (talk) 14:36, 22 February 2013 (UTC)
Does the Scala example make sense?
[edit]Given that Scala has first class functions, wouldn't one never actually use the command pattern, as it is unecessary? Perhaps it could be instructive to show how it can be done more simply by just passing a function? — Preceding unsigned comment added by 2605:A601:41E8:4100:285D:C783:6890:454A (talk) 22:19, 24 February 2017 (UTC)
Diagram Doesn't Match the Explanation
[edit]Explanation talks about an invoker object, yet the diagram doesn't show one. — Preceding unsigned comment added by 192.155.0.198 (talk) 21:05, 23 March 2017 (UTC)
Collections of examples in different programming languages
[edit]The article has a section headed "Example", which seeks to illustrate working of command pattern by means of an example. Many years ago over the course of time people added versions transcribed in a range of different programming languages. There are many web sites where that kind of thing is encouraged: a single example is given, and people are invited to provide versions in programming languages that they like. Often getting as many different languages as possible is seen as a desirable aim. However, that is neither consistent with the purpose of Wikipedia nor consistent with the purpose of this article. A collection of versions in different languages may be a good way of illustrating the differences among those languages, and how they may differ in their handling of the same concept, but this article is not about differences in how different languages handle concepts. Nor is serving as a repository of lists of examples of programming code in different languages any part of Wikipedia's aim. One example serves the purpose of illustrating the methods involved in implementing command pattern, and illustrating differences in the ways different languages might be used to do so is off topic for this article. There have been attempts to clean this up; one such attempt dates from almost 10 years ago, when BenFrantzDale removed most of the transcriptions into different languages, and added comments in the source requesting editors not to add them back. He wrote: "Wikipedia is not a list of examples. Do not add examples from your favorite programming language here; this page exists to explain the design pattern, not to show how it interacts with subtleties of every language under the sun. Feel free to add examples here: http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Command". He added that note both at the beginning and at the end of the example, so that it is difficult to imagine anyone trying to add a new example and not seeing it.
Alas, subsequent editors have ignored that very reasonable request from Ben, and strings of examples have again been added. Recently I tried to do a similar clean up. I was editing from my phone, where I find doing the kind of thorough checking of the history of the article that is needed in order to do this properly is fiddly and difficult, so I provisionally removed the lot, intending to do a better job of it once I got a chance to edit on a computer. With hindsight I think that was a mistake; it would have been better to leave things as they were until I could do it properly. An anonymous editor decided to restore the lot. That editor even restored BenFrantzDale's request not to do so, both the copies Ben had put at the beginning and at the end, at the same time as doing exactly what that message asked one not to do.
I propose to revert to a version with just one example, and with Ben's request in place. If anyone has some reason for thinking that having numerous examples in different languages makes such a large contribution to helping readers to understand the concept of command pattern, which is what the article is about, to justify deviating so greatly from the principle that Wikipedia is not a directory or collection of arbitrary lists then I suggest they explain their reason here, and be willing to discuss the issue, rather than once again ignoring the request in the article and just adding them back without providing any justification for doing so. JBW (talk) 20:26, 16 November 2020 (UTC)