[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kuml-devel
Subject:    Repositories, Visitors and generic interfaces.
From:       Jake Fear <fear1 () home ! com>
Date:       1999-12-21 7:37:46
[Download RAW message or body]

Hi Everyone, 
    Pascal, you and I have already had some starter discussions about this, I
hope this is helpful.  I have done some thinking on creating a generic interface
to the repository (repository for all items) that would provide generic
functionality.  The idea of having several different repositories for different
entities is attractive, but is likely to lead to a complex and unfriendly
interface for the user and codebase for us (just my opinion here, but read
on...).  In order to implement my idea there are a few things that would make
it more understandable.  The first would be to rename data/Properties to
data/Entity and have Entity to be a common superclass for ALL UML types
(classes, packages, use cases, interfaces, components, you get the idea...). 
Now the Entity class is going to be participating in a pattern known to me as
"Node-Visitor" as the Node.  The basic idea goes something like this: The
object structure is generic and holds many different types of objects, each
requiring unique operations.  Rather than using run time type checking or some
other difficult and non OO approach, have some method in the generic class (in
our case in Entity) that accepts an object of type Visitor (we would use
something more specific for our purposes of course).  Visitors then implement
the custom operations by making use of the method overloading mechansim. 
So, here is the addition to the interface of Entity and a portion of the Visitor
interface.

class Entity : public IDontRemember {
public:
    ......// Existing Properties code..
    virtual void accept(Visitor* visitor) { }
    // no-op or pure virtual would be acceptable...
};

class Visitor {
public:
    virtual setEntity(Classes* cl) = 0;
    virtual setEntity(Package* pkg) = 0;
    virtual setEntity(UseCase* uc) = 0;
    virtual setEntity(Component* cmpnt) = 0;
    ..... // One for each concrete type, but not for Entity (the common
superclass)..
};

Now, all of the subclasses of Entity should implement this method like this:

void MyEntity::accept(Visitor* v) {
    v->setEntity(this);
}

Which would cause the correct overloaded version of setEntity to be called when
the visit method is called with some Visitor.  Why we don't have a
setEntity(Entity* e) signature is so that the compiler can help us follow this
plan and prevent silly bugs 8?).  The setEntity call of any method in Visitor
may be a no-op call if that visitor is not interesed in that particular type. 
This could be used to help facilitate drag and drop with a visitor like this.

class DrawingItemCreator : public Visitor {
public:
   DrawintItemCreate() {
        item = NULL;
    }

    virtual setEntity(Classes* cl) {
        item = new DrawingClass(cl);
    }

    virtual setEntity(Package* pkg)  {
        item = new DrawingPackage(pkg);
    }

    virtual setEntity(UseCase* uc)  {
        item = new DrawingUseCase(uc);
    }

    virtual setEntity(Component* cmpnt)  {
        item = new DrawingComponent(cmpnt);
    }

   // Imagine one for each drawing item here....

   DrawingItem getDrawingItem() {
        return item;
    }

private:
    DrawingItem* item;
}

The Drag operation could create one of these visitors, pass it to the node
where the drag event has occured, and then check for a non-null DrawingItem
from the getDrawingItem() call.  If one is found, make it the data that would
be dropped on the drop target, otherwise abort the operation.









--  
Jake Fear

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic