Software Design Patterns (2) four commonly used design patterns using php (singleton, factory, adapter & decorator)
the singleton pattern (1) o when only one object needs to be responsible for a particular task. o exclusive resource with only one type of this resource. o most commonly used in PHP to limit connections to the database throughout the codebase. o singleton pattern considered a responsibility pattern because it delegates control for creation to a single point. o All singleton patterns have at least three common elements: - they must have a constructor, and it must be marked private - they contain a static member variable that will hold an instance of the class - they contain a public static method to access the instance
basic form: class Singleton { private static $instance = null; private static function __construct() { } public static function getInstance() { if(empty(self::$instance) { self::$instance = new Singleton(); } return self::$instance; } the singleton pattern (2)
the singleton pattern (3) class Database { private $_db; static $_instance; private function __construct() { $this->_db = mysql_connect('localhost', 'root', ''); mysql_select_db('phobias'); } private function __clone() {} public static function getInstance() { if(!(self::$_instance instanceof self)) { self::$_instance = new self(); } return self::$_instance; } public function query($sql) { return mysql_query($sql, $this->_db); }
$db = Database::getInstance(); $result = $db->query("SELECT * FROM phobias WHERE def LIKE '%pain%'"); while ($row = mysql_fetch_assoc($result)) { echo $row["term"].' : '. $row["def"].' '; } test singleton: run testview code the singleton pattern (4)
the factory pattern (1) o the factory pattern is a class that creates objects. o a factory is typically used to return different classes that conform to a similar interface. o usually, a factory pattern has one key ingredient: a static method, which is by convention named “factory”. o the static method may take any number of arguments and must return an object. o factories are critically important to the practice of polymorphic programming.
the factory pattern (2) basic form: class Driver { # The parameterized factory method public static function factory($type) { if (include_once 'Drivers/'. $type. '.php') { $classname = 'Driver_'. $type; return new $classname; } else { throw new Exception('Driver not found'); } # Load a MySQL Driver $mysql = Driver::factory('MySQL'); # Load an SQLite Driver $sqlite = Driver::factory('SQLite');
the factory pattern (3) interface DB { public function connect(); public function query(); public function disconnect(); } class DBmysql implements DB { public function connect() { //database connection stuff } public function query() { //perform database query stuff } public function disconnect() { //disconnect database } } class DBoracle implements DB { public function connect() { //database connection stuff } public function query() { //perform database query stuff } public function disconnect() { //disconnect database } }
the factory pattern (4) class DBfactory { public static $_DB; public static function &factory($szType = "") { if(!is_object(self::$_DB)) { switch($szType) { case 'mysql': self::$_DB = new DBmysql; break; case ‘oracle': self::$_DB = new DBoracle; break; default: self::$_DB = new DBmysql; break; } return self::$_DB; }
the factory pattern (5) db = DBfactory::factory("mysql"); $db->query(".."); DBfactory::factory()->query(".."); factory can now create different driver objects (default mysql):
aside : Type Hinting the factory pattern (6)
the adapter pattern (1) o the adapter pattern simply converts the interface of one class to what another class expects. o for this reason, it is often referred to as a "wrapper" pattern. o adapters are helpful when a class doesn't have quite the exact methods needed, and its not possible to change the original class. o the adapter can take the methods accessible in the original class, and adapt them into the methods needed.
the adapter pattern (2) class SimpleBook { private $author; private $title; function __construct($author_in, $title_in) { $this->author = $author_in; $this->title = $title_in; } function getAuthor() { return $this->author; } function getTitle() { return $this->title; }
the adapter pattern (3) class BookAdapter { private $book; function __construct(SimpleBook $book_in) { $this->book = $book_in; } function getAuthorAndTitle() { return $this->book->getTitle(). ' by '. $this->book->getAuthor(); } $book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns"); $bookAdapter = new BookAdapter($book); echo 'Author and Title: '.$bookAdapter->getAuthorAndTitle(); run testview code
the decorator pattern (1) o the point of the decorator pattern is to enhance an object with some functionality without modifying the structure of the original object. o the decorator pattern is often used an example of the principle of preferring "composition over inheritance"
class Cupcake { public $Toppings = array('sprinkles' => 0, 'frosting' => 'none'); public function __construct($int, $str) { $this->Toppings['sprinkles'] = $int; $this->Toppings['frosting'] = $str; } abstract class Decorator_Wrapper { abstract function Add($mixed); abstract function Remove($mixed); } the decorator pattern (2)
class Sprinkle_Decorator extends Decorator_Wrapper { public function __construct(Cupcake $c) { $this->Cupcake = $c; } public function Add($int) { $this->Cupcake->Toppings['sprinkles'] += $int; } public function Remove($int) { $this->Cupcake->Toppings['sprinkles'] -= $int; } the decorator pattern (3)
the decorator pattern (4) class Frosting_Decorator extends Decorator_Wrapper { public function __construct(Cupcake $c) { $this->Cupcake = $c; } public function Add($str) { $this->Cupcake->Toppings['frosting'] = $str; } public function Remove($str) { echo "Hrmm.. We cant seem to remove your $str, it's stuck on the muffin!"; }
# Test the decorator pattern echo ' Make a new cupcake! '; $cupcake = new Cupcake(5, 'none'); print_r($cupcake->Toppings); echo ' Add more sprinkles! ' ; $sprinkle = new Sprinkle_Decorator($cupcake); $sprinkle->Add('55'); print_r($cupcake->Toppings); echo ' Remove 25 sprinkles! ' ; $sprinkle->Remove('25'); print_r($cupcake->Toppings); echo ' Add some frosting :) '; $frosting = new Frosting_Decorator($cupcake); $frosting->Add('Chocolate');print_r($cupcake->Toppings); the decorator pattern (5) run testview code