Write efficient code with the Composition object pattern and CFCs

You can harness the power of object-oriented programming by using ColdFusion Components (CFCs). See how to use CFCs in conjunction with the Composition object pattern to simplify your app development.

For ColdFusion developers, the door to the object-oriented world was finally opened with ColdFusion MX. Version 6.1 allows for the creation of ColdFusion Components (CFC). These constructs deliver many of the benefits of object technology, including inheritance, methods, and polymorphism.

Through CFCs, developers can now apply many well-established object patterns like the Strategy pattern and the Singleton pattern. In this article, I'm going to demonstrate an object pattern called Composition, which can be used with CFCs.

A phone number
Before we jump into using Composition, let's look at a situation where it's not used. This example is simple: a phone number.

Let's say we have created a Customer CFC which encapsulates data and methods related to a customer. One data parameter that the Customer CFC contains is the customer's phone number. At first glance, this might not seem especially interesting. We can easily create some code to get and set a phone number:
<cffunction name="setCustomerPhoneNumber" returntype="void">
       <cfargument name="aPhoneNumber" type="string">
       <cfset _customerPhoneNumber = arguments.aPhoneNumber>

<cffunction name="getCustomerPhoneNumber" returntype="string">
       <cfreturn _customerPhoneNumber>

Seems simple enough, doesn't it? But let's think this through a bit more. Right now, all we're doing is passing in a string, hoping it's a phone number, and setting the variable. We'll probably want to ensure that the string is actually a phone number. Okay, so we can add some validation to our setCustomerPhoneNumber() method. And, if you think about it, the validation will be pretty extensive: Is the string the right length for a U.S. phone number? Does the area code have parentheses around it? Is each portion of the number separated by a dash or a space? And this can be taken further: What if we want to be able to return only the area code or to return the number in a constant format?

Okay, still not much of a problem. We could add validation, and we could parse the phone number into its subelements, like area code and prefix, and then create setters and getters for those. Our "simple" phone number methods are now getting more numerous and complex. But this would work—and our customer CFC would eventually have methods and data values for whatever we require.

This all seems fine and good, until you remember that there are other CFCs that need a phone number. How about an Office CFC? A Company Car CFC?A Supplier?A Pager? You can probably think of others.

What do we do—duplicate all the code that handles phone numbers in our Customer CFC into our Office CFC and then duplicate it again into all the other CFCs that need a phone number? Of course not. We just eliminate the problem by using Composition with our CFCs.

A phone number with Composition
Composition is an object pattern in which one CFC contains instances of other CFCs. In this case, we'll create a PhoneNumber CFC, which handles all the methods and data related to a phone number. Once we define the PhoneNumber CFC, we can create an instance of PhoneNumber within our Customer and Office CFCs. Now, whenever we need to do something with a phone number, we call methods on that instance of PhoneNumber. For example, Listing A shows a sample PhoneNumber CFC.

The PhoneNumber component does some basic validation, parses out the area code, prefix, and last four numbers, and provides a way to return the number in a standard format. Now, we can use an instance of this CFC from within our Customer CFC:
<cffunction name="setCustomerPhoneNumber" returntype="void">
    <cfargument name="aCustomerPhoneNumber" type="string" required="Yes">
    <cfset _phoneNumber = createObject( 'component', 'phoneNumber' )>
    <cfset _phoneNumber.init( arguments.aCustomerPhoneNumber )>

When you need to do something like output the phone number, the Customer CFC will return the instance of PhoneNumber to the caller. Then, the caller can use any of the methods we defined in PhoneNumber. First the getCustomerPhoneNumber() method:
<cffunction name="getCustomerPhoneNumber">
    <cfreturn _phoneNumber>

Figure A shows a CFDUMP of _phoneNumber, which is what the caller gets back.

Figure A
ColdFusion dump of PhoneNumber

Because _phoneNumber contains an instance of the PhoneNumber CFC, the calling code shown in Listing B can now do whatever it needs to with it.

The function getCustomerPhoneNumber() returns the instance of the PhoneNumber CFC, and, from there, we can call any methods that PhoneNumber understands, such as getPhoneNumber(). This would output a formatted phone number. We could then do the same thing within an Office CFC or any other CFC that needs to maintain a phone number as part of its duties. All of these objects will just be holding their own specific instances of PhoneNumber.

Going further with Composition
Now that the wheels are turning, you might start to see how this idea could be applied in a huge number of situations. Customers have addresses; so do offices and airports. You could create an Address CFC and instantiate it within any other CFC that needs to incorporate an address.

It's easy to think of examples where applying Composition simplifies your CFCs and reduces code duplication. A ShoppingCart CFC could contain one or more Product instances. So could a Shipment CFC or a Warehouse CFC.

I hope that this discussion of using Composition with CFCs helps you write more efficient and object-oriented ColdFusion applications. Please e-mail me or post to the discussion thread at the bottom of the page if you have any questions or comments.

Editor's Picks