views:

84

answers:

3

This question is a refinement of my question http://stackoverflow.com/questions/3161392/different-ways-of-observing-data-changes.

I still have a lot of classes in my C++ application, which are updated (or could be updated) frequently in complex mathematical routines and in complex pieces of business logic.

If I go for the 'observer' approach, and send out notifications every time a value of an instance is changed, I have 2 big risks:

  • sending out the notifications itself may slow down the applications seriously
  • if user interface elements need to be updated by the change, they are updated with every change, resulting in e.g. screens being updated thousends of times while some piece of business logic is executing

Some problems may be solved by adding buffering-mechanisms (where you send out notifications when you are going to start with an algorith, and when the algorithm is finished), but since the business logic may be executed on many places in the software, we end up adding buffering almost everywhere, after every possible action chosen in the menu.

Instead of the 'observer' aproach, I could also use the 'mark-dirty' approach, only marking the instances that have been altered, and at the end of the action telling the user interface that it should update itself.

Again, business logic may be executed from everywhere within the application, so in practice we may have to add an extra call (telling all windows they should update themselves) after almost every action executed by the user.

Both approaches seem to have similar, but opposite disadvantages:

  • With the 'observer' approach we have the risk of updating the user-interface too many times
  • With the 'mark-dirty' approach we have the risk of not updating the user-interface at all

Both disadvantages could be solved by embedding every application action within additional logic (for observers: sending out start-end notifications, for mark-dirty: sending out update-yourself notifications).

Notice that in non-windowing applications this is probably not a problem. You could e.g. use the mark-dirty approach and only if some calculation needs the data, it may need to do some extra processing in case the data is dirty (this is a kind of caching approach).

However, for windowing applications, there is no signal that the user is 'looking at your screen' and that the windows should be updated. So there is no real good moment where you have to look at the dirty-data (although you could do some tricks with focus-events).

What is a good solution to solve this problem? And how have you solved problems like this in your application?

Notice that I don't want to introduce windowing techniques in the calculation/datamodel part of my application. If windowing techniques are needed to solve this problem, it must only be used in the user-interface part of my application.

Any idea?

+2  A: 

An approach I used was with a large windows app a few years back was to use WM_KICKIDLE. All things that are update-able utilise a abstract base class called IdleTarget. An IdleTargetManager then intercepts the KICKIDLE messages and calls the update on a list of registered clients. In your instance you could create a list of specific targets to update but I found the list of registered clients enough.

The only gotcha I hit was with a realtime graph. Using just the kick idle message it would spike the CPU to 100% due to constant updating of the graph. Use a timer to sleep until the next refresh solved that problem.

If you need more assistance - I am available at reasonable rates...:-)

graham.reeds
Good idea. What's nice about it that it clearly separates the business-logic part (which isn't aware of any user interface at all) from the user-interface part.
Patrick
A: 

Another point I was thinking about.

If you are overwhelmed by the number of events generated, and possibly the extra-work it is causing, you may have a two phases approach:

  • Do the work
  • Commit

where notifications are only sent on commit.

It does have the disadvantage of forcing to rewrite some code...

Matthieu M.
A: 

You could use the observer pattern with coalescing. It might be a little ugly to implement in C++, though. It would look something like this:

m_observerList.beginCoalescing();
m_observerList.notify();
m_observerList.notify();
m_observerList.notify();
m_observerList.endCoalescing(); //observers are notified here, only once

So even though you call notify three times, the observers aren't actually notified until endCoalescing when the observers are only notified once.

Tom Dalling