Combining composite, decorator and visitor patterns

by Antoine Boisier-Michaud   Last Updated December 06, 2018 15:05 PM

I am currently working on a project where I need to manipulate a tree-like data structure, which I implemented with a composite pattern. I want to be able to do different actions on this data structure, so I implemented a visitor pattern.

I was starting to see some code duplication in between my visitors, so I decided to implement a decorator pattern over my visitors. The decorators implement the Visitor interface, and their constructor accepts a Visitor as a parameter.

enter image description here

The idea is that the decorator executes some code before, executes its base visitor (the one passed as a parameter), and executes some code after, a bit like that:

class ConcreteDecorator {
    decoratedVisitor: Visitor

    visitLeaf(leaf) {
        // Do some stuff before
        result := decoratedVisitor.visitLeaf(leaf)
        // Do some stuff after
        return result;
    }

    visitComposite(composite) {
        // Do some stuff before
        result := decoratedVisitor.visitComposite(leaf)
        // Do some stuff after
        return result;
    }
}

The decorator/visitor stuff can be setup like that:

visitor := new ConcreteVisitorA()
visitor := new ConcreteDecoratorA(visitor)
Visitor := new ConcreteDecoratorB(visitor)

The problem is that once I call visitComposite on a decorator, for example, the decorator does its stuff, then calls its child visitor's visitComposite. Since visitComposite is a recursive method, when it is called on the ConcreteVisitor and the method does its recursive calls, we lose the decorators. The decorators are only applied to the first visited node.

I thought of different solutions, like using inheritance instead of decorators, but I want to be able to reuse the decorators on different visitors, so that's not a viable option.

I also thought of using some kind of strategy pattern. The strategies would have a beforeVisitLeaf/afterVisitLeaf and beforeVisitComposite/afterVisitComposite methods. The problem is I can't implement a filter decorator, which abort the visit of certain nodes.

I managed to do a hack this solution and make it work by keeping a hook on the child visitor methods and substituting the child visitor instance methods by the decorator methods manually (I can do that because... JavaScript).

This solution is super hacky, so I was wondering if you guys had any design ideas on how to fix this.



Related Questions


Updated February 21, 2017 15:05 PM

Updated May 21, 2015 22:02 PM

Updated August 15, 2017 09:05 AM

Updated May 11, 2016 08:02 AM

Updated March 26, 2016 08:02 AM