Applied design patterns: Database abstraction (part 2)
June 9, 2008 – 8:21 pmIn some of my previous posts, I’ve pretty much ranted about the poor design qualities of some people that enjoy calling themselves PHP programmers. In these two posts however, I’d like to show you what good and proper design is. The topic is the same as that in my previous posts: databases. Or, to be more precise, database abstraction.
In the first part, transformed a concrete set of database interaction classes into an abstract set, to improve flexibility and extensibility. In the second part (i.e. this one), we’ll introduce a design pattern which will help us to manage and maintain the new abstract database classes and their concrete implementations. In this post, we’ll create and implement the design pattern we’ll use to determine which concrete database connection should be used, using an implementation of the Factory Method.
In the first part, we encountered the following line in the example code:
$databaseConnection = new MySQLDatabaseConnection($server, $username, $password);
This, in itself, will work, but it’s not what we want. If we used this line in every bit of code where we require a database connection, our application would become dependent on the MySQLDatabaseConnection class. Not only that, but it’ll become rigid, inflexible, and a general pain in the arse to maintain. You might consider that in most cases your application will stick to a single database, but what if you’re writing an application for clients that may want to use a different database? Do you just lock them out saying ‘No we don’t support ‘? Not only that, but learning this method now (and not even particularly for this situation) will give you a benefit in the future, when you encounter similar problems. Anyways, back to the tutorial.
In order to solve the above case of inflexibility, we’ll want to move the concrete object instantiation (= object creation) to a single location. We’ll want to be able to create an object that can produce new instances of the objects required to work with a database of a specific type, and pass that object around to the bits of code that need it. The $databaseConnection in the above example will, as such, be instantiated not by calling the new operator on a specific database connection type, but by calling a method on an object that’s assigned to the part of the program using databases which will return an instance of the database connection type currently in use. The former sentence is complex, but I hope it’ll make sense in a short while. Read on.
To do the above, we have to create ourselves a Factory Method. The name “Factory Method” refers to a Design Pattern, an element of reusable object-oriented software as described in The book on Design Patterns, and probably in a load of other books as well. This method (or function, whatever floats your boat) will return an instance of the DatabaseConnection currently used in your application.
Next to a method that creates / returns a DatabaseConnection, we’ll also want to support connection re-use: in most applications, people only want a single database connection at a time for the duration of a request, so we’ll want to make the behavior of the factory as such that it’ll only create a new instance of a Connection if it isn’t already there. This only-one-object-of-a-certain-type-at-a-time business can be achieved by using the Singleton pattern (albeit slightly different from the one described in The Book, but that difference isn’t important).
In our Factory, we’ll also want to keep track of all existing connections, so we’ll have to maintain a list of active database connections and the means to manage them.
We’ll create a new interface for this, the ConnectionManager. The ConnectionManager is in essence a pretty basic class, in that it contains only one field (an array that contains the currently active connections) and a handful of connection management methods - one for establishing a connection, one for closing a connection, one for getting a connection from the list of connections, and one for creating a new connection. We’ll want the ConnectionManager to create new Connections based on whichever type of database is currently selected. To do this, we’ll create one ConnectionManager for each type of database, so that a MySQLConnectionManager returns MySQLConnections, and a PostgreSQLConnectionManager returns PostgreSQLConnections.
There is one thing that’s shared in all ConnectionManagers by the way, and that’s that they all contain a list of database connections. We’ll take advantage of PHP’s typelessness by defining the location of those connections in the abstract ConnectionManager. We’ll add actual functionality to the otherwise abstract ConnectionManager, which means it’s not an official Interface anymore - it’s become an Abstract Class, which means that it implements some methods, while leaving the implementation of other methods to subclasses. Here’s our ConnectionManager:
abstract class ConnectionManager
{
private $connections = array();
const DEFAULT_NAME = 'Default';
// retrieves a Connection from the local connection storage.
public function GetConnection($name = ConnectionManager::DEFAULT_NAME)
{
return $this->connections[$name];
}
// Adds a new connection under the given $name into the connection storage.
// We don’t want external parties (outside of subclasses) to add connections
// to the storage, so we declare it as protected.
protected function AddConnection($connection, $name)
{
$this->connections[$name] = $connection;
}
// Close the connection specified by the name (if it exists).
public function CloseConnection($name = ConnectionManager::DEFAULT_NAME)
{
if ($this->connections[$name] != null)
{
$this->connections[$name]->Close();
$this->connections[$name] = null;
}
}
// This method has to be implemented by our subclasses.
public abstract function CreateConnection($host, $username, $password, $name = ConnectionManager::DEFAULT_NAME);
}
It defines logic for adding and getting Connections, which is independent of actual database implementations, and leaves the logic for creating and closing Connections open for subclasses to implement. We’ve used a class constant to define the default name for connections, which looks pretty ew in code, but provides a centralized location to store the default name, so you’ll only have to change it once. Not that it matters in terms of functionality, but eh.
We’ll define a MySQLConnectionManager as follows:
class MySQLConnectionManager extends ConnectionManager
{
// Creates a new MySQLDatabaseConnection and inserts it into the ConnectionList.
// This method has to be called first before the GetConnection method can be called.
public function CreateConnection($host, $username, $password, $name = ConnectionManager::DEFAULT_NAME)
{
$connection = new MySQLDatabaseConnection($host, $username, $password);
$this->AddConnection($connection, $name);
}
}
When a user calls CreateConnection() on an instance of ConnectionManager (or, to be more precisely, on an object reference (variable) that references an object that extends ConnectionManager), the CreateConnection method will return a DatabaseConnection of the type matching the currently active ConnectionManager. To clarify, here’s a usage example:
$manager = new MySQLConnectionManager();
$manager->CreateConnection('localhost', 'root', '');
$connection = $manager->GetConnection();
$manager = new PostgreSQLConnectionManager();
$manager->CreateConnection('localhost', 'root', '');
$connection = $manager->GetConnection();
Looks easy enough. Also looks like we’ve simply moved the same problem we’ve had before instead of actually solving it. But no, we’ll assign the $manager somewhere in the initializing stage of the program, and pass it around to anything that needs a connection. The piece of code that requires a connection then simply calls $manager->GetConnection() and gets a connection to a database. Notice how I’ve used the word ‘a’? The code that requires no longer requires a connection to a MySQL database, but just ‘a’ reference to ‘a’ database connection, to which it can pass ’some’ kind of query. Consider the following example as well:
$random = rand(0, 2);
$manager;
switch($random)
{
case 0: $manager = new MySQLConnectionManager(); break;
case 1: $manager = new PostgreSQLConnectionManager(); break;
case 2: $manager = new SQLiteConnectionManager(); break;
}
$manager->CreateConnection('localhost', 'root', '');
$connection = $manager->GetConnection();
What this does is create a random connection manager (and, as a result, a random connection). Yet the access methods remain the same, no matter which ConnectionManager is eventually used. Of course, whether the above will work or not is still the question (it won’t work over here, since I don’t have Postgres or SQLite installed, let alone wrote an actual PostgreSQLConnectionManager etc), but that’s not really the point. The point is that, with this construction, you can program your application to a single type - the DatabaseConnection type - without having to worry about the eventual implementation of that one. All you care about is that you get a connection when calling GetConnection(), and that your query gets executed when you call Execute on the resulting connection. And that is abstraction. Less headache, more flexibility, and great justice.
For your entertainment, here’s a UML diagram (or well, it’ll look like that) that depicts the Factory Method as used in this example (made non-specific to this application btw). In it, you see the abstract factory (ConnectionManager) (defined as an interface in this case, since we’ve added the member access functions as an application-specific extra in the example - you probably won’t need it or have different requirements in other applications of this design pattern), the concrete factory (MySQLConnectionManager) that returns a concrete Product object (MySQLDatabaseConnection), which in turn inherits from a Product interface. The image uses the Factory Method in a slightly different manner from how we’ve used it here. In the image, the abstract Factory (our ConnectionManager) has a method that calls the FactoryMethod (CreateConnection / GetConnection) for use of its own. The implementation of FactoryMethod goes to a subclass. So in the image, the Factory gets a Product that gets produced by an implementing class. In fact, now that I see that image, we could’ve used the same method in our own ConnectionManager. We could’ve implemented the ConnectionManager’s CreateConnection method so it would call a differently named method that gets implemented by a subclass, which would return an instance-specific Connection.
In the basics though, the two methods are interchangeable and, functionally seeing, do the exact same. But hey, it’s good to see there’s still some flexibility in design patterns.
In these two posts, you’ve learned at least one important rule: Program to interfaces, not to concrete implementations. This might be difficult and probably obsolete and unnecessary in a lot of cases (i.e. don’t do it unless you want some flexibility), but it’ll pay off in terms of flexibility, extensibility and maintainability.









9 Responses to “Applied design patterns: Database abstraction (part 2)”
Hi,
sorry for my poor english ,
i have a question.
In my implementation of this pattern,
i have a set of utility function .. for many job,
one example is cleanup string, or execute defaul query
ok?
right , where i insert this api ??
in the factory class, or in a single driver class ?
Can i extend driver class to basedriver class with common utils method ?
Tnx for your reply
bye
ps: Good article
great job 
By Marco on Aug 18, 2008
Hrm, cleaning up is a pretty non-database specific action, so I’d say you put that in a new class, outside of this particular structure. You could also choose to insert it into the driver or, probably more logically, the query class, since it’s the query that eventually has to be escaped.
By admin on Aug 18, 2008
Tnx for your reply,
but i have a little dubt
You talk about query class .. .
how to implements this ? i need to write another class completly indipendent to this layer ?
One most specified example is my function to build and prepare query … for your point of view where is right place to insert this function ?
Tnx !!
By Marco on Aug 18, 2008
Great Post. What would you suggest if I had a custom Session class that needed a db connection inside of it? Would I just pass the connection in when the Session object instantiated or I am missing something fundamental here?
By Chris on Oct 30, 2008
Sounds to me that your Session class can be seen as a regular bit of data, so it’s basically a Model in the MVC scheme, which makes it all right to give it a database connection (object). There’s an alternative approach which, in my opinion, keeps your Session object cleaner, and that’s to use a database access object (DAO) for Sessions, which is basically a class / object you use to retrieve and insert Sessions into your database, instead of leaving that responsibility with the Session object itself.
By admin on Oct 30, 2008
Thanks for the uber quick reply on an old post. I like the idea of DAO, but I guess what I was shooting for was a way to manage connections to multiple databases with the ability to get access to those connections within other classes without having to pass arguments when instantiating the object. I thought about the singleton pattern, but since I will need to connection to different db’s that wouldn’t really work. Is there a way to do what I’m asking? If not (or it doesn’t make sense), I will surely take your advice.
By Chris on Oct 30, 2008
There’s currently plenty of people that vote against the singleton design pattern, calling it a remnant of ye olde imperative programming and, from a practical point of view, it doesn’t really apply to database connection thingies - after all, multiple connections to a database are perfectly allowed and whatnot.
For your problem, you could, I guess, write a database connection manager, which basically keeps track of a list of your database connections, so yeah, it’s perfectly valid. I’m not entirely sure what motivation people have when they apply the singleton pattern to database connections - it’s firstly not applicable to database connections, and second, it seems to me like a complex way to make it a global thing.
As for the quick reply, I get an e-mail whenever someone posts a comment, so I can be pretty quick, =D.
By admin on Oct 30, 2008
I think I am just overdoing it a bit. Since connections can be reused I might just decide to have a class connect to the db and do its thing.
Who knows.
You’re right, It seems the singleton is going the way of the dodo. I have used in logging classes before, though.
By Chris on Oct 31, 2008