vmpstr
vmpstr

Reputation: 5211

observer pattern -- passing information to the observer

please excuse any and all newbieness),

I have the following task to perform:

I have several classes (call these A) that constantly gather information from various sources (database, internet, etc). They can contain a potentially large amount of information on some topic..

I also have a bunch of classes (call these B) that allow me to render a variety of graphs, if supplied with enough information (here, information can be as simple as one or more floating values).

Now, I have to tie these two things together, so that I can modify which information is displayed in which form with minimal changes. Now, I'm considering using an observer pattern here, because it seems to lend itself nicely to this problem. However, I'm a bit stuck and would like advice. I can clearly make classes A of a "data source" base type, that allows subscribers and notifies subscribers when there are changes. I can also make classes B of the type "observer" and let them subscribe to data sources and be notified of changes.

The problem is that I don't want my observers to know any particular type of information they are displaying. For instance, if I want to graph temperature in my city on the Y-axis and time on the X-axis, and I have a 2D-plot class (of type B), then I want to avoid any kind of A->GetTemperature () calls. Similarly, in class A, I don't want to call NotifyOfTemperatureChange () or anything like that...

One idea is to define a bunch of enums or strings like "temperature", "time", "humidity", etc and then tell the observer what it should listen to (something like A->SetYAxis (B, "temperature") -- here, I'm informing class A that it should get a single float value for its Y axis from data source B, channel "temperature")

so that A can just do B->subscribeTo (whateverIPassedIn). That way, B doesn't need to know what information its plotting. A can then say notifyOfChangesOnThisChannel ("temperature"). This, however, seems a bit hacky for me... For instance, would the data be actually passed to the notified function? Would I have to do something like this:

void B::subscriberChanged (int subscriberId, std::string channel)
{
    float value = datasource [subscriberId].GetCurrentValue (channel);
}

or would be it something like

void B::subscriberChanged (int subscriberId, std::string channel, void *data)
{
   float value = *static_cast <float *> (data);
}

and besides, how would B know the type of data? I mean in this example it's a float, but what if it's an int or a double?

I guess my question is: is this correct? Is there a nicer way to approach this problem?

Thank you in advance

Upvotes: 3

Views: 779

Answers (1)

Bj&#246;rn Pollex
Bj&#246;rn Pollex

Reputation: 76778

You could solve this problem by making your observers template classes. You would then have to define a minimal interface (or concept actually) that you could call, say, a Fact that would define what a single item of data looks like. You could also define a concept AxisDescription that defines how axis are described (labels, units, linear/logarithmic etc).

Here a simple example to illustrate:

template<class FactType, class AxisType>
class B {
public:
    b(AxisType axis); // initialization requires a description of the axis

    // called when a new fact is available
    void notify(FactType fact); 

    // called when many fact should be reported
    template<class FactIterator>
    void notify(FactIterator begin, FactIterator end); 
};

FactType can be as simple as float or int, but also more complex, depending on what you want to do with it.

Upvotes: 3

Related Questions