Patterns notes Patterns Notes

Centralized dispatching … or not

If you centralize HTTP request processing, you need to dispatch an appropriate view.  If you process page-by-page requests, the views self-select; but, you need to resist the temptation to cut and paste code from page to page and, instead, carefully factor out duplication.

Principles

Code to an Interface - not to an Implementation

In defining class responsibilities, if a conditional is needed to select between alternative strategies or contexts, consider creating a new type and encapsulating the implementation details behind its interface.

Avoid instantiating objects within classes where possible; instead, have objects passed in to the constructor or other methods. 

Where passing an object as a method argument, try to ask for a parent type, rather than a specific implementation unless you really need that particular functionality. This allows you to pass different implementations as needs and contexts change.

Polymorphism, also known as class switching, is the practice of using a common superclass to mask distinct implementations.

Database modeling

To connect to a database and retrieve a data set, using PEAR::DB.

<?php

    require_once("DB.php");
    
    $dsn = "sqlite://./venue.db";	// get this from    config
    $db = DB::Connect($dsn);

    $result = $db->query("SELECT * FROM venue");
    
    while ($row    = $result->fetchRow(DB_FETCHMODE_ASSOC))    
    {
        print "id: {$row[id]} name: {$row[name]}\n";
    }
    
?>

Depending upon the DSN, which would be retrieved from an external source, such as a configuration file, the code fragment will run with MySQL, SQLite, Oracle or any other database.

Pulling embedded components away from their context is known as decoupling,  one of the great objectives of many patterns.  With client code decoupled from the database implementation, adding new databases without changes elsewhere is easier.

By coding to the DB_common interface:

      function getVenue($id) 
      {
			$result = $this->db->query("SELECT *    FROM venue where id = $id");
      
			return $result->fetchRow(DB_FETCHMODE_ASSOC);
      }
      
      function getAllVenues() 
      {
			$result = $this->db->query("SELECT *    FROM venue");
      
      		while    ($row = $result->fetchRow(DB_FETCHMODE_ASSOC)) 
      		{
      			$ret[] = $row;
      		}
      		return $ret;
      } 

Conditional coding has been eliminated. The database platform is declared once, when the DB_common implementation, stored in the $db property, is instantiated.

Favor composition over inheritance

Encapsulate the concept that varies

Decorator pattern

Decorators add object functionality at runtime, as an alternative to subclassing. The Decorator pattern defines simple components which can be combined in any order, using class and subclass hierarchy.

A class tree structure can be created by instantiating the parent object.  Constructor calls are nested; read the nesting from the inside out.  New functionality can be implemented by adding to the instantiation tree.

Observer pattern

The subject class uses the observer interface to broadcast its updates, no longer concerned with individual subtypes and their various communications. The Observer pattern defines a mechanism for components to opt-in to receive messages when a target “subject” object changes state. The “subject” object need have no knowledge of the components 'watching' it for events.  This divorces the component from knowledge of and dependence on its peers.  Interested components implement a common interface, confirming the primacy of interface over implementation.

To remove subject class dependence upon components with which it must communicate, the interested objects must opt in to receive notifications. To turn component listener classes into Observer classes, either have them extend a common superclass or implement a common interface.  The latter guarantees type and functionality without preventing classes from subclassing different parent classes.

With the Gang of Four 'pull' approach there’s no need to anticipate the information needed to pass to your observer objects. Instead, pass an observed class instance and let the observer object call state methods to find out whatever.

The ‘push’ method provides information parameters in an update call.
The ‘notify’ method …

Unit testing

If you're coding to an interface, you can create fake objects.  If database code is encapsulated behind a clear interface, one can create a class the same as your database class, containing hard-coded testing data. Create a dummy “mock” class that extends the same parent. The client is passed an object unaware of the implementation with which it works. This is why it is usually a good idea to pass objects around a system, rather than have them instantiated directly by the classes that use them.

Back Home