Continuing in this design patterns series taken from Head First Design Patterns, is a ColdFusion implementation of the Observer Pattern.
Interfaces
Subject.cfc
<cfinterface>
<cffunction access="public" returntype="void" name="registerObserver">
<cfargument required="true" type="Observer" name="o">
</cffunction>
<cffunction access="public" returntype="void" name="removeObserver">
<cfargument required="true" type="Observer" name="o">
</cffunction>
<cffunction access="public" returntype="void" name="notifyObservers">
</cffunction>
</cfinterface>
Observer.cfc
<cfinterface>
<cffunction access="public" returntype="void" name="update">
<cfargument required="true" type="numeric" name="temperature">
<cfargument required="true" type="numeric" name="humidity">
<cfargument required="true" type="numeric" name="pressure">
</cffunction>
</cfinterface>
DisplayElement.cfc
<cfinterface> <cffunction access="public" returntype="void" name="display"> </cffunction> </cfinterface>
Subject Implementation
WeatherData.cfc
<cfcomponent implements="Subject" output="false">
<cffunction access="public" returntype="Subject" name="init">
<cfset VARIABLES.observers = arrayNew(1)>
<cfreturn THIS>
</cffunction>
<cffunction access="public" returntype="void" name="registerObserver">
<cfargument required="yes" type="Observer" name="o" />
<cfset arrayAppend(VARIABLES.observers, ARGUMENTS.o)>
</cffunction>
<cffunction access="public" returntype="void" name="removeObserver">
<cfargument required="yes" type="Observer" name="o" />
<cfset arrayDelete(VARIABLES.observers, ARGUMENTS.o)>
</cffunction>
<cffunction access="public" returntype="void" name="notifyObservers">
<cfset var LOCAL = {}>
<cfloop index="LOCAL.o" array="#VARIABLES.observers#">
<cfset LOCAL.o.update(VARIABLES.temperature, VARIABLES.humidity, VARIABLES.pressure)>
</cfloop>
</cffunction>
<cffunction access="public" returntype="void" name="measurementsChanged">
<cfset notifyObservers()>
</cffunction>
<cffunction access="public" returntype="void" name="setMeasurements">
<cfargument required="yes" type="numeric" name="temperature" />
<cfargument required="yes" type="numeric" name="humidity" />
<cfargument required="yes" type="numeric" name="pressure" />
<cfset VARIABLES.temperature = ARGUMENTS.temperature>
<cfset VARIABLES.humidity = ARGUMENTS.humidity>
<cfset VARIABLES.pressure = ARGUMENTS.pressure>
<cfset measurementsChanged()>
</cffunction>
</cfcomponent>
Display Elements
CurrentConditionsDisplay.cfc
<cfcomponent implements="Observer, DisplayElement" output="true">
<cffunction access="public" returntype="CurrentConditionsDisplay" name="init">
<cfargument required="true" type="WeatherData" name="weatherData">
<cfset VARIABLES.weatherData = ARGUMENTS.weatherData>
<cfset VARIABLES.weatherData.registerObserver(THIS)>
<cfreturn THIS>
</cffunction>
<cffunction access="public" returntype="void" name="update">
<cfargument required="true" type="numeric" name="temperature">
<cfargument required="true" type="numeric" name="humidity">
<cfargument required="true" type="numeric" name="pressure">
<cfset VARIABLES.temperature = ARGUMENTS.temperature>
<cfset VARIABLES.humidity = ARGUMENTS.humidity>
<cfset display()>
</cffunction>
<cffunction access="public" returntype="void" name="display">
<cfoutput>
Current conditions: #VARIABLES.temperature#F degrees and #VARIABLES.humidity#% humidity
<br />
</cfoutput>
</cffunction>
</cfcomponent>
HeatIndexDisplay.cfc
<cfcomponent implements="Observer, DisplayElement" output="true">
<cffunction access="public" returntype="HeatIndexDisplay" name="init">
<cfargument required="true" type="WeatherData" name="weatherData">
<cfset VARIABLES.weatherData = ARGUMENTS.weatherData>
<cfset VARIABLES.weatherData.registerObserver(THIS)>
<cfreturn THIS>
</cffunction>
<cffunction access="public" returntype="void" name="update">
<cfargument required="true" type="numeric" name="temperature">
<cfargument required="true" type="numeric" name="humidity">
<cfargument required="true" type="numeric" name="pressure">
<cfset VARIABLES.temperature = ARGUMENTS.temperature>
<cfset VARIABLES.humidity = ARGUMENTS.humidity>
<cfset VARIABLES.heatIndex = computeHeatIndex(VARIABLES.temperature, VARIABLES.humidity)>
<cfset display()>
</cffunction>
<cffunction access="public" returntype="void" name="display">
<cfoutput>
Heat index is #VARIABLES.heatIndex#
<br />
</cfoutput>
</cffunction>
<cffunction access="private" returntype="numeric" name="computeHeatIndex">
<cfargument required="true" type="numeric" name="t">
<cfargument required="true" type="numeric" name="rh">
<cfset var LOCAL = {}>
<cfset LOCAL.index = ((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) +
(0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) +
(0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
(0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *
(rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
(0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
0.000000000843296 * (t * t * rh * rh * rh)) -
(0.0000000000481975 * (t * t * t * rh * rh * rh)))>
<cfreturn LOCAL.index>
</cffunction>
</cfcomponent>
Test Page
WeatherStation.cfm
<cfset weatherData = createObject("component", "WeatherData").init()>
<cfset currentDisplay = createObject("component", "CurrentConditionsDisplay").init(weatherData)>
<cfset heatDisplay = createObject("component", "HeatIndexDisplay").init(weatherData)>
<cfset weatherData.setMeasurements(80, 65, 30.4)>
<cfset weatherData.setMeasurements(82, 70, 29.2)>
<cfset weatherData.setMeasurements(78, 90, 29.2)>
Source Code
- Head First Observable ColdFusion Builder Project - headfirstobserver.zip