Doug's Resume
OO Lexicon
Chat with Doug!
Recent Entries
You may also be interested in...

heaters
hotels boeken in 7 sec
Engagement Rings
Online Dating Australia




SURF'S UP!
You:
Your Web Site:
<< July, 2008 >>
SMTWTFS
12345
6789101112
13141516171819
20212223242526
2728293031
Search Blog

ColdFusion Jobs
Recent Comments
Categories
Archives
Photo Albums
Funnies (5)
Family (3)
RSS
Reciprocal Links

Powered by
BlogCFM v1.11

20 June 2007
Circular Dependency Experiment
Circular Dependency is a phrase used to describe two objects who both use one another internally. That's simple enough. But...how the heck do those two OBJs get inside each other? And how do they behave once they're in there? These were some of the questions I needed answers to, and so I'd like to share with you my experiment and some of the things it taught me about circular object dependency.

I basically had the following questions I wanted to answer:

  1. How can I successfully get instantiated objects inside one another?
  2. Once instantiated, does object 2's manipulation of its internal copy of object 1 affect object 1's state, and vica versa?

Getting Objects Inside One Another
Okay, so how do we get an object inside another object? We inject it (embrace the phrase, you're gonna hear it a lot in the OO world!). With Coldfusion CFCs, this can be done one of two ways that I'm aware of: using "Setter Injection", or "Constructor Argument Injection". The Coldspring framework does that very thing for us when we leverage it in our apps, BUT I wanted to know what the raw, manual process of doing so looked like, so I created two sets of rudimentary CFCs, each of which has circular dependencies within them.

The first set (CFC1 and CFC2) have dependencies which utilize setter injection; The second set (CFCA and CFCB) use constructor arguments to get inside each other. CFC1 and CFC2 are identical, code-wise, as are CFCA and CFCB. Here is what they look like:
CFC1 and 2:
<cfcomponent displayname="CFC1 and CFC2">
    <cffunction name="init" access="public" returntype="any">
        <cfreturn this>
    </cffunction>
    <cffunction name="getMyName" access="public" returntype="string">
        <cfreturn variables._myname />
    </cffunction>
    <cffunction name="setMyName" access="public" returntype="void">
        <cfargument name="newname" type="string" required="true" />
        <cfset variables._myname = arguments.newname />
    </cffunction>   
    <cffunction name="getObj2" access="public" returntype="any">
        <cfreturn variables._obj2 />
    </cffunction>
    <cffunction name="setObj2" access="public" returntype="void">
        <cfargument name="obj2" type="any" required="true" />
        <cfset variables._obj2 = arguments.obj2 />
    </cffunction>
</cfcomponent>

(The Setter Injection method, as seen in CFC1, simply utilizes a "setObj2" method to set an internal variables-scoped variable to hold an instantiated copy of CFC2)


CFCA and B:
<cfcomponent displayname="CFCA and CFCB">
    <cffunction name="init" access="public" returntype="any">
        <cfargument name="obj2" type="any" required="true" />
        <cfargument name="myName" type="string" required="true" />
        <cfset variables._myName = arguments.myName />
        <cfset variables._obj2 = arguments.obj2 />
        <cfreturn this>
    </cffunction>
    <cffunction name="getMyName" access="public" returntype="string">
        <cfreturn variables._myname />
    </cffunction>
    <cffunction name="setMyName" access="public" returntype="void">
        <cfargument name="newname" type="string" required="true" />
        <cfset variables._myname = arguments.newname />
    </cffunction>   
    <cffunction name="getObj2" access="public" returntype="any">
        <cfreturn variables._obj2 />
    </cffunction>
    <cffunction name="setObj2" access="public" returntype="void">
        <cfargument name="obj2" type="any" required="true" />
        <cfset variables._obj2 = arguments.obj2 />
    </cffunction>
</cfcomponent>

(Notice that I still do have setters and getters for obj2; I didn't really have to have a setter, but the getter is needed so I can retrieve obj2 and call its methods)

Here is the code I used to instantiate CFC1 and CFC2 using the Setter Injection method:
<cfscript>
    //circular dependency using setter injection...
    obj1 = createobject("component","CFC1").init();
    obj2 = createobject("component","CFC2").init();
    obj1.setMyName(newname="Object 1");
    obj1.setObj2(obj2);
    obj2.setMyName(newname="Object 2");
    obj2.setObj2(obj1);
</cfscript>

Here is the code I used to instantiate CFCA and CFCB using the constructor argument method:
<cfscript>
    //circular dependency using constructor argument injection
    objA = createobject("component","CFCA");
    objB = createobject("component","CFCB");
    objA.init(obj2 = objB.init(obj2 = objA,myName="object B"),myName="object A");
</cfscript>

Okay, everything instantiated without any errors! Cool, and I have answered my first question. Now for question 2...

Object Behavior
How do these objects behave when set up in this fashion? To find out, I conducted interviews with each of the objects. Following are some exerpts and code snippets from those interviews (full interview can be seen here):

Interviewing obj1...

Q: What is your name?
A: My name is Object 1!
My name is #obj1.getMyName()#!
Q: What is your dependent object's name?
A: My dependent object's name is Object 2!
My dependent object's name is #obj1.getObj2().getMyName()#!

Interviewing obj2...

Q: What is your name?
A: My name is Object 2!
My name is #obj2.getMyName()#!

Q: What is your dependent object's name?
A: My dependent object's name is Object 1!
My dependent object's name is #obj2.getObj2().getMyName()#!

Q: Can you change your dependent object's name?
A: I don't know...let's give it a try, shall we?
(lots of grunting and straining sounds can be heard...)
<cfscript>
    obj2.getObj2().setMyName(newname="Eduardo");
</cfscript>

I think I did it! My dependent object's name is NOW Eduardo!
I think I did it! My dependent object's name is NOW #obj2.getObj2().getMyName()#!

Interviewing obj1 again...

Q: What is your name NOW, obj1?
A: My name is Eduardo!
My name is #obj1.getMyName()#!

Q: Why don't you go ahead and try to change YOUR dependent object's name...
A: Sure thing! My dependent object's new name is Florence. He he he he he.
<cfscript>
    obj1.getObj2().setMyName(newname="Florence");
</cfscript>
My dependent object's new name is #obj1.getObj2().getMyName()#. He he he he he.

Interviewing obj2 again...

Q: Obj2, is that really your new name?
A: Lemme check... Florence...yep!
Lemme check...#obj2.getMyName()#...yep!

I conducted the same interview with objA and objB, and the answers were identical.

My Conclusion
Circular dependencies, in my experiment, are nothing more than providing each object with a proper internal reference to the instance of the other object, in a reciprocal fashion. The fact that I could change the value of a variables-scoped variable in an injected instance of obj2, and that change be visible by obj2 itself from outside of obj1 proves that point unequivocably. Just for fun, I asked one final question of Obj1:

One Final Deep Question for obj1...

Q: Obj1, what is the name of your dependent object's dependent object's dependent object's dependent object?
A: It's name is Florence
It's name is #obj1.getObj2().getObj2().getObj2().getMyName()#


Cool stuff. Remember though, Coldspring is there for you to manage all of this so that you don't HAVE to do it manually. Coldspring can perform even deeper work, too, like injecting individual METHODS into objects on the fly! That's a little thing I like to call Aspect Oriented Programming, or AOP. You should take the time to investigate it.

Doug out.



Posted by dougboude at 2:26 PM | PRINT THIS POST! |Link | 3 comments
Subscription Options

You are not logged in, so your subscription status for this entry is unknown. You can login or register here.

Re: Circular Dependency Experiment
Doug, this is one of the coolest circular dependency posts I have seen. Awesome experiment!
Posted by Ben Nadel on June 21, 2007 at 8:57 AM

Re: Circular Dependency Experiment
Well done Doug. I think you've done a great job explaining Circular Dependency and its implementation between this and your last post.

Always good to see how someone else views a topic and this will be a valuable post for those learning as well.

Mike.
Posted by Mike Kelp on June 21, 2007 at 9:29 AM

Re: Circular Dependency Experiment
Thanks for the kudos, everyone!. I know I can't be the only one out there who sometimes takes a little longer to grasp a new concept or wade through the jargon, so figured that in the spirit of the community (and the internet) it's my duty to share what I learn. Hope it helps someone!
Posted by Doug Boude on June 21, 2007 at 10:31 AM

Name:   Required
Email:   Required your email address will not be publicly displayed.

Want to receive notifications when new comments are added? Login/Register for an account.

Time to take the Turing Test!!!

What letter comes three place(s) after the letter L?
Type your answer exactly two time(s) in the designated box.

Type in the answer to the question you see above:

Your comment:

Sorry, no HTML allowed!