mercredi 24 juin 2015

Take specific action depending on "foreign" subtype, without switch, casts and so on. Can we use polymorphism somehow?

I faced similar problem many times, and yet haven't found good solution. What follows is a concrete example with which I'm struggling now, but the problem is actually general.

Let's say we have some application that listens for binary data from serial port, decodes it, and sends some data back if needed. This is the core functionality, and it is done by a kind of "core" module.

This core module emits events. There is an abstract type Event, which contains some common data such as event time, and there are some subclasses of Event: for example, there is an event EventRawData that is emitted when any raw data is received, and EventMessage, that is emitted when message is decoded or sent.

There is GUI which listens for these events, and takes some actions when event happens. Of course, exact action depends on exact event type. The problem is how to take special action depending on event type. Event itself is completely unaware of any kind of GUI (and it shouldn't be aware), so, I can't add some virtual method to Event that displays this event somehow.

The naive approach is to use some kind of switch: in C++ we would use dynamic_cast, in Java it would be instanceof, etc. This is what I've done before, and I don't like it:

if (my_event instanceof EventRawData){
   // ...
} else if (my_event instanceof EventMessage){
   // ...
}

What I can think of instead, is:

Maybe we can invent some interface for GUI, and each particular GUI should implement this interface. Then, each event could have show() method:

abstract class Event {
   // ...
   abstract void show(GuiAbstract gui);
   // ...
}

and when this method is invoked by some particular GUI, the GUI should pass this there. This is probably what is called a "dependency injection" these days.

Well, I don't like this either: I want Event to be completely unaware of GUI.

Or, maybe it's better to get rid of base class Event, make each event completely separate class, and listen for them separately. I don't like it as well: I really want all events to have some common data (such as time of the event).

Maybe there is some design pattern that I'm unaware of? Any help is appreciated.

Aucun commentaire:

Enregistrer un commentaire