The problem
Lets look at the analogy with the Command pattern:
- A
Client creates objects of classes that that implement the Participant (similar to Command). For convenience, let's call one of these classes ConcreteParticipant.
- The
ConcreteParticipant object knows all the context, such as receiver to perform its duties and proceed() (similar to execute() in the command pattern). This context may be provided at construction or later, but before any invocation.
- The
invoker object is a little more complex, since it has a collection of Participant, This may be let's take for example ConcreteParticipant have all the necessary context (e.g. receiver in the command pattern) to perform the calculation of the conditions and proceed().
- The conditions that say if the
Participant must proceed() is not calculated by the invoker, but by the Participant itself.
Your initial approach
Your first approach is to expose the Participant condition determination and let the invoker do the filtering:
//PSEUDO CODE: I'm not Java fluent...
interface Participant {
void proceed();
boolean isApplicable(); // but why?
}
// in the invoker:
for (Participant p: participants) {
if (p.isApplicable())
p.proceed();
}
What's the benefit of such approach? If the Participant determines itself if the condition applies (and perhaps some are even unconditional) it makes no sense to let another class deciede.
Keep it simple!
According to the principle of least knowledge and sound separation of concerns, and unless there are reasons you forget to tell about, you should not expose the condition.
Instead, you should trust the participant to work only if necessary:
interface Participant {
void proceed();
}
class ConcreteParticipant implements Participant {
private bolean isApplicable() { ... } // no longer explosed in the interface
public void proceed() {
if (isApplicable()) {
...
}
}
}
class ConcreteUnconditionalParticipant implements Participant {
public void proceed() {
doItAnyway();
}
}
With this approach you no longer have any performance issue of redoing twice the same time-consuming operation: you may refactor the code without changing the interface:
class OtherConcreteParticipant implements Participant {
private ComplexResult prepareCondition() { ...}
private bolean isApplicable (ComplexResult r) { ... } // stateless :-)
public void proceed() {
ComplexResult r = prepareCondition();
if (isApplicable(r)) {
... // here you may reuse r.
}
}
}
And you have no longer a naming issue either ;-)
Need tighter control?
If the invoker must do some bookkeeping, for example counting the number of participants that contributed, you could change slightly your interface:
interface TalkativeParticipant {
boolean proceed(); // return true if it was active, and false if not applicable.
}
Note that this approach would also allow you more elaborate decisions on invoking participants:
- you could easily stop the calls after the first participant did work.
- or stop the calls after the first that did not work
Remark: The first result could also be achieved using a chain of responsibility pattern. But chain of responsibility would require each Participant to know its successor. THis is a very different situation than what you described. The collection of participants seems easier to manage.