Structuring and reusing code



Component inheritance and the Super keyword are two important tools for creating structured, object-oriented ColdFusion components.

Component inheritance
Lets you create a single base component and reuse this code in multiple subclasses that are derived from the base component. Typically a base component is more general, and subcomponents are typically more specific. Each subclass does not have to redefine the code in the base component, but can override it if necessary.

The Super keyword
Lets a component that overrides a base component method execute the original base component method. This technique lets your subclassed component override a method without losing the ability to call the original version of the method.

Using component inheritance

Component inheritance lets you import component methods and properties from one component to another component. Inherited components share any component methods or properties that they inherit from other components, and ColdFusion initializes instance data in the parent CFC when you instantiate the CFC that extends it.

Component inheritance defines an is a relationship between components. For example, a component named president.cfc inherits its methods and properties from manager.cfc, which inherits its methods and properties from employee.cfc. In other words, president.cfc is a manager.cfc; manager.cfc is an employee.cfc; and president.cfc is an employee.cfc.

In this example, employee.cfc is the base component; it’s the component upon which the others are based. The manager component extends the employee component; it has all the methods and properties of the employee component, and some additional ones. The president component extends the manager component. The president component is called a subcomponent or child component of the manager component, which, in turn, is a child component of the employee component.

  1. Create the employee.cfc file with the following content:

    <cfcomponent> 
        <cfset This.basesalary=40*20> 
    </cfcomponent>
  2. Create the manager.cfc file with the following content:

    <cfcomponent extends="employee"> 
        <cfset This.mgrBonus=40*10> 
    </cfcomponent>

    In the example, the cfcomponent tag’s extends attribute points to the employee component.

  3. Create the president.cfc file with the following content:

    <cfcomponent extends="manager"> 
        <cfset This.prezBonus=40*20> 
    </cfcomponent>

    In the example, the cfcomponent tag’s extends attribute points to the manager component.

  4. Create the inherit.cfm file with the following content, and save it in the same directory as the components you created in the previous steps:

    <cfobject name="empObj" component="employee"> 
    <cfobject name="mgrObj" component="manager"> 
    <cfobject name="prezObj" component="president"> 
    <cfoutput> 
        An employee's salary is #empObj.basesalary# per week.<br> 
        A manager's salary is #mgrObj.basesalary + mgrObj.mgrBonus# per week.<br> 
        A president's salary is #prezObj.basesalary + prezObj.mgrBonus + 
            prezObj.PrezBonus# per week. 
    </cfoutput>

When you browse the inherit.cfm file, the manager component refers to the basesalary defined in employee.cfc, which is the base component; the president component refers to both the basesalary defined in the employee component, and the mgrBonus defined in the manager component. The manager component is the parent class of the president component.

Using the component.cfc file

All CFCs automatically extend the ColdFusion WEB-INF/cftags/component.cfc component. (The WEB-INF directory is in the cf_root/wwwroot directory on ColdFusion configured with an embedded J2EE server. It is in the cf_root directory when you deploy ColdFusion on a J2EE server.) This CFC is distributed as a zero-length file. You can use it for any core methods or properties that you want all CFCs in your ColdFusion application server instance to inherit.

Note: When you install a newer version of ColdFusion, the installation procedure replaces the existing component.cfc file with a new version. Therefore, before upgrading, save any code that you have added to the component.cfc file, and then copy the code into the new component.cfc file.

Using the Super keyword

You use the Super keyword only on CFCs that use the Extends attribute to extend another CFC. Unlike ColdFusion scopes, the Super keyword is not used for variables; it is only used for CFC methods, and it is not available on ColdFusion pages that invoke CFCs.

The Super keyword lets you refer to versions of methods that are defined in the CFC that the current component extends. For example, the employee, manager, and president CFCs each contain a getPaid method. The manager CFC extends the employee CFC. Therefore, the manager CFC can use the original versions of the overridden getPaid method, as defined in the employee CFC, by prefixing the method name with Super.

  1. Create the employee.cfc file with the following content:

    <cfcomponent> 
        <cffunction name="getPaid" returntype="numeric"> 
            <cfset var salary=40*20> 
            <cfreturn salary> 
        </cffunction> 
    </cfcomponent>
  2. Create the manager.cfc file with the following content:

    <cfcomponent extends="employee"> 
        <cffunction name="getPaid" returntype="numeric"> 
            <cfset var salary=1.5 * Super.getPaid()> 
            <cfreturn salary> 
        </cffunction> 
    </cfcomponent>
  3. Create the president.cfc file with the following content:

    <cfcomponent extends="manager"> 
        <cffunction name="getPaid" returntype="numeric"> 
            <cfset var salary=1.5 * Super.getPaid()> 
            <cfreturn salary> 
        </cffunction> 
    </cfcomponent>
  4. Create the payday.cfm file with the following content, and save it in the same directory as the components that you created in the previous steps:

    <cfobject name="empObj" component="employee"> 
    <cfobject name="mgrObj" component="manager"> 
    <cfobject name="prezObj" component="president"> 
    <cfoutput> 
        <cfoutput> 
            An employee earns #empObj.getPaid()#.<br> 
            A manager earns #mgrObj.getPaid()#.<br> 
            The president earns #prezObj.getPaid()#. 
        </cfoutput> 
    </cfoutput>

In this example, each getPaid method in a child component invoked the getPaid method of its parent component. The child’s getPaid method then used the salary returned by the parent’s getPaid method to calculate the appropriate amount.

Included pages can use the Super keyword.

Note: The Super keyword supports only one level of inheritance. If you use multiple levels of inheritance, you can only use the Super keyword to access the current component’s immediate parent. The example in this section illustrates handling this limitation by invoking methods in a chain.

Using component packages

Components stored in the same directory are members of a component package. Component packages help prevent naming conflicts, and facilitate easy component deployment; for example:

  • ColdFusion searches the current directory first for a CFC. If you place two components in a single directory as a package, and one component refers to the other with only the component name, not a qualified path, ColdFusion always searches the package directory first for the component. As a result, if you structure each application’s components into a package, your applications can use the same component names without sharing the component code.

  • If you use the access="package" attribute in a method’s cffunction tag, access to the method is limited to components in the same package. Components in other packages cannot use this method, even if they specify it with a fully qualified component name. For more information on access security, see Using access security.

Invoke a packaged component method with the cfinvoke tag

  1. In your web root directory, create a directory named appResources.

  2. In the appResources directory, create a directory named components.

  3. Copy the tellTime2.cfc file you created in Invoking methods of a CFC instance and the getUTCTime.cfm file that you created in Placing executable code in a separate file to the components directory.

  4. Create the timeDisplay.cfm file with the following content and save it in your web root directory:

    <!--- Create the component instance. ---> 
    <cfobject component="appResources.components.tellTime2" name="tellTimeObj"> 
    <!--- Invoke the methods. ---> 
    <cfinvoke component="#tellTimeObj#" method="getLocalTime" 
        returnvariable="localTime" > 
    <cfinvoke component="#tellTimeObj#" method="getUTCTime" 
        returnvariable="UTCTime" > 
    <!--- Display the results. ---> 
    <h3>Time Display Page</h3> 
    <cfoutput> 
        Server's Local Time: #localTime#<br> 
        Calculated UTC Time: #UTCTime# 
    </cfoutput>

    You use dot syntax to navigate directory structures. Place the directory name before the component name.

  5. Browse the timeDisplay.cfm file in your browser.

The following example shows a CFScript invocation:

<cfscript> 
helloCFC = createObject("component", "appResources.components.catQuery"); 
helloCFC.getSaleItems(); 
</cfscript>

The following example shows a URL invocation:

http://localhost/appResources/components/catQuery.cfc?method=getSalesItems

Using CFCs in persistent scopes

You can place a CFC instance in the Session or Application scope. This way, the component properties continue to exist while the scope persists. For example, if you use a CFC for a shopping cart application, where the shopping cart contents must persist for the length of the user’s session. If you place the shopping cart CFC in the Session scope, you can use component properties to store the cart contents. For example, the following line creates an instance of the shoppingCart component in the Session scope:

<cfobject name="Session.myShoppingCart" component="shoppingCart">

Code that manipulates persistent scope CFC properties must be locked, just as all other code that manipulates persistent scope properties must be locked. Therefore, lock both of the following types of application code:

  • Code that directly manipulates properties of a persistent scope CFC instance

  • Code that calls methods of a persistent scope CFC instance that manipulate properties of the instance

If you place multiple CFC instances in a single persistent scope, you can create a named lock for each CFC instance. For more information on locking, see Using Persistent Data and Locking.

Note: Session scope CFCs cannot be serialized, so you cannot use them with clustered sessions; for example, if you want to support session failover among servers.