views:

103

answers:

4

I have a process which has a "notify" method which receives as a parameter the base class of the message type. I'd like to do different processing based on the derived type of message. Does this mean I need to add a method called "process" or something similar to the message type, and invoke it using polymorphism? Is it better to add a "notify" for each specific message type?

More details: The language is C++. I thought notify would be a good idea here, so that I would only need one method to be notified of the various message types. The controller inherits from a listener class which specifies a pure vitual notify(MsgBaseClass) method. I still like that idea, since I don't have to add a notify for each new message type. But in the controller code itself, I don't see any way to distinguish between the message type other than something like dynamic cast, or adding a message type to the message.

edit: I think I'm going to go with the Visitor pattern. It allows me to keep just one method for the notify, and I can avoid a switch statement in my code. A "visitor" interface will specify the various methods needed by the listener to process the various derived message types. This will require only one message to be added to the Message base class, a pure virtual "accept(MyMessageTypeVisitor v). The derived message classes will implement it using v.visit(this);

I think this oughta work.

+1  A: 

Edit: I think dirkgently has a good point, and that messages shouldn't know how to process themselves. Therefore the approach I described where messages could be used as factories isn't a good idea. I do think that an abstract process factory might be a good solution though.

Use an abstract factory to create an object that can handle the processing, and invoke it using polymorphism. This factory could possibly be included directly in the message class, or you could create a separate factory class that accepts the message type as a parameter and returns an appropriate object.

class Message {
public:
  virtual Processor *getProcessor() = 0;
  // other methods
};

class Processor {
public:
  virtual void doWork() = 0;
};

class MyListener : Listener {
public:
  void notify(Message *message);
};

void MyListener::notify(Message *message) {
  Processor *proc = message->getProcessor();
  proc->doWork();
};

(Sorry if this is incorrect. My C++ is a bit weak, but I believe it illustrates the principle.)

This would allow you to just override getProcessor() for each message type, and create the appropriate processor there.

IMVHO, Polymorphism is the way to go. My guess it that the kind of processing logic that you want to do doesn't belong in the message class and should be moved to separate classes. Another reason that I would prefer this approach is that it doesn't require me to change the structure of the class being notified if I add additional messages. If there's only one or two message types, this might not be an issue.

Emil H
A: 

Are you stuck with the observer design pattern?

Overloaded notify looks like a candidate. The observer pattern is really simple. It's based on the Hollywood Principle namely, "Don't call us, we'll call you!". The idea is to have a set of objects (observers) and notify them instead of having them query you. You pass in a generic Event sort of data to the observers. It should be left to the observer to decide what to do with this. There'd be some dynamic_casts if the observers react to different events (yes, you'd need an event hierarchy too).

dirkgently
Hi Dirk,I added some more detail to the main question.
Jack BeNimble
I like the simplicity of the dynamic cast idea. But having the processing packaged up with the message itself is more "OO", isn't it?
Jack BeNimble
dirkgently
No, I'm trying to stick with a single notify method for the message base class. I mean something like add a pure virtual "process()" method to the Message base class that varies with the subclass.
Jack BeNimble
Sorry, I mean, I'm trying to stick with a single notify message for the listener.
Jack BeNimble
Doesn't that mean you are expecting the Message subclasses to actually know how they should be processed? Shouldn't it really be the observers who decide what to do with a message?
dirkgently
A: 

You could do something like this:

DerivedType *dt = dynamic_cast< DerivedType >( &BaseType );
if( dt != NULL )
{
    // Handle processing of DerivedType
}

Just try doing a dynamic_cast to each handled DerivedType. If you get a non-null pointer then you know that you have received the type you attempted to cast to.

Naaff
+1  A: 

The classic OO answer requires the base message class to provide an abstract method which concrete message subclasses override to provide the specific processing.

Some (not very widespread) languages such as Dylan and CLisp provide "generic functions" (dispatched dynamically on argument types) that solve the problem quite drastically.

One flexible approach viable in popular languages is Uncle Bob's "Acyclic Visitor" design pattern, http://www.objectmentor.com/resources/articles/acv.pdf ; for more Visitor variants see www.ccs.neu.edu/research/demeter/adaptive-patterns/visitor-usage/papers/plop96/variations-visitor-nordberg.ps .

Alex Martelli
I'm going with the generic visitor pattern.
Jack BeNimble