2

Question:

  • Are there any techniques for communicating with methods of other components but still keep a "pure" Observer pattern ?
  • If yes are they indicated/regularly-used or am I just overcomplicating stuff?

A practical example

Suppose I have an architecture with the following characteristics:

  • System is a Word Processor app
  • Many components, each with it's own purpose, e.g KeypressDetector, Printer, DocumentRenderer.
  • Components modify/observe a single model, the Document
  • The components thus "communicate" via this model observation/modification. The components don't know about each other in any other way.

If I'm not mistaken this is what the Observer Pattern is all about.


So here's one case where there's a problem:

  • For component Printer to do it's job it needs some output from component PagePreparator.

  • This is just one edge-case where component PagePreparator can't continuously update the model that is shared between the components because it involves heavy-computation. This involves just a single aspect of PagePreparator, e.g PagePreparator.prepare() // takes a long time to run.

So that's one case where It looks to me that I need to "break away" from this pure Observer setup and just expose the method of PagePreparator to Printer directly and call it explicitly from Printer. This will couple them explicitly together though.

Are there any techniques for keeping this Observer pattern exclusively and still be able to perform this kind of invocations?

Possible solutions:

  • When Printer needs output it sets a flag on the model Document, e.g updatePages which is picked up by PagePreparator's observers. PagePreparator then sets the output on the model Document which is picked up by Printer's observer which proceeds to do it's job.

  • Simply "breaking" the pattern and just expose PagePreparator's method, pagePreparator.prepare() to Printer which can then explicitly call it.

  • Dispatching an event from Printer which is picked up by PagePreparator which proceeds to set the value on the model Document, for Printer to pick it up.

  • For clarification, could you explain the print process? Presumably some method like Printer.print is called. Is that method called directly as the entry point? Is it called by Document? Is it hooked into an event which is raised by Document? And when you talk about "observing" currently, how does that work? Is it polling for changes to a property on some timer, or is it there some push mechanism like an event? – Ben Aaronson Mar 29 '16 at 13:02
  • Oh, and another question, is the PagePreparator's output used by anything other than the Printer? – Ben Aaronson Mar 30 '16 at 7:43
  • @BenAaronson Printer.print() is called using an event. On your 2nd question, I don't really know what happens under the hood but it's just a regular data-binding mechanism (define a model and some observers for that model). As for your 2nd comment, yes PagePreparator output can be used for other components as well. – Nik Kyriakides Mar 30 '16 at 13:29
  • Thanks for the explanation. And what's the name of the specific language feature/framework/library/whatever you're using for the data-binding mechanism? – Ben Aaronson Mar 30 '16 at 13:52
  • Thanks for the interest - Here: Polymer data-binding explained – Nik Kyriakides Mar 30 '16 at 14:17
1

The third option seems cleanest to me. I frequently find myself making use of the Event Aggregator Pattern with applications containing isolated/disconnected modules communicating with each other via messages (Another good page Here).

The pattern itself has become common at least in .NET with a lot of examples of 'generic' Event Aggregators around which should be able to translate into most languages.

The benefit of using messages to communicate between modules is that those modules remain decoupled; the cost however, is adding a layer of indirection.

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.