4

Say I have the following components:

enter image description here

  • Producer produces numbers and sends messages to Consumer
  • Both Producer and Consumer send messages to Monitor
  • Monitor, say randomly, decides when the produce / consume process should stop and sends a message to Stopper
  • Stopper then stops both Producer and Consumer cleanly

I know this is easy to accomplish in a mutable language such as Java. I know also this can be resolved by allowing partial mutability with interfaces, such as described here.

However, it's not a good practice to have cyclic dependencies even if possible. So, let's assume all references are constructor-injected and final:

  • Producer has final Consumer and final Monitor
  • Consumer has final Monitor
  • Monitor has final Stopper
  • Stopper has final Producer and final Consumer

I found references such as this, but they don't seem to apply.

How would one go about un-cycling this case and cases such as this in general? In other words, I'm mostly interested in how to accomplish not forming the cycles from a design standpoint. Any hints?

levant pied
  • 3,886
  • 5
  • 37
  • 56
  • Where is cyclic dependency ? – John Jun 18 '15 at 22:23
  • 5
    Decouple it all with a message bus? Your scenario is a bit abstract, and perhaps contrived? (why must everything be final constructor dependencies?) – Taylor Jun 18 '15 at 22:37
  • @Taylor Not contrived at all - it's a simplified version of an actual system. What do you see abstract, can you clarify? As for why everything must be a final variable, I said I think that's better design - and [many](http://www.martinfowler.com/articles/injection.html#ConstructorVersusSetterInjection) [seem](http://spring.io/blog/2007/07/11/setter-injection-versus-constructor-injection-and-the-use-of-required/) [to](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/) [agree](http://www.yegor256.com/2014/10/03/di-containers-are-evil.html). Why do you think otherwise? – levant pied Jun 22 '15 at 12:34
  • It's not that I have a particular issue with constructor based injection, it just doesn't seem like a "hill to die on", know what I mean? Apologies if "contrived" came out as pejorative, but my point there is if you're using Spring, don't worry about it, it's the IOC's problem. Tapestry 5, whose IOC is completely constructor based, creates proxies of everything so actual instanstiation is defered. This is another way to approach, but a lot of work (or just use Tapestry/Wicket) – Taylor Jun 22 '15 at 21:37

1 Answers1

2

You're right, this won't work if all dependencies are final and injected via the constructor.

But may I ask, why do they have to be injected via the constructor? There is nothing wrong at the end of the day to use setters to wire up beans.

In fact, in Spring, beans are usually instantiated first and injected afterwards. So you could look at that approach.

Other than that, you could look at a different way to model your problem (that does not have circular dependencies).

For example, since you are using queues already to send messages between the producer and consumer, why not also send messages on queues to the monitor? The stopper could also send messages to the producer and consumer.

Or, as Taylor suggests, an ESB.

There are probably many other ways to design it, have a read about (for example) Apache Camel Enterprise Integration Patterns for some ideas.

vikingsteve
  • 38,481
  • 23
  • 112
  • 156
  • I would use at least three message queues: one between producer and consumer, one between producer/consumer and monitor and one between monitor and producer/consumer (you could have 5 if you separated the p/c ones). – Giovanni Botta Jun 22 '15 at 12:24
  • Thanks @vikingsteve. I agree it can be solved, I mentioned a couple of solutions that are even simpler than using ESB. Moving the problem from one point to another != solving it. I'm trying to figure out if there's a way to avoid circular dependency somehow in a system I presented - i.e. looking for some ideas from the design perspective, as I'm sure you and others ran into cyclic dependencies and, even though you could just use setter injection to "solve" it, probably did not like them that much either... – levant pied Jun 22 '15 at 13:17