interface Task> { } interface Result { V get(); } class Processor { public > R process(Task t) { return null; } } //---- Cooking module ---------------------------------------------------------- interface CookingTask> extends Task {} class CookPuddingTask implements CookingTask {} class CookSteakTask implements CookingTask {} interface CookingResult extends Result { V accept(CookingVisitor vst); } class PuddingCookedResult implements CookingResult { public PuddingValue get() { return null; } public PuddingValue accept(CookingVisitor vst) { return vst.visit(this); } } class SteakCookedResult implements CookingResult { public SteakValue get() { return null; } public SteakValue accept(CookingVisitor vst) { return vst.visit(this); } } class PuddingValue {} class SteakValue {} interface CookingVisitor { public PuddingValue visit(PuddingCookedResult r); public SteakValue visit(SteakCookedResult r); } class CookingClient extends AbstractProcessingClient implements CookingVisitor { CookingClient() { super(null); } public PuddingValue cookPudding(Object data) { CookPuddingTask task = null; return processTask(task); } protected Object handleResult(CookingResult result) { // dispatch by visitor pattern return result.accept(this); } public PuddingValue visit(PuddingCookedResult r) { return r.get(); } public SteakValue visit(SteakCookedResult r) { return r.get(); } } //---- Laundry module ---------------------------------------------------------- interface LaundryTask> extends Task {} class CleanJeansTask implements LaundryTask {} class CleanTieTask implements LaundryTask {} interface LaundryResult extends Result { V accept(LaundryVisitor vst); } class CleanJeansResult implements LaundryResult { public JeansValue get() { return null; } public JeansValue accept(LaundryVisitor vst) { return vst.visit(this); } } class CleanTieResult implements LaundryResult { public TieValue get() { return null; } public TieValue accept(LaundryVisitor vst) { return vst.visit(this); } } class JeansValue {} class TieValue {} interface LaundryVisitor { public JeansValue visit(CleanJeansResult r); public TieValue visit(CleanTieResult r); } class LaundryClient extends AbstractProcessingClient implements LaundryVisitor { LaundryClient() { super(null); } public JeansValue cleanJeans(Object data) { CleanJeansTask task = null; return processTask(task); } protected Object handleResult(LaundryResult result) { // dispatch by visitor pattern return result.accept(this); } public JeansValue visit(CleanJeansResult r) { return r.get(); } public TieValue visit(CleanTieResult r) { return r.get(); } } abstract class AbstractProcessingClient> { Processor proc; public AbstractProcessingClient(Processor p) { this.proc = p; } // protected > V processTask(Task task) { // R result = (R)proc.process(task); // return (V)handleResult(result); // } protected V1 processTask(Task task) { R1 result = proc.process(task); return handleResult(result); } abstract protected V1 handleResult(R1 result); }