| By Brendan O'Hara | Article Rating: |
|
| October 15, 2003 04:41 PM EDT | Reads: |
13,671 |
With the recent introduction of ColdFusion MX 6.1, developers continue to explore the new features and improvements ColdFusion has to offer. What you may discover, as I have, is that we have hardly scratched the surface of what is possible with ColdFusion Components (CFCs). Introduced last year with the release of ColdFusion MX, CFCs were a radical leap forward for the language. Getting used to this new paradigm, and getting the most out of it, will take a while even for the most seasoned CF developer.
ColdFusion MX is built on top of the Java/J2EE platform; in fact MX 6.1 now includes a full version of JRun, Macromedia's Java application server. ColdFusion has the ability to directly connect to and utilize Java natively. This gives developers the tremendous power of Java in addition to the Rapid Application Development (RAD) capabilities of ColdFusion and CFML.
However, most of us aren't Java experts, and J2EE projects, although highly scalable and stable, aren't easy or fast to develop. This is especially true in comparison to ColdFusion. In addition to this new (in MX) and expanded Java interactivity, we also have a CFML extension to the language. ColdFusion Components, or CFCs, can be used in many of the same ways as Java objects. They are not pure OOP but they are pure CF. That is, after a small learning curve on creating and using CFCs in your code, the actual writing of CFCs is done completely in ColdFusion so as to make it open to the entire range of CF developers.
So what are CFCs good for? Are they simply static function libraries? Are they object-light components used for Flash Remoting or Web services? Are they a replacement for custom tags? Are they objects? The answer to all of these questions is "Yes." They can be all of those things and so much more. If you have read a number of my previous articles you know I love CFCs and use them for just about everything.
Static Methods and Function Libraries
Since we are at release 6.1, I'll assume
everyone has had some experience with
user-defined functions, or UDFs. The
script-based variety was introduced in
ColdFusion 5.0. UDFs are extremely useful
ways to expand the functionality of
ColdFusion. UDFs are custom functions
we create to eliminate repetitive coding of
simple processing routines or to ensure
that those routines aren't forced to live
inside a custom tag as they had to before
ColdFusion 5.0. In ColdFusion MX, a tagbased
UDF syntax was introduced, using
the <CFFUNCTION> tag, that further
expanded UDFs and also makes up the
basis for the writing methods inside a
CFC. To use a CFC method as a static (or
nonpersistent) function, use this syntax:
<cfinvoke component="tax" method="getRateByState"
returnvariable="taxrate" state ="PA" />
This method returns the sales tax rate for a passed-in state code. This is one approach. Another is to use the <CFOBJECT> tag to create a variable that is a reference to an entire collection of functions or a function library. To create a reference to your function library, you call <CFOBJECT>, the same as creating any other CFC reference:
<cfobject component="myTaxFunctionLibrary" name="tax">
Since this CFC instance "persists" you can access any function from your library using <CFINVOKE> as shown:
<cfinvoke component="#tax#" method="getRateByState"
returnvariable="taxrate" state ="PA" />
You can also call the function inline; simply reference with dot (.) syntax as in #CFC.Method(args)#. This is available because the variable "tax" references the CFC instance, which is our function library.
#Tax.getRateByState("PA")#
While this is the way static function libraries would be done in Java, it isn't in my opinion the best way to do it in ColdFusion. I'll explain why. In general, objects have Class data and Instance data as well as Class methods and Instance methods. Class data is the same for every instance of a CFC. Instance data is different for most or all instances of the CFC. Instance data is usually set in a constructor or initialization method often named init(). If a CFC method doesn't use any "instance data" and doesn't make any <CFQuery> database calls, it probably shouldn't be an instance method. Instance methods access instance-specific data for dynamic runtime processing. Class methods act exactly like UDF functions. They process dynamically, but they do so based only on passed-in arguments, since like a UDF, they have no instance data to use.
In Java you are forced to create static functions within a Class because everything is an object in Java. ColdFusion, while more structural in nature, does not have that "limitation". Perhaps the best solution in ColdFusion is to treat static functions similarly to a JavaScript function library. You are able to create a .CFM file containing all of your UDFs. You can then <cfinclude> this at the top of your page (or perhaps in Application.cfm) and you will now have these UDF functions available within your pages. The syntax for this is below:
<cfinclude template="/myUDFLibrary.cfm">
PA Tax Rate: <cfoutput>#GetRateByState("PA")#</cfoutput>
In that case you do not need a prefix to identify the UDF, since the function doesn't belong to a CFC instance, but you do need to be careful you do not have two UDFs with the same name. In fact, if you have a CFC with 50 methods and a .CFM file with 50 UDFs, although the functions are identical, they do not take the same amount of time to process. The CFC takes significantly more time to process although you could cache the CFC instance in the Session, Application, or even Server scope. In that case it will take a little longer the first time through, but after that, no time at all.
So what rule do I go by when making this determination? I
ask myself the following questions:
1. Do I have a CFC that the function is directly related to?
2. Does the function access a database or another file?
3. Do I need to call that function directly from Flash?
4. Do I want/need to call that function as a Web service?
If any of these are true, I put it in a CFC. For 95% of standalone functions, a .CFM file as a UDF library is the best bet. By far the most comprehensive collection of UDFs on the Web is the repository at the Common Function Library Project (www.cflib.org). The site's creators, Raymond Camden and Rob Brooks-Bilson, as well as other notables such as Ben Forta, have crafted literally thousands of useful functions to extend ColdFusion 5.0, MX, and MX 6.1.
Components As Components?
Whether utilizing Flash Remoting or Web services, there are
numerous ways to get information out of CFCs. In Flash
Remoting, unless you store the CFC instance in the Session
scope, all access is through static or nonpersistent methods. Web
services, like a remote procedure call, do not actually create a
session when they connect. They cannot store a CFC instance in
Session scope and then retrieve it so they are also completely
static. When CFCs are used with a number of related methods
but do not use any instance data and/or they need to be
accessed remotely, then they are less "objects" than "components."
They do not persist data, are less dependent on instantiation,
and are more likely to be accessed via Web services to perform
some specific task on passed-in data. This is more akin to
how COM objects are routinely used. Many in the software
development industry have been extolling the virtues of a new
type of programming referred to as "component-based development."
Think of it as an extension or perhaps an alternative to
object-oriented design. While ColdFusion is not entirely objectoriented
or component-based, it has the ability and facility to
work in both paradigms.
For developers interested in utilizing design patterns with Flash Remoting, I must highly recommend Sean Corfield's article on the Macromedia Web site that talks extensively about using the Facade design patten with CFCs for Flash Remoting. The article can be found at www.macromedia.com/devnet/mx/flashremoting/articles/facades.html.
Components As Objects!
Now we arrive at the heart of the matter as it relates to design
patterns and object creation. One thing we should be aware of is
that objects need to be instantiated. In ColdFusion our native
"objects" are CFCs so they need to be instantiated to persist
across method calls and be treated like real objects in the OOP
sense. Creational patterns tend to encapsulate and abstract the
instantiation process. That is, we may make creating a CFC
through <CFOBJECT> or createObject() the responsibility of
another CFC or perhaps even a custom tag. It can be useful for
simplifying the code needed to initiate certain processes and to
manage the construction and destruction of a large number of
CFC object instances. Although it draws closer with every
release, ColdFusion MX 6.1 is not purely object oriented. As CF
developers we are likely to have little experience with the benefits
and drawbacks of any type of "object creation." What do
we need to know or what can we relate this to? We need to
know how to reference a CFC object, how to create a specific
type of CFC object, and using design patterns, how to vary the
actual type of CFC being created. Below is the normal instantiation
process as it works in Java and ColdFusion. First you reference
the object, then you call a constructor method to create
the instance:
Java:
ClassName myInstanceName;
ColdFusion:
<CFObject component="ClassName"
name="myInstanceName">
You would then call a constructor like this:
Java:
myInstanceName = new ClassName(args);
ColdFusion:
<CFInvoke component="#myInstanceName#"
method="init"
argumentcollection="#argsStruct#">
This ColdFusion "constructor" isn't an official constructor as we see in Java. In Java the constructor is always the class name following the new keyword. In CF you can call constructors any name you want or eliminate them completely. In addition, any code in a CFC outside of a <CFFUNCTION> is processed once at the time the CFC is initialized. This generally happens on a call to <CFOBJECT> or createObject() or before the first method is invoked. Without the dynamic initialization provided by a constructor method or initialization outside of <CFFunction>, your CFC is more or less static in nature. What that means is that although you may have data that persists across method calls, if the data isn't set into the "this" or "variables" scopes through some form of dynamic initialization, then you aren't taking advantage of the fact that the instances are the same. You are therefore treating it more or less like a static UDF.
You can also simplify the call by combining the two statements to call the constructor and return a new CFC reference at the same time.
Java:
ClassName myInstanceName = new ClassName(args);
ColdFusion:
<CFInvoke component="ClassName"
method="init"
argumentcollection="#argsStruct#"
returnvariable="myInstanceName">
It should be noted that this combined statement example requires that the Init() method return "this", which is the internal CFC reference to itself.
Creational Patterns
As we have already said, creational patterns encapsulate and
abstract the instantiation process. This actually means a number
of things. When dealing with classes or types of CFCs, creational
patterns vary the class being instantiated. That is, a method that
returns a CFC instance may return different types of CFC
instances depending on passed-in parameters. Additionally, creational
patterns encapsulate knowledge of which CFC we are
actually using. This allows us to completely hide how instances
are created and assembled. In fact creational patterns almost
always delegate instantiation to another object.
As we do every month when talking about object-oriented
design patterns we like to refer to the original "intent" of the
pattern as laid out in the book (Design Patterns: Elements of
Reusable Object-Oriented Software). As the preeminent work
on the subject of design patterns, its authors, the so-called
"Gang of Four," established the general "intent" of the following
creational patterns:
Overall, creational patterns gain most of their advantages in their inherent flexibility. These techniques allow the developer full control over what gets created, who creates it, and how it gets created even though each object may be chosen to be created and instantiated dynamically. You write a CFC so that it can instantiate other CFCs without being dependent on any of the CFCs it instantiates. Take the following example:
<cfcomponent displayname="Person">
<cfset Variables.Name = "">
<cffunction name="Init" access="public" returntype="struct">
<cfargument name="Name" required="Yes" default="">
<cfset Variables.Name = Arguments.Name>
<cfreturn this>
</cffunction>
<cffunction name="getName" access="public" returntype="string">
<cfreturn Variables.Name>
</cffunction>
</cfcomponent>
This CFC uses an Init() method as a constructor, which returns "this", a reference to the CFC itself, to the calling page. It takes one argument – the string representing the Person instance's name. That is set into the Variables scope within the CFC and persists for as long as the CFC does. I call the CFC this way:
<cfinvoke
component="Person"
method="Init"
returnvariable="myPerson">
<cfinvokeargument name="Name" value="Simon Templar">
</cfinvoke>
That's a pretty standard use of a constructor method to return the CFC instance, which is of the CFC type "Person". Now take a look at a CFC that chooses what CFC to return dynamically:
<cfcomponent displayname="Employee" extends="Person">
<cfset Variables.Name = "">
<cfset Variables.Title = "">
<cfset Variables.EmployeeID = "">
<cffunction name="Init" access="public" returntype="struct">
<cfargument name="EmployeeID" type="numeric" required="Yes" default="">
<cfquery name="EmpQuery" datasource="employee">
SELECT EmployeeType, Name, Title
FROM Employee
WHERE EmployeeID = '#Arguments.EmployeeID#'
</cfquery>
<cfinvoke
component="#EmpQuery.EmployeeType#Employee"
method="Init"
returnvariable="myEmployee">
<cfinvokeargument name="Name" value="#EmpQuery.Name#">
<cfinvokeargument name="EmployeeID"
value="Arguments.EmployeeID#">
<cfinvokeargument name="Title" value="#EmpQuery.Title#">
</cfinvoke>
<cfreturn myEmployee>
</cffunction>
</cfcomponent>
This CFC uses an Init() method as a constructor that returns a CFC instance but it isn't a reference to that CFC. It takes one argument, which is an employee ID number. It queries an employee database to determine what type of employee this EmployeeID represents. It then takes the information from the query and dynamically calls the constructor of the type of CFC this employee represents. I call the CFC this way:
<cfinvoke
component="Employee"
method="Init"
returnvariable="theEmployee">
<cfinvokeargument name="EmployeeID" value="12345">
</cfinvoke>
This may return a "JanitorEmployee" CFC instance or a "WebDeveloperEmployee" CFC instance. This allows your code to remain independent by delegating the choice of which CFC or class to instantiate to another object and referring to the newly created CFC instance through a common interface. This allows an object to create customized objects without knowing their class or any details of how to create them.
Stay Tuned
Next month we'll expand on the topic of object creation as
well as work directly with several creational pattern examples.
We will examine a small document-management system with
multiple implementations that show all four of the previously
mentioned creational design patterns. The document management
system has at its core document objects, which are
instances of document.cfc. Document.cfc is a composite
object as it contains one or more "document parts" that are
themselves CFC instances.
Published October 15, 2003 Reads 13,671
Copyright © 2003 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Brendan O'Hara
Brendan O'Hara is a software architect and CEO of Exos Technology LLC, a software consulting firm in the Philadelphia suburbs.
He co-authored the Advanced Macromedia ColdFusion MX Application Development, published by Macromedia Press, and was
technical reviewer for Programming ColdFusion MX by O'Reilly. Brendan is a Team Macromedia volunteer for
ColdFusion and chairman and founder of the Philadelphia Developers Network. bohara@exostechnology.com
![]() |
Doug Smidt 08/31/04 12:13:25 PM EDT | |||
The code in this article is straightforward, but I''m having a little trouble seeing the advantages to implementing this. As far as I know, there is no way in CF MX 6.1 to determine the type of an object, only if it is an object (i.e. IsObject()). This leaves me with three questions: 2) Building on this point, isn''t this approach only a benefit if all of the extended classes contain the same data members? What if a JanitorEmployee has different data members than a WebDeveloper employee? Isn''t more work required to complete initialization of JanitorEmployee than just the arguments provided in the init() method shown? If we are unable to determine what type of object we have returned, how do we complete the initialization for data members different from the base class Employee? 3) Doesn''t instantiating an object with a returntype of "struct" open the door for errors? Isn''t this a black box where the developer isn''t even sure what will be returned when something is passed in? I''m sure I may be missing the point of the concept, but the other articles on design patterns have really made sense to me. What is it that I''m misunderstanding with this one? Thanks for your time. |
||||
![]() |
David Tananbaum 10/26/03 11:26:52 PM EST | |||
I have installed MX6.1 on a WInServer 2003 box. My local setting work ok for dynamic ip settings. When I brought the servger out to my ISP, I found that I was getting an error when I tried to access the server saying that there was an internal error with a reference to JAVA. Can you assist me to debug this problem. David J. Tananbaum |
||||
![]() |
Xavi Clotet 10/21/03 06:04:42 AM EDT | |||
Hi, u put the datasource name directly (datasource="employee"), but if I want that it be dynamic, which would be the best method? |
||||
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Reader Sued
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Adobe Flex Developer Earns $100K in New York City
- Adobe LiveCycle Enterprise Suite 2 for Cloud Computing
- Adobe Cans Another 9% of its Workforce
- Adobe Betas Target RIAs and Cloud Computing
- Adobe MAX 2009 Online
- Thinking of Flex in London
- Moyea DVD4Web Converter V2.0 Converts DVD to FLV Fast and Synchronously with Watermarks
- Adobe & Salesforce Cut Cloud Deal
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Is Microsoft as Free as Open Source?
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Reader Sued
- The Planet Named “Bronze Sponsor” of Cloud Computing Expo
- Microsoft Expression Web Has Got Game
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Bruce Chizen Joins Voyager Capital as Venture Partner
- My Top Seven Wishes From Adobe MAX 2009
- Adobe Flex Developer Earns $100K in New York City
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers
- The Asynchronous CFML Gateway
- Web Services Using ColdFusion and Apache CXF




































