In the same system another usage of the Visitor pattern impeded the refactoring: In the last of a chain of six singleton Spring collaborators a visitor has been used to accomplish a certain task by visiting the current instance of the blackboard subtype which has been presented in the previous post.
public class CollaboratorUsingVisitor {
...
public void useVisitor(BlackBoardBaseType blackBoard) {
...
TaskAccomplishingVisitor visitor = new TaskAccomplishingVisitor();
blackBoard.accept(visitor);
Result result = visitor.getResult();
...
}
...
}
public class TaskAccomplishingVisitor implements BlackBoardVisitor {
private Result result;
public void visit(BlackBoardSubType1 blackBoardSubType) { ... }
...
public void visit(BlackBoardSubTypeN blackBoardSubType) { ... }
public Result getResult() { return result; }
}
It can be seen that on every call of the method useVisitor() a new instance of the visitor is created. Since I needed to extract the whole collaborator chain, too, I needed to abstract this visitor from the blackboard subtypes as well. But in order to achieve this a special case collaboration had to be implemented: Singleton collaborator using prototype visitor. It is not very widespread, at least according to the systems which I've seen so far, but definitely a clean solution, because Spring supports lookup-method injection since version 1.x.There was an additional step to get in a state where the this kind of injection could be applied: Extract an interface specifying the method returning the computed result.
After finishing the refactoring this is how the Java code looked like:
public abstract class CollaboratorUsingVisitor {
...
public void useVisitor(BlackBoardBaseType blackBoard) {
...
TaskAccomplishingVisitor visitor = createVisitor();
blackBoard.accept(visitor);
Result result = visitor.getResult();
...
}
public abstract TaskAccomplishingVisitor createVisitor();
...
}
public class ExistingTaskAccomplishingVisitor implements BlackBoardVisitor, TaskAccomplishingVisitor {
private Result result;
public void visit(BlackBoardSubType1 blackBoardSubType) { ... }
...
public void visit(BlackBoardSubTypeN blackBoardSubType) { ... }
public Result getResult() { return result; }
}
public class NewTaskAccomplishingVisitor implements TaskAccomplishingVisitor {
public Result getResult() { return new Result(); }
}
And this is a snippet of the Spring XML configuration holding the bean definitions for the old and the new module:
In case of the new visitor in the new module there were no requirements regarding what result to deliver, therefore if was completely sufficient to return just a dummy result. With this whole change the collaborator chain could be abstracted and duplicated without having to extract the blackboard subtypes.
No comments:
Post a Comment