Design Patterns

Originally, design patterns were templates used for solving common architectural problems, but they have also been applied to computer programming. Patterns are somewhat akin to abstract classes or interfaces, but are even less specific, providing only a general description of a solution.

The Singleton Pattern

One well-known and well-documented design pattern is the singleton pattern, a pattern that ideally suits the database class you created in Chapters 9 and 10. As the name implies, this pattern is used where only one instance of a class is wanted.

Your implementation of the MySQLConnect class uses a static variable and throws an exception if there is an attempt to construct more than one instance of the class. A more conventional implementation of the singleton pattern might use a private constructor and a static method to return a class instance. Let's revise the MySQLConnect class to highlight the usefulness of static methods. (I'll outline only the major changes here; download the code if you want to see them all.)

To begin with, the static data member designed to keep track of the number of instances becomes a static data member for holding a reference to the class instance.

private static $instance = NULL;

The constructor still creates a connection, but the access modifier is changed from public to private and the test for existing instances is removed.

private function __construct($hostname, $username, $password){
    if(!$this->connection = mysql_connect($hostname, $username, $password)){
        throw new MySQLException(mysql_error(), mysql_errno());
    }
}

Because the constructor has been declared as private, you can only invoke it from within the class. This may seem like an impossibility (how do you get inside a class that you can't create?), but a static method provides the means, as shown in Listing 11-4.

Listing 11-4. Static method for returning an instance
static public function getInstance($hostname, $username, $password){
    //instance must be static in order to be referenced here
    if(self❶::$instance == NULL ){
         self::$instance = new MySQLConnect❷($hostname, $username, $password);
        return self::$instance;
    }else{
        $msg = "Close the existing instance of the ".
            "MySQLConnect class.";
        throw new MySQLException($msg, self::ONLY_ONE_INSTANCE_ALLOWED);
    }
}

In order to reference ❶ the instance handle inside a static method, the handle itself must be static. If no instance exists, the constructor ❷ is called and the returned object is copied into the static class variable $instance. The getInstance method then returns a reference to this static data member.

Now, instead of directly creating an instance of the MySQLConnect class by calling the constructor, you invoke the static getInstance method to perform that task for you.

$instance = MySQLConnect::getInstance('localhost', 'user', 'password'),

It was noted earlier that static methods can only reference static data members. Conversely, static methods are prohibited from referencing regular data members. This makes sense when you remember that regular data members belong to and are created when objects are instantiated. By definition a static method does not require an object, so those non-static data members don't exist. Likewise, as you saw earlier, a static method cannot use the pseudo-variable $this, since $this refers to the current instance.


Note:

A singleton class should also disallow clones. You'll see how this is done in Chapter 13.


Which Implementation?

This revised MySQLConnect class has exactly the same functionality as the original. Apart from the way an instance is created, there is no other change to the interface of the MySQLConnect class. However, having a copy of the lone instance stored in a static class variable allows you to return that instance instead of throwing an exception, should an attempt be made to create a second instance. This is exactly what some implementations of a singleton database class do, but it is not always the desired behavior. What if the user wants to connect to a different server? For this reason, in the section "Making Other Connections" on page 68, we chose to force the user to close the current connection before creating a new one.

The coding style of the original implementation may be more direct and more readily understood, but having a reference to the class instance could prove useful in some circumstances. If the getInstance method receives a request to connect to the same host with the same username, why not return the current instance rather than throwing an exception?

Which version is preferable? It's up to you to decide.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.85.33