Thursday, 18 February 2010

ColdFusion Head First Design Patterns: Strategy

Following on from my previous post on a ColdFusion implementation of the Head First Design Patterns web MVC Pattern is a ColdFusion implementation of the Strategy Pattern.

The Strategy Pattern is probably the most useful pattern, to quote the Head First book:

"The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it."

Abstract Duck

Duck.cfc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<cfcomponent output="true">
 
  <cffunction access="public" returntype="void" name="display">   
  </cffunction>
   
  <cffunction access="public" returntype="void" name="performFly">
    <cfset VARIABLES.flyBehaviour.fly()>   
  </cffunction>
   
  <cffunction access="public" returntype="void" name="performQuack">
    <cfset VARIABLES.quackBehaviour.quack()>   
  </cffunction>
 
  <cffunction access="public" returntype="void" name="swim">
    <cfoutput>All ducks float, even decoys!<br/></cfoutput>   
  </cffunction>
 
  <cffunction access="public" returntype="void" name="setFlyBehaviour">
    <cfargument required="true" type="FlyBehaviour" name="flyBehaviour">
    <cfset VARIABLES.flyBehaviour = ARGUMENTS.flyBehaviour>
  </cffunction>
 
  <cffunction access="public" returntype="void" name="setQuackBehaviour">
    <cfargument required="true" type="QuackBehaviour" name="quackBehaviour">
    <cfset VARIABLES.quackBehaviour = ARGUMENTS.quackBehaviour>
  </cffunction>
     
</cfcomponent>

Quack Strategies

Quack.cfc

1
2
3
4
5
6
7
8
9
10
11
<cfcomponent implements="QuackBehaviour" output="true">
 
  <cffunction access="public" returntype="Quack" name="init">
    <cfreturn THIS>
  </cffunction>
 
  <cffunction access="public" returntype="void" name="quack">
    <cfoutput>Quack<br/></cfoutput
  </cffunction>
   
</cfcomponent>

Fly Strategies

FlyWithWings.cfc

1
2
3
4
5
6
7
8
9
10
11
<cfcomponent implements="FlyBehaviour" output="true">
   
  <cffunction access="public" returntype="FlyWithWings" name="init">
    <cfreturn THIS>
  </cffunction>  
   
  <cffunction access="public" returntype="void" name="fly">
    <cfoutput>I'm flying!<br/></cfoutput>
  </cffunction>
   
</cfcomponent>

FlyNoWay.cfc

1
2
3
4
5
6
7
8
9
10
11
<cfcomponent implements="FlyBehaviour" output="true">
   
  <cffunction access="public" returntype="FlyNoWay" name="init">
    <cfreturn THIS>
  </cffunction>
   
  <cffunction access="public" returntype="void" name="fly">
    <cfoutput>I can't fly<br/></cfoutput>
  </cffunction>
   
</cfcomponent>

FlyRocketPowered.cfc

1
2
3
4
5
6
7
8
9
10
11
<cfcomponent implements="FlyBehaviour" output="true">
   
  <cffunction access="public" returntype="FlyRocketPowered" name="init">
    <cfreturn THIS>
  </cffunction
   
  <cffunction access="public" returntype="void" name="fly">
    <cfoutput>I'm flying with a rocket!<br/></cfoutput>
  </cffunction>
   
</cfcomponent>

Duck Implementations

MallardDuck.cfc

1
2
3
4
5
6
7
8
9
10
11
12
13
<cfcomponent extends="Duck" output="true">
 
  <cffunction access="public" returntype="MallardDuck" name="init">
    <cfset VARIABLES.flyBehaviour = createObject("component", "FlyWithWings").init()>
    <cfset VARIABLES.quackBehaviour = createObject("component", "Quack").init()>
    <cfreturn THIS>
  </cffunction>
   
  <cffunction access="public" returntype="void" name="display">
    <cfoutput>I'm a real Mallard duck<br/></cfoutput>
  </cffunction>
    
</cfcomponent>

ModelDuck.cfc

1
2
3
4
5
6
7
8
9
10
11
12
13
<cfcomponent extends="Duck" output="true">
 
  <cffunction access="public" returntype="ModelDuck" name="init">
    <cfset VARIABLES.flyBehaviour = createObject("component", "FlyNoWay").init()>
    <cfset VARIABLES.quackBehaviour = createObject("component", "Quack").init()>
    <cfreturn THIS>
  </cffunction>
   
  <cffunction access="public" returntype="void" name="display">
    <cfoutput>I'm a model duck<br/></cfoutput>
  </cffunction>
    
</cfcomponent>

Test Page

MiniDuckSimulator.cfm

1
2
3
4
5
6
7
8
<cfset mallard = createObject("component", "MallardDuck").init()>
<cfset mallard.performQuack()>
<cfset mallard.performFly()>
 
<cfset model = createObject("component", "ModelDuck").init()>
<cfset model.performFly()>
<cfset model.setFlyBehaviour(createObject("component", "FlyRocketPowered").init())>
<cfset model.performFly()>

Source Code