Christopher R contacted me through my contact form to ask about object composition. I thought I would answer it here in case it helps other folks as well. I'm also planning on answering questions like this going forward, so if anyone has questions that you think I can help with, feel free to contact me through the blog and I'll do my best to answer!

greetings...i recently came across a great article you wrote called "Write efficient code with the Composition object pattern and CFCs". it greatly assisted in my initial dilemma involving how to relate distinct but related classes. the current article works for related classes (PhoneNumber) into which you pass a final piece of data (e.g. the phone number). however, whats the best approach when that data is merely a reference or pointer (e.g. PhoneID) that requires further querying / creation of data access objects? as an example, several customers may share the same phone number (PhoneID). in this case - bear in mind that we still want to stick to OOP + not introduce db queries into the related class (e.g. PhoneID.cfc) - we might use a DAO to communicate with the related class (e.g. PhoneDAO.cfc) into which we would need to pass a database ref along with the PhoneID(s) in order to find the proper record. i would like to return a reference to the Phone object that the main class (e.g.Customer) could then utilize. to better elucidate the approach, im following a series of articles at iknowkingfoo.

hopefully this makes some sense - difficult to encapsulate in writing succintly. im getting up in arms as far as these objects, accessing their data as well as trying to access application variables. any help greatly appreciated.

thanks in advance.

To reiterate, composition models a "has-a" relationship between objects, as opposed to an "is-a" relationship which is typically done through inheritance or interface implementation. However, Christopher seems to be working with two different kinds of objects here: Singletons and business objects. How you handle the composition can depend on the kind of object you are dealing with and what they are meant to do.

For example, a PhoneDAO would almost certainly be a Singleton object, meaning that only one instance of the PhoneDAO exists in the application. However, a PhoneNumber object would be a business object, meaning that there could be many instances of PhoneNumber, each with their own data, modeling many different actual phone numbers. The same goes for Customer. Customer is a business object.

The question seems to be how to build up composite object relationships in your business objects. The answer is usually to use a Factory to build your business object. The Factory would also be a Singleton since you only need one. So Christopher might consider creating a CustomerFactory which he would call "getCustomer(13)" on to create an instance of that Customer and return it. The factory would then be responsible for also creating and setting any composite objects. As a result, the factory may itself have other singletons composed within it such as a CustomerDAO, PhoneNumberDAO, etc. The factory would use these objects and know what to do with the results (in this case, setting the resulting PhoneNumber into the resulting Customer before returning it).

The idea with factories is not only that they create objects. It has to do with the primary OO design principle of encapsulation. What the factory encapsulates is knowledge of how to create and relate a Customer and a PhoneNumber. This is crucial to understand, because it means that you become free to change how the Customer and PhoneNumber are created and related at any time. Nothing outside the factory would ever know that you made any changes.

Consider the Transfer ORM framework. Transfer handles making queries to the database as well as building object relationships for you. It is very handy, and I would recommend that Christopher have a look at it when he has the time to evaluate it. But lets say that he creates a CustomerFactory and any code that needs a user calls customerFactory.createCustomer(id). If he later decides to use Transfer, he can easily make that change because he only has to change one thing: the CustomerFactory. He can remove his own DAOs and rip out the logic that relates these objects, and replace it with calls to Transfer. Nothing outside his factory needs to know that the way these objects are being created has changed. That is the beauty and power of encapsulation, and why factories are so useful.

For building composite relationships in your Singletons, there is another option to consider: the ColdSpring framework. This framework is designed primarily to "wire up" or relate your Singleton objects. That means things like Services, DAOs, Gateways, etc. It is a really powerful tool but does have a learning curve to wrap your head around. I have a number of blog entries on ColdSpring and there are numerous other blogs and mailing lists that can help with this as well. If you give ColdSpring a look and I can offer any additional help please let me know.

Hopefully that helps, Christopher? I'd look at using a factory to handle creating and relating your objects. The factories can get rather complex if you have a lot of object relationships to manage, but again, the logic is all kept in the factories. It's certainly possible for one factory to use another factory as well, so don't feel like you have to create a single uber-factory that does everything. And if or when you decide to try out another approach such as Transfer, you'll be happy you went the factory route. Good luck!

Comments Comments (1) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 6567 Views

Comments