« September 2005 | Inicio | November 2005 »

October 18, 2005

And the pattern was...

Strategy. That was the name of the pattern in yesterday's post.

October 17, 2005

An example of the guess-its-name pattern

UPDATED: This is the Strategy Pattern. So, the title of the post could be "An example of the strategy pattern in actionscript"

Professor Coupling has been enjoying his well deserved hollidays after conquering the world (yes, since the last time we knew about him he seems to have succeeded with his evil plan).

But ruling the world is quite boring. Professor Coupling misses the old times, when nobody understood him, when he could hate all the world's leaders because they ignored him... Now he has to deal with a lot of paperwork everyday, and he misses when he could hang around with his troops, telling jokes, and drinking beer.

So, he has decided that, to combat this mortal boredom, he wants to see a millitary parade everyday. A different parade everyday, formed by a different selection from his troops. One day he will ask his Marshal to form a parade with the cows from the company B, another day he will want a parade formed by all the sheeps whose name contains an "a"... Evil geniuses...

Professor Coupling troops are well trained. They know that, when asked for their names all they can say is their name, company, and serial number. Nothing more. So think of a solider as something like this:

class Soldier { private var name : String; private var id : String; private var company : String; private var weapons : Object; function Soldier( initInfo: Object ) { this.name = initInfo.name; this.id = initInfo.id; this.company= initInfo.company; } public function getPublicInfo( ) { return { name: this.name, id: this.id, company: this.company }; } //Other methods public function toString( ): String { return "soldier{ name: " + this.name + ", id: " + this.id + ", company: " + this.company + " }"; } }

What defines a soldier is its name, its company, and its serial number (id), and that is the info they will provide when asked.

So, imagine that professor coupling asks his Marshal to prepare a parade with all the soldiers from company B. The Marshal, whose responsibility is to build and maintain an army, will have to go asking all his soldiers for their company, and select only those that serve in the company B. But now, imagine that Professor Coupling wants a parade formed by all the soldiers whose name contains a "P". The Marshal will have to loop through all his soldiers, and select only those whose name contains a "P". So, the Marshal code will be something like this:

class Marshal { public static var CONTAINS_LETTER: String = "Letter"; public static var COMPANY : String = "Company"; private var soldiersList: Array; function Marshal( ) { this.soldiersList = new Array( ); } public function recruitSoldier( newSoldier: Soldier ) { this.soldiersList.push( newSoldier ); } public function getFilteredCollection( filterType: String, filterValue: String ): Array { var returnVal: Array = new Array( ); var numSoldiers: Number = this.soldiersList.length; var actualSoldierInfo: Object; for( var k: Number = 0; k< numSoldiers; k++ ) { actualSoldierInfo = this.soldiersList[ k ].getPublicInfo( ); switch( filterType ) { case Marshal.CONTAINS_LETTER: if( actualSoldierInfo.name.indexOf( filterValue ) != -1 ) { returnVal.push( this.soldiersList[ k ] ); } break; case Marshal.COMPANY: if( actualSoldierInfo.company == filterValue ) { returnVal.push( this.soldiersList[ k ] ); } break; default: trace( "Filter not created" ); } } return returnVal; } }

So Professor Coupling will do something like:

class Professor { function Professor( ) { } public static function initApp( ) { var professor : Professor = new Professor( ); var marshal : Marshal = new Marshal( ); marshal.recruitSoldier( new Soldier( { name: "Peter", id: "0001", company: "B" } ) ); marshal.recruitSoldier( new Soldier( { name: "Paul", id: "0002", company: "B" } ) ); marshal.recruitSoldier( new Soldier( { name: "Cesar", id: "0003", company: "A" } ) ); marshal.recruitSoldier( new Soldier( { name: "Javier", id: "0004", company: "B" } ) ); var companyB: Array = marshal.getFilteredCollection( Marshal.COMPANY, "B" ); trace( companyB ); var companyA: Array = marshal.getFilteredCollection( Marshal.COMPANY, "A" ); trace( companyA ); var nameWithP: Array = marshal.getFilteredCollection( Marshal.CONTAINS_LETTER, "P" ); trace( nameWithP ); var nameWithe: Array = marshal.getFilteredCollection( Marshal.CONTAINS_LETTER, "e" ); trace( nameWithe ); } }

But what happens if now, Professor Coupling wants a parade formed with the soldiers whose id is lower than a given number. The code of the Marshal class will have to be changed. And what if now, Professor Coupling wants... (you, know, this always happens with evil geniuses, they always want more...). The code of the Marshal class can not be easily scaled. It is not easy to add new filtering conditions. But there is also another problem. With every iteration of the loop, all the possible conditions have to be checked, which is, to say the least, not too elegant. And Professor Coupling can be crazy, but he is not an idiot, and he wants his code to be clean, easy to maintain, and elegant. So, he remembers (insert thunders, laughs, and melodramatic music here, please) when he was a student, and he learnt about the (sorry, naming it is up to you) pattern.

If he finds the way to give his Marshal a package containing the condition to check, in a way that the Marshal doesn't need to know what he is checking, the problem will be solved. The Marshal should delegate the condition checking in what Professor Coupling gives him, and new conditions could be added without changing the Marshal code. Let's see how.

Professor Coupling will, then, give the Marshal a class that will be responsible for checking the filtering condition. But there can be many conditions, so all of them should have a common interface, so the Marshal could interact with them in an anonymous way.

This interface could be:

interface ICompare { public function matches( checkValues: Object ): Boolean; }

So, one condition could be:

class NameContainsLetterFilter implements ICompare { private var refValue: String; function NameContainsLetterFilter( ref: String ) { this.refValue = ref; } public function matches( checkValues: Object ): Boolean { return ( checkValues.name.indexOf( this.refValue ) != -1 ); } }

And the Marshal code will be:

class Marshal { private var soldiersList: Array; function Marshal( ) { this.soldiersList = new Array( ); } public function recruitSoldier( newSoldier: Soldier ) { this.soldiersList.push( newSoldier ); } public function getFilteredCollection( filter: ICompare ): Array { var returnVal: Array = new Array( ); var numSoldiers: Number = this.soldiersList.length; var actualSoldierInfo: Object; for( var k: Number = 0; k< numSoldiers; k++ ) { actualSoldierInfo = this.soldiersList[ k ].getPublicInfo( ); if( filter.matches( actualSoldierInfo ) ) { returnVal.push( this.soldiersList[ k ] ); } } return returnVal; } }

And Professor Coupling will do something like:

class Professor { function Professor( ) { } public static function initApp( ) { var professor : Professor = new Professor( ); var marshal : Marshal = new Marshal( ); marshal.recruitSoldier( new Soldier( { name: "Peter", id: "0001", company: "B" } ) ); marshal.recruitSoldier( new Soldier( { name: "Paul", id: "0002", company: "B" } ) ); marshal.recruitSoldier( new Soldier( { name: "Cesar", id: "0003", company: "A" } ) ); marshal.recruitSoldier( new Soldier( { name: "Javier", id: "0004", company: "B" } ) ); var nameWithP: Array = marshal.getFilteredCollection( new NameContainsLetterFilter( "P" ) ); trace( nameWithP ); var nameWithe: Array = marshal.getFilteredCollection( new NameContainsLetterFilter( "e" ) ); trace( nameWithe ); } }

Adding new filters will be easy. To add a filter by the name of the company, Professor Coupling will have to encapsulate it in a class:

class CompanyFilter implements ICompare { var refValue: String; public function CompanyFilter( ref: String ) { this.refValue = ref; } public function matches( checkValues: Object ): Boolean { return ( checkValues.company == this.refValue ); } }

Another filter:

class IDLowerFilter implements ICompare { private var refValue: String function IDLowerFilter( ref: String ) { this.refValue = ref; } public function matches( checkValues: Object ): Boolean { var ref : Number = parseInt( this.refValue, 10 ); var check : Number = parseInt( checkValues.id, 10 ); return ( check<= ref ); } }

So, to use those filters:

class Professor { function Professor( ) { } public static function initApp( ) { var professor : Professor = new Professor( ); var marshal : Marshal = new Marshal( ); marshal.recruitSoldier( new Soldier( { name: "Peter", id: "0001", company: "B" } ) ); marshal.recruitSoldier( new Soldier( { name: "Paul", id: "0002", company: "B" } ) ); marshal.recruitSoldier( new Soldier( { name: "Cesar", id: "0003", company: "A" } ) ); marshal.recruitSoldier( new Soldier( { name: "Javier", id: "0004", company: "B" } ) ); var nameWithP: Array = marshal.getFilteredCollection( new NameContainsLetterFilter( "P" ) ); trace( nameWithP ); var nameWithe: Array = marshal.getFilteredCollection( new NameContainsLetterFilter( "e" ) ); trace( nameWithe ); var companyB: Array = marshal.getFilteredCollection( new CompanyFilter( "B" ) ); trace( companyB ); var companyA: Array = marshal.getFilteredCollection( new CompanyFilter( "A" ) ); trace( companyA ); var idLessThan2: Array = marshal.getFilteredCollection( new IDLowerFilter( "0002" ) ); trace( idLessThan2 ); var idLessThan3: Array = marshal.getFilteredCollection( new IDLowerFilter( "0003" ) ); trace( idLessThan3 ); } }

So, Professor Coupling has been able to change the filters without changin the Marshal code. Now, some considerations. All the filters implement the same interface. You could say "Well, why don't they just extend a base class?". Sure, they could, but imagine that the reference value is a Number instead of a String, or that there are two reference values in a given filter, or... That's why they just implement an interface (altough in this example it will be valid to make them extend a base class).

Then, what has Professor Coupling done?. First, he has followed the open-closed principle. The Marshal is open for extensions but closed for modifications. That means that his functionality can be extended without changing its code.

Second, he has delegated the construction of the filters in an entity different to the one that executes them. So the creation of those filters is totally decoupled.

But, the pattern can be improved. A filter could be created composing it from two or more existing filters, for instance. But that will be another Professor Coupling adventure...

Now, it's time for you to guess the name of the pattern... *hint* Professor Coupling has decoupled an algorithm from its host, encapsulating it in a separate class.

Download the source code. (if you wish, of course)

October 16, 2005

[Cocoa] Some links

In the last weeks there have been some interesting posts about Cocoa. In Theobroma Cacao, Scott Stevenson has posted two articles about key-value coding:

In Mac Geekery, codepoet has posted two tutorials about Core Data:

October 09, 2005

[Cocoa] Introduction to memory management

Informit published an article a few days ago about memory management in Cocoa, called A Java Programmer's Introduction to Objective-C: Memory Management.

The article focuses on the differences between Java and Cocoa regarding memory management, and it can be useful as an introduction to the most important, powerful and complex aspect of Objective-C, which is the lack of a garbage collector.

A Java Programmer's Introduction to Objective-C: Memory Management