Reputation: 35
I have different commands that all share some common data, so I extracted that to a super-class Command
. All the concrete commands operate on an object of Foo
when they implement the execute
method. The actual invoker of the command is a client TheClient
that creates a new object of the required command and directly executes it.
I have implemented it in such a way that the client and inovker is independent from the implementation details in the commands, and more importantly, independent from the class Foo
.
I have the following questions:
1) Is this an implementation of the command pattern, or somehow an adoption of it?
2) From my understanding of the command pattern, in this example Foo
is the receiver. Is this correct?
3) In contrast to the pure command pattern, I have merged the invoker and client into the same class. Some people say that this is OK in the command pattern, since both are a theoretical construct and in an actual implementation they can be in the same class. Is this correct?
public abstract class Command {
protected String a;
protected Foo foo;
public Command(String a) {
this.a = a;
this.foo = new Foo(a);
}
public abstract void execute();
}
public class StartCommand extends Command {
private String b;
public StartCommand(String a, String b) {
super(a);
this.b = b;
}
public void execute() {
this.foo.doSomething("start " + a + " with " + b);
}
}
// ... other commands ...
public class Foo {
protected String name;
public Foo(String name) {
this.name = name;
}
public void doSomething(String action) {
// does something...
}
}
public class TheClient {
public static void main(String[] args) {
Command command = new StartCommand("x", "y");
command.execute();
}
}
Upvotes: 1
Views: 144
Reputation: 2125
1st question: Yes. It is an adaptation of the Command pattern.
2nd question: Foo
is the receiver.
3rd question: Yes, the invoker is merged with the client class. Here comes a little problem. The Foo
is not independent from the concrete StartCommand
. It's true, that You have to modify the Command
class both implementation, when a rename occurs on the Foo
class for example, but the instantiation of the Foo
should be somewhere in the main
if You ask Uncle Bob. In Your example it's in the Command
's constructor.
EDIT
You can instantiate Foo
in somewhere else, than wrap it around with the ConcreteCommand. Than Invoker will latch around the command. Both wrapping around will embrace Decoupling, and Single Responsibility.
For example You can test Foo
's every behaviour without being afraid of any side effect of the Command. In the test You create a Foo
, test it around, no surprise. Testing the StartCommand
You have to check if any method chaining happens. Like this:
public Command.SetAOfFoo(string a) {
this.foo.SetA(a);
}
You have to check all Foo
's properties to hold, that You checked in the first time with the unit tests of Foo
. You will find some failing testcases because some calling to the StartCommand
modified the state of Foo
, and that lead to failing tests.
I know that is far away from the code that You provided, but this.foo = new Foo(a);
is close to the imaginary this.foo.SetA(a)
that I wrote as an example.
In Your example, there was a possible programming problem. Both the constructor of Foo
and the StartCommand
's constructor got the value 'a'
as parameter. What if You make it public? And You are very surprised, by setting the 'a'
in the StartCommand
, the printout changes, but Foo
behaves differently. The constructor of Foo
stored the previous value, and You maybe forget to change of the code of the Command, to pass the new value to Foo
, where You forget to make the 'a'
public.
The whole example's headscratching can be avoided with removing the construction of Foo
from Command
.
Upvotes: 1
Reputation: 3825
1)it seems to be adaption to command pattern.
2)Foo
is receiver so it knows how to carry out request.doSomething()
3).They can be in same class but it violates some design principles like single resposibility.Purpose of client in command pattern is creating objects and injecting receivers.The role of invoker is to hold commands in some data structure and calling their execute method.Simply it schedules commands and you can do a lot of thing like logging,command history and so on.And putting this kind of logic into client is too much burden for client.
Upvotes: 0