In a GUI application (to organize images), I use the Observer Pattern (or anything similar to model-view-(view)controller) to inform other components about changes.

Assuming three components A, B, C which show different aspects of some objects, I can trigger "batch actions" which affect many objects in A and B. Each change will lead to an update of the set of objects in any or all of A, B, C, depending on the change.

If A now triggers a change of three objects, B and C will display three successive changes each. Apart from taking time, it's flickering the UI.

What I would need is some way of globally (argh!) saying that during the batch action, no UI changes should happen. Since I would not want to limit the usage of the ObserverPattern to UI stuff, I would like to not stop the entire pattern from working, but only the UI-relevant part of it.

Any idea? When I came across this situation, I was thinking it's a usual requirement, and I wondered why I haven't come across a solution before.

  • 1
    How much time do those batch operations take? Would it be an option to put a small delay between receiving the update and actually redrawing the UI (with updates being received during the delay being merged)? – Bart van Ingen Schenau Oct 10 '16 at 12:29

You may be interested in using something like Reactive Extensions to do some more complex event processing.

Specifically, using the Sample Filter might be just want you want here.

If you combine all your events that result in a UI refresh into a single stream and sample that stream then you can avoid unnecessary UI refreshes.

  • "Observer pattern done right" - cool! Starred the RxPy repository and will look into it. Since you stress the sampling, I started to wonder whether I can really drop some events and still the internal state is consistent. – virtualnobi Oct 10 '16 at 13:06
  • FYI, Your links appeared to have titles appended to the end, which was breaking them for me. ... I stripped those off, hopefully still linking to the desired pages... – svidgen Oct 10 '16 at 14:14
  • Cool, thanks. I'm still a bit iffy on the URL markup/down. I probably got it wrong :) – MetaFight Oct 10 '16 at 14:46

There are a few strategies I'd consider:

  • Refresh on an interval.
    Pick an interval based on the longest you'd want to wait to see an update and the longest time you might be waiting between notifications. Either queue the notifications and handle them and the UI update on an interval, or more simply, handle notifications as they arrive and simply refresh the UI on an interval.
  • Pass batch objects through the notifications.
    Include a list of objects that are part of the batch, an ObjectsCount, or a BatchCompleted state. Whatever's easiest for you to include and/or interpret.
  • Put every change in a Batch and watch a BatchJobs channel/object.
    Your Batch can include a collection of changes or changed objects. You can either delay it's insertion into the channel until it's complete, or include an IsComplete status and make it observable (or just include an OnComplete event).

You should introduce an intermediate level between the Observed and the Observers. Instead of having Y Observe Z directly (Y<-Z), have Y observing X which observes Z (Y<-X<-Z) . When X is notified of the event of Z, it can delay publishing its own event to Y until you are ready.

  • I wouldn't like to do this literally, since the observer often wants to know which observable triggered the event. But your idea made me think whether I could add some more generic stuff into the ObserverPattern which would allow to stop some events... – virtualnobi Oct 10 '16 at 13:03
  • That's cool. Whatever works. – Gonen I Oct 10 '16 at 14:51

Here's what I finally ended up with: My PausableObserverPattern on Github. Comments welcome!

The Reactive Extensions mentioned by @MetaFight seemed to be too big (i.e., too complex) to me.

Refreshing on an interval does not work since I do not know how long the batch process will need.

Since I am using a very simple ObserverPattern (see github), there's no easy way to pass additional data about the batch of changes.

The answer by @user889742 triggered my thinking - only the "intermediate" level he mentions is the Observable class (actually a subclass).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.