Monday, February 4, 2008

[Design Patterns, OOP, PHP] Design Patterns you use without knowing them

In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design.

Wikipedia


Rise your hands if time ago (or even now) you stood litteraly in trance listening to your friends or colleagues talking about design patterns. . .I thought "Oh my God? Design what??", and I learned I was not the best incredibly skilled new born super ultra young mega nerd programmer in the world!
Anyway I felt better (and also my ego did) when I found those Design Patterns were no more than ways to solve common programming problems, and as I was programming since 2 or 3 years, I had already discovered some of them myself.
One of those was the strategy pattern. Imagine you have a class that connects to a storage layer (it could be a database or even another kind of diabolic machinery). At first you decide to use MySQL, as it is free and easy to use (escpecially with PHP). Unfortunately your first customer decides to use e.g. Ms-SQL Server: what a mess! Different libraries and methods...but as you have a bit of experience, gained by re-writing time after time your own libraries as each time you forget a method or parameter or a class, you know the great use of interfaces and you luckily used them with your SuperCoolMySQLClass. Now what you have to do is writing a MegaMSSQLServerClass, that will implement the SuperDataBaseInterface, and what you'll have to modify is just the row in which you create the instance of the class.

As for an example I used PHP, that is never used to make such examples, but actually you are allowed to use whatever OOP language you want.


<?php
/* common interface */
interface SuperDataBaseInterface{
public function connect($username,
$password,$host,$dbName);
. . .
}
/* MySQL DB connection class */
class SuperCoolMySQLClass implements SuperDataBaseInterface{
public function connect($username,
$password,$host,$dbName){
mysql_connect($host,$username,$password)
or die("Error!");
. . .
}
. . .
}

/* MS SQL Server connection class */
class MegaMSSQLServerClass implements SuperDataBaseInterface{
public function connect($username,
$password,$host,$dbName){
mssql_connect($host,$username,$password)
or die("Error!");
. . .
}
. . .
}

/* use of the code */
//$db = new SuperCoolMySQLClass();
$db = new MegaMSSQLServerClass();
$db->connect("localhost","user","password");
. . .

?>


Actually che procedural style code upon this paragraph should be replaces by a Context class that whould have a constructor that receives the desired DB class, and allows a wrapper method that recalls che connect() method and all other methods to access the SuperDataBaseInterface interface (few times I used to write down this class, but even without it, the pattern doesn't loose its sense).

It seems good, but I found in this way you are breaking the Open-Close Principle (OCP) that states that:
software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

that is to say your application code should not be modified if a change in its behavior is required...indeed no one pretends that you could not modify a class after having implemented it but, after software analysis, if you find that, as in our case, your application can run over different database layers, it's a good practice to state which one to use in a global variable or a configuration file. In this way itwill feed a factory class that is a class that, given an input (e.g. a codified string / integer), returns you a SuperDataBaseInterface object, so without changing any row of code.


class DBFactoryClass{

const MySQL_DB = 0;
const MSSQL_DB = 1;

public static function create($classId)
{
switch ($classId){
case self::MySQL_DB:
return new SuperCoolMySQLClass();
case self::MSSQL_DB:
return new MegaMSSQLServerClass();
/* add here future classes */
default:
return new SuperCoolMySQLClass();
}
}
}

. . .
$db = DBFactoryClass::create(DBFactoryClass::MySQL_DB);
$db->connect("localhost","user","password");
. . .


This is the factory pattern: if you find other ways to implement an algorithm, you can add a new class that implements the common interface, add another "switch" statement in your factory class thus choosing your brand new functional class: more over using a factory class, if can also handle bad class identifier, in the case that for example if you implement some functionalities and a further programmer pretends to use another one that is not in the allowed list, you can handle it by using a default method.
As far as my knowledge goes, I don't know which other design patterns I usually use, and if you have more examples I'm glad to write down a "Design Patterns you use without knowing them Pt.2".

3 comments:

Anonymous said...

I have read an interesting post on 10 design patters for PHP

http://www.hurricanesoftwares.com/ten-php-design-patterns/

Jeamy said...

I read this blog in half.Then i thought finally i got a nice blog in Php information..Actually i am getting training in web designing now that 's why i need this type of information so thanks for sharing with us..

pegasys said...

I have gone through your article and would like to write a similar blog concerning this topic, you beat me to it. You did a nice job! Thanks and well add your rss to come categories on our blogs. Thanks so much, Jon B.
web development