views:

56

answers:

3

Hi Stackoverflow, I have a design problem I cannot find a clean and nice solution to. I am developing in PHP but I believe this could occur in any language. My basic problem is that I have two objects that have circular interdependence at some level of indirection. That means I have a class (call it F) implementing the Facade pattern which contains an object (of class B) which itself needs an object of class A to be created. class A's constructor itself needs a facade F to be created => I have circular interdependence of objects.

I believe I cannot resolve the circular interdependence (the objects basicly implement a finite state machine with a loop using the state pattern) so I am looking for a clean solution. I came up with two possible solutions myself, but I dont think either is especially elegant:

  1. Have class A implement a setFacade(F $facace) method and remove the entire facade from the constructor and just set it after A and the facade are created. Objects of class A cannot work without the facade so this would actually create an object of class A which is not able to do anything until setFacade is called and it would reduce encapsulation and would allow to replace the facade at object runtime, which I also don't like.

  2. Implement something like a Promise that is passed to A instead of the facade which will be able to resolve the facade later as soon it is created. I dont like to introduce this additional indirection layer, especially because I have no good place to actually resolve the promise than in the methods that handle buisness logic inside of A, which could a) produce terrible errors and (more important) b) woul need me to check if the promise was already resolved or if i will need to resolve it now, whenever the buisness logic is called. That's just terrible design in my eyes.

So if anyone can come up with a better solution or could support one of my possible solutions with a good argument I'd really happy.

+1  A: 

Assuming you're using the Facade as it's commonly defined (as a simplified interface which manages dependencies and makes it easier to use a complicated API) then none of the "hidden" (by the facade) classes should know of classes which use the facade. Essentially, think of it as a single point of entry, which either means that B shouldn't be dependent on A, or A shouldn't be dependent on the Facade.

EricBoersma
I used the term Facade for a sub finite state machine which handles especially complex logic and returns (transfers) back to the simpler finite state machine after that logic is done.This "transfer back" is actually the point where the circular dependcy is created. I could refactor the dependecy to move it from B to F, but it would still remain. See also my comment to Kangkans comment.
Daniel Baulig
In the circumstances that you're describing, I don't see it as a Facade, then. It seems like it's something closely approximating a Facade, but it seems like the A->B->F->A (or however it falls out) design is inherently flawed. I have to agree with everyone else, it feels like you need to look back at your design and determine how to separate these dependencies.
EricBoersma
I just don't see how else I could model a circular finite state machine where creating exit points on the fly is not possbile (for various reasons). My system looks basicly like this (http://www.danielbaulig.de/StateExample.png). Of course this is simplyfied. F in reality is much more complex with various different states and even additional sub machines. I cannot create A without F and cannot create F without A (if both require each other in the constructor). I cannot think of any way to break that circular dependency. There might not even be such a solution.
Daniel Baulig
Assuming your diagram there vibes with your actual design (and that was very useful, thank you), you need to remove B's dependency on A. I assume that the two are attempting to send messages back and forth, or call methods on each other; had you considered using some sort of independent go-between (not F) for the two objects, removing their dependency on each other? Essentially, you could set up a subscriber between the two which has no dependencies, have each object subscribe to the intermediary, and then register functions which should be called as a response to certain messages.
EricBoersma
Using the publish/scubscribe pattern could indeed decouple those objects. Thank you for enlightening me there. Since each topic would only have single publisher and subscriber in my case though, I believe this would be a bit overkill.While the solution I described below may not be perfect I feel comfortable enough using it. Thank you alot for all your effort in helping me.
Daniel Baulig
+2  A: 

Circular dependencies are such a malicious evil that they must be avoided at all costs, even if it means completely re-thinking your design and throwing away hours of work. (spoken from a maintenance programmer's point of view. Some poor schmuck after you will need to do it anyway.)

There are several ways to look at refactoring code, but the short non-specic advice I have is that any object that is causing a circular dependency should have the offending properties, methods, etc, be split off into a new object. Then each of the two original dependencies would depend on this third object, and not on each other. (And ensure this third object does not depend on the originals.)

Even if it means having duplicate or similar code, it's still better than a circular dependency (but even this should be avoidable with the proper up-front design.)

David Stratton
I am aware of this, but I am not certain how to break that circular dependency - or if it is possible at all, because there simply is a circular dependency in the system I am trying to model.I do understand your point of view though - I am, professionally, a maintenance programmer myself, although this question is regarding a private project.
Daniel Baulig
After reading this and your other comments... it's not as bad as I was picturing. Not desirable, but if the actual system you're modeling inherently has this circular dependency, then you may be modeling correctly.
David Stratton
+1  A: 

While I was not able to resolve my circular dependency I at least settled on a solution how to create my system containing that circular dependency.

I changed all my state classes to not take their exit points in the constructors anymore, but through a method that will basicly throw an exception if it is called a second time.

I then introduced a builder class that will create each state in my state machine and then setup their state transfer connections using the method explained above. So as soon as the builder returns the finite state machine it is completely set up and ready to be used. The exit points of each state cannot be altered anymore, because the methods for setting them would throw an exceptions if called, since the builder called them once already while creating the finite state machine.

Thank you to everybody for helping me on this issue.

Daniel Baulig
Glad to help, and I think your setup is fairly elegant.
EricBoersma