Saturday, May 23, 2009

The factory pattern using PHP

Many of the design patterns in the original Design Patterns book encourage loose coupling. To understand this concept, it's easiest to talk about a struggle that many developers go through in large systems. The problem occurs when you change one piece of code and watch as a cascade of breakage happens in other parts of the system -- parts you thought were completely unrelated.
The problem is tight coupling. Functions and classes in one part of the system rely too heavily on behaviors and structures in other functions and classes in other parts of the system. You need a set of patterns that lets these classes talk with each other, but you don't want to tie them together so heavily that they become interlocked.
In large systems, lots of code relies on a few key classes. Difficulties can arise when you need to change those classes. For example, suppose you have a User class that reads from a file. You want to change it to a different class that reads from the database, but all the code references the original class that reads from a file. This is where the factory pattern comes in handy.

The factory pattern is a class that has some methods that create objects for you. Instead of using new directly, you use the factory class to create objects. That way, if you want to change the types of objects created, you can change just the factory. All the code that uses the factory changes automatically.
Factory1.php shows an example of a factory class. The server side of the equation comes in two pieces: the database, and a set of PHP pages that let you add feeds, request the list of feeds, and get the article associated with a particular feed.

Factory1.php

<?php
interface IUser {
function getName();
}

class User implements IUser {
public function __construct( $id ) { }

public function getName() {
return "Jack";
}
}

class UserFactory {
public static function Create( $id ) {
return new User( $id );
}
}

$uo = UserFactory::Create( 1 );
echo( $uo->getName()."\n" );
?>






An interface called IUser defines what a user object should do. The implementation of IUser is called User, and a factory class called UserFactory creates IUser objects.


The factory class and its related IUser interface and user class

The factory class and its related IUser interface and user class

If you run this code on the command line using the php interpreter, you get this result:




% php factory1.php
Jack
%




The test code asks the factory for a User object and prints the result of the getName method.



A variation of the factory pattern uses factory methods. These public static methods in the class construct objects of that type. This approach is useful when creating an object of this type is nontrivial. For example, suppose you need to first create the object and then set many attributes. This version of the factory pattern encapsulates that process in a single location so that the complex initialization code isn't copied and pasted all over the code base.


Factory2.php shows an example of using factory methods.


Factory2.php



<?php
interface IUser {
function getName();
}

class User implements IUser {
public static function Load( $id ) {
return new User( $id );
}

public static function Create( ) {
return new User( null );
}

public function __construct( $id ) { }

public function getName() {
return "Jack";
}
}

$uo = User::Load( 1 );
echo( $uo->getName()."\n" );
?>




This code is much simpler. It has only one interface, IUser, and one class called User that implements the interface. The User class has two static methods that create the object.


The IUser interface and the user class with factory methods

The IUser interface and the user class with factory methods



Running the script on the command line yields the same result as the code in Listing 1, as shown here:


% php factory2.php
Jack
%


As stated, sometimes such patterns can seem like overkill in small situations. Nevertheless, it's still good to learn solid coding forms like these for use in any size of project.
source: ibm.com

Design Patterns for PHP

No comments:

Post a Comment