Friday, May 9, 2008

design patterns - A walk through

I may be a little redundant here, but it really helps me to write it down, and if im blogging here, i am forced to think and articulate a little more critically.

This week, I am walking through a sample application provided by the good folks at cfobjective. I have my eye on the familiar data patterns and how they are implemented in a typical CF application. The application is not using a model manager like ColdSpring or LiveWire, nor is it using a application framework like machII, fusebox or coldbox. You could say its a little more clean this away and allows you to focus on the design of the objects (beans) and its interactions with its service, the application and model layer.

The application is following the MVC pattern and is using a service layer to interact with the DAO and Gateway and a facade to encapsulate the session scope.

The application.cfm file is creating the service object and other app. level setup work. The creation of the service object in the application scope allows it to be avail and used for the creation of a value or bean object and subsequent writes to the persistence layer via the DAO and Gateway.

The init() method of the service object is returning a reference to itself after it creates objects for both its DAO and Gateway. This is a case of the service object having state and knowing about other objects. If there was a model management tool, it would be responsible for keeping the state or dependencies, also referred to as CFC wiring.

The service contains all the methods to both the DAO and the Gateway. The service also contains the method to create a new value bean, which returns an instance of itself. In other words, the service is not only responsible for speaking to the data layer, but also for creating instances of the value beans that it is servicing.

If you need to create a value bean then find its service and call its public method that returns an instantiation of the bean. You are not returning just data like a string or a query, but the entire object, including the methods that are avail. in it. If you need to reference or update part of that value bean, then use its avail. getter or setter methods. This is clean object notation and usage.

For example, lets say we are dealing with a person bean or object.
A user has supplied details via a webform, those details have passed the submission filters and a new person object has been created and its attributes updated via bean setters.

cfset variables.person = CreateObject("component", "Person").init()
cfset variables.person.setFirstName(form.firstName)
cfset variables.person.setLastName(form.lastName)
cfset variables.person.setAge(form.age)


Next, call a addNewPerson function in the service, passing in the object reference and do a little error checking prior to calling the DAO function;

cfset variables.errors = application.personService.addNewPerson(variables.person)

If no errors result, call the addNewPerson function and require the object be supplied.

cffunction name="addNewPerson"...
cfargument name="person" type="Person" required="true" ...

If everything is in order, call the createPerson function, passing in the object reference, which will call the related DAO function.

cffunction name="createPerson" access="public"...
cfargument name="person" type="Person" required="true"
cfreturn variables.dao.create(arguments.Person)

In the create function of the DAO, require the person object be passed in and insert the record using the getter method for the person to get the actual value to write into the table.

cfargument name="Person" type="Person" required="true"

cfqueryparam value="#arguments.Person.getFirstName()#
cfqueryparam value="#arguments.Person.getLastName()#

This is a change of thinking for me, not easy, since i have treated CF in a procedural manner, where i am simply passing in args by value, not by object reference. I am trying to get my head around the benefit, which is trying hard to hide itself behind the added complexity, maybe its not really more complex, im just conditioned to think the other way and so think it more complex.

No comments: