Visitor design pattern - breaking dependence on the target hierarchy

Discussion in 'C++' started by Siphiuel, Mar 7, 2006.

  1. Siphiuel

    Siphiuel Guest

    Hi everyone.
    When using visitor pattern, we have a nasty dependence on the types of
    visitable objects that is coded way on top on the visitor hierarchy. i
    mean, like this:

    class AbstractVisitor
    {
    public:
    virtual void visit(Object_type_1 *);
    virtual void visit(Object_type_2 *)
    .............................
    virtual void visit(Object_type_N *;
    };

    That is so nice that visitable objects are aware only of the
    AbstractVisitor type, but that's not so good that every concrete
    visitor must know about the whole multitude of visitable object types!

    I've encountered this problem when trying to separate visitor/visitable
    classes into libraries. That is, suppose there is a base library Base,
    that contains definitions for AbstractVisitor and some AbstractObject
    class, which is the base class for all visitable objects. Pointers to
    AbstractObject's are stored in some STL container inside the Base
    library. Objects can be manipulated by visitors only through some
    method in the container class:

    // ------ Classes contained in the Base library ------
    // Abstract.h
    class AbstractVisitor;
    class AbstractObject
    {
    public:
    void accept(AbstractVisitor *);
    };

    // Container.h
    #include "AbstractVisitor.h"
    #include "AbstractObject.h"

    class Container
    {
    private:
    std::set<AbstractObject *> objects_;.
    public:
    void manipulate(AbstractObject *, AbstractVisitor *);
    };

    There could be multiple client libraries that have their specific
    AbstractObject descendants and visitors, which are run only on the
    objects defined in the same library. For instance:

    // ------ Classes contained in ClientLibrary1 ------
    class ClientObject1
    :
    public AbstractObject
    {
    public:
    void accept(AbstractVisitor *);
    };

    class ClientVisitor1
    :
    public AbstractVisitor
    {
    public:
    // It is desirable that here are contained only methods pertaining to
    relevant objects
    void visit(ClientObject1 *);
    // other visit()'s
    };

    Naturally, it is not good for ClientLibrary1 to know about object types
    contained in some ClientLibrary2, for instance.

    The aim can be achieved through the use of dynamic_cast'ing, though. In
    order to accomplish, we modify the visitor object hierarchy slightly by
    inserting a templatized ancestor class:

    // ------ Base library code ------
    class AbstractVisitor
    {
    public:
    // AbstractVisitor now knows nothing about the objects
    // on which it's descendants operate
    virtual void visit(void *); // default method
    };

    template<class TObjectType>
    class InterimVisitor
    :
    virtual public AbstractVisitor
    {
    public:
    virtual void visit(TObjectType *);
    };

    The concrete visitor classes can now be defined as follows:

    // ------ Client library code
    class ConcreteVisitor
    :
    public InterimVisitor<ObjectType1>,
    public InterimVisitor<ObjectType2>
    {
    public:
    virtual void visit(ObjectType1 *);
    virtual void visit(ObjectType2 *);
    };

    And finally, the use of dynamic_cast does the right job in overloaded
    accept methods:

    class SomeObject
    :
    public AbstractObject
    {
    public:
    void accept(AbstractVisitor * v)
    {
    Interim<SomeObject> * i = dynamic_cast<Interim<SomeObject> *>(v);
    if (i)
    {
    // v is allowed to visit this object
    v->visit(this);
    }
    }
    };

    I'm sorry for including this much of code and statements that you all
    probably have seen thousand times :). And the main question is - are
    there any other solutions that do not incur performance penalties
    caused by the use of dynamic_cast? Thanks in advance
    Siphiuel, Mar 7, 2006
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. er
    Replies:
    3
    Views:
    330
    Victor Bazarov
    Dec 3, 2007
  2. aaragon
    Replies:
    9
    Views:
    677
    aaragon
    Aug 14, 2008
  3. Replies:
    1
    Views:
    383
    Andrew Tomazos
    May 10, 2009
  4. Pallav singh
    Replies:
    0
    Views:
    345
    Pallav singh
    Jan 22, 2012
  5. Pallav singh
    Replies:
    0
    Views:
    390
    Pallav singh
    Jan 22, 2012
Loading...

Share This Page