Avatar

Design Patterns

A while ago I started reading a book about Design Patterns. Now I've read it, I thought it was time to summarize the differences between OO  and procedural programming in a way most people will understand.

For this example1 I'll use a visitor which is logged in on a website, who wants to read a news item, which is only available for registered members, first the procedural style:

1<?php
2// Connect to the database
3// ... a pile of HTML for the rest of the page
4// ... and some code to check if there's a session or cookie
5if ($_COOKIE['logged_in'] == true) {
6
7    // Retrieve the item from the database, using the id given with the URL
8    $result = pg_query("SELECT title, author, content FROM news WHERE id = " . $_GET['id']);
9
10    // Loop through the results, in this case just one row is returned by the database
11    while ($item = pg_fetch_assoc($result)) {
12
13        // We want to know who posted the item and of course the item itself
14        // HTML and PHP are mixed in the same file
15        echo '<h1>' . $item['title'] . '</h1>';
16        echo $item['author'] . '<br/>';
17        echo '<article>' . $item['content'] . '</article>';
18    }
19}

For a website which has just one page, the code above will be a perfect solution. However, when one wants to add a second page, the same code has to be used. For example on a photo album, here too it's about a picture only a registered member is allowed to see:

1<?php
2// Connect to the database
3// ... a pile of HTML for the rest of the page
4// ... and some code to check if there's a session or cookie
5if ($_COOKIE['logged_in'] == true) {
6
7    // Retrieve the item from the database, using the id given with the URL
8    $result = pg_query("SELECT title, author, photo FROM pictures WHERE id = " . $_GET['id']);
9
10    // Loop through the results, in this case just one row is returned by the database
11    while ($item = pg_fetch_assoc($result)) {
12
13        // We want to know who posted the item and of course the item itself
14        // HTML and PHP are mixed in the same file
15        echo '<h1>' . $item['title'] . '</h1>';
16        echo $item['author'] . '<br>';
17        echo '<img src="' . $item['photo'] . '">';
18    }
19}

As you can see, only a small change is needed, the rest of it is duplicate code. With only two pages there's not much damage done, but tomorrow of course there will come another page, and another... If you want to support comments on your website, which are almost equal on every page, this code has to be added on each of the four pages. The copy and pasting won't hurt, but bugs always appear afterwards, so you have to edit this code on the four locations. For websites with hundreds of pages, this just is no option. With OO this problem is solved. In this example I will be using the MVC pattern.

The Model is used to connect to the database. It pulls data from and puts data into this database. It also deals with the logic behind this data. A timestamp is converted to a readable date or time format. And it checks user input, so no strange content can appear on the website and it protects the website against hacks.

The View is used to display the data on screen, this is the only place where HTML (and sometimes CSS) is used. In most cases the HTML for markup and CSS for styling is separated in different files. Which is a good habit to keep the code clean.

The Controller is in between the Model and View like some sort of negotiator. For example, it makes sure only permitted users can view certain data.

In the example below I'll use this MVC pattern to refactor the procedural code. First the Models, with a class which acts like an interface, with a standard method and an abstract method, this abstract method doesn't do anything, but every class that extends this class, should overrule this method. Every Model has to contain a database connection, so this functionality is put in the constructor. The constructor is automatically called when a class is initialized, or when an object is created.

1<?php
2// All Models 'extend' this class, so all Models automatically contain the connect() method
3// This one has to be written just once. When the database password changes, this has to be 
4// altered on one location
5class Model {
6
7    public function __construct() {
8        // Some code to connect...
9    }
10
11    public abstract function getData($id);
12}
1<?php
2class ModelNews extends Model {
3
4    // The controller picks all variables that are specified in the URL, in this case
5    // the id, and uses them to call this method
6    public function getData($id) {
7        $result = pg_query("SELECT title, author, content FROM news WHERE id = " . $id);
8
9        // Loop through the results, in this case just one row is returned by the database
10        while ($item = pg_fetch_assoc($result)) {
11
12            // No HTML needed here. An array is returned that all Views can understand
13            $data[0]['title'] = $item['title'];
14            $data[0]['author'] = $item['author'];
15            $data[0]['content'] = $item['content'];
16        }
17        return $data;
18    }
19}
1<?php
2class ModelPhotos extends Model {
3    public function getData($id) {
4        $result = pg_query("SELECT title, author, photo FROM pictures WHERE id = " . $id);
5        while ($item = pg_fetch_assoc($result)) {
6            $data[0]['title'] = $item['title'];
7            $data[0]['author'] = $item['author'];
8            $data[0]['photo'] = $item['photo'];
9        }
10        return $data;
11    }
12}

Looking at the Models, we have pretty much the same code, but the HTML is separated and the Models only have to know how the database is set up. Next we have the Views:

1<?php
2class View {
3    public function __construct() {
4        // A pile of HTML...
5    }
6
7    // Every View has to have the option to show the output on screen
8    public function show($data) {
9
10        // First loop through the array
11        while ($data) {
12
13            // Then make sure every field is displayed, in this case title; author and content
14            while ($data[$i]) {
15
16                echo '<h1>' . $data[$i][$j] . '</h1>';
17                echo $data[$i][$j];
18                echo '<article>' . $data[$i][$j] . '</article>';
19            }
20        }
21    }
22}
1<?php
2class ViewNews extends View {}
1<?php
2class ViewPhotos extends View {}

The ViewNews and ViewPhotos classes can be kept small, because they inherit their functionality from the main View class. When one of the Views needs some extra functionality, it can be easily edit by overruling the show() method. Also, other methods can be added. Last but not least, the Controllers:

1<?php
2class Controller {
3    public function run() {
4        // The Model and View are initialized
5        $model = new Model();
6        $view = new View();
7
8        // The data from the Model is passed to the View
9        $view->show($model->getData($_GET['id']));
10    }
11}
1<?php
2class ControllerNews extends Controller {}
1<?php
2class ControllerPhotos extends Controller {}

The Controllers also can be kept small, because the run() method is inherited. When initializing the Model and View only the right title has to be passed, so that ModelNews and ViewNews are called when ControllerNieuws is called. The same story goes for the ModelPhotos; ViewPhotos and ControllerPhotos. The Controller class can handle this, so no other code is needed for ControllerNews en ControllerPhotos.

The number of lines is pretty much the same, but with bigger websites one can get lost in the first example. But actually the article is about Design Patterns. Some basic principles of OO from Head First Design Patterns.


OO Principles:

  • Encapsulate what varies
  • Favor composition over inheritance
  • Program to interfaces, not to implementations
  • Strive for loosely coupled design between objects that interact
  • Classes should be open to additions, but closed for alterations
  • Depend upon abstractions. Do not depend upon concrete classes
  • Only talk to friends
  • Don't call us, we call you
  • A class should have only one reason to change it
  • Another keyword: polymorphism.

Some situations don't allow the use of all principles, so they have to be compromised, that's where Design Patterns come in. These are solutions for these situations, used a lot by other developers, so these patterns are docoumented a lot. The patterns get a title which allows developers world whide to use the same vocabulary.

OO Patterns (Design Patterns):

Creational patterns

  • Abstract factory2 Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
  • Builder2 Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.
  • Factory method2 Define an interface for creating a single object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses (dependency injection).
  • Lazy initialization Tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. This pattern appears in the GoF catalog as "virtual proxy", an implementation strategy for the Proxy pattern.
  • Multiton Ensure a class has only named instances, and provide a global point of access to them.
  • Object pool Avoid expensive acquisition and release of resources by recycling objects that are no longer in use. Can be considered a generalisation of connection pool and thread pool patterns.
  • Prototype2 Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
  • Resource acquisition is initialization Ensure that resources are properly released by tying them to the lifespan of suitable objects.
  • Singleton2 Ensure a class has only one instance, and provide a global point of access to it.
  • Object library Encapsulate object management including factory interface with live and dead lists.

Structural patterns

  • Adapter or Wrapper or Translator2 Convert the interface of a class into another interface clients expect. An adapter lets classes work together that could not otherwise because of incompatible interfaces. The enterprise integration pattern equivalent is the translator.
  • Bridge2 Decouple an abstraction from its implementation allowing the two to vary independently.
  • Composite2 Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
  • Decorator2 Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
  • Facade2 Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
  • Flyweight2 Use sharing to support large numbers of similar objects efficiently.
  • Front controller The pattern relates to the design of Web applications. It provides a centralized entry point for handling requests.
  • Marker Empty interface to associate metadata with a class.
  • Module Group several related elements, such as classes, singletons, methods, globally used, into a single conceptual entity.
  • Proxy2 Provide a surrogate or placeholder for another object to control access to it.
  • Twin Twin allows modeling of multiple inheritance in programming languages that do not support this feature.

Behavioral patterns

  • Blackboard Artificial intelligence pattern for combining disparate sources of data (see blackboard system)
  • Chain of responsibility2 Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
  • Command2 Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
  • Interpreter2 Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
  • Iterator2 Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
  • Mediator2 Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
  • Memento2 Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later.
  • Null object Avoid null references by providing a default object.
  • Observer or Publish/subscribe2 Define a one-to-many dependency between objects where a state change in one object results in all its dependents being notified and updated automatically.
  • Servant Define common functionality for a group of classes.
  • Specification Recombinable business logic in a Boolean fashion.
  • State2 Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
  • Strategy2 Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
  • Template method2 Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
  • Visitor2 Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Concurrency patterns

  • Active Object Decouples method execution from method invocation that reside in their own thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests.
  • Balking Only execute an action on an object when the object is in a particular state.
  • Binding properties Combining multiple observers to force properties in different objects to be synchronized or coordinated in some way.
  • Block chain Decentralized way to store data and agree on ways of processing it in a Merkle tree, optionally using Digital signature for any individual contributions.
  • Double-checked locking Reduce the overhead of acquiring a lock by first testing the locking criterion (the 'lock hint') in an unsafe manner; only if that succeeds does the actual locking logic proceed. Can be unsafe when implemented in some language/hardware combinations. It can therefore sometimes be considered an anti-pattern.
  • Event-based asynchronous Addresses problems with the asynchronous pattern that occur in multithreaded programs.
  • Guarded suspension Manages operations that require both a lock to be acquired and a precondition to be satisfied before the operation can be executed.
  • Join Join-pattern provides a way to write concurrent, parallel and distributed programs by message passing. Compared to the use of threads and locks, this is a high-level programming model.
  • Lock One thread puts a "lock" on a resource, preventing other threads from accessing or modifying it.
  • Messaging design pattern (MDP) Allows the interchange of information (i.e. messages) between components and applications.
  • Monitor object An object whose methods are subject to mutual exclusion, thus preventing multiple objects from erroneously trying to use it at the same time.
  • Reactor A reactor object provides an asynchronous interface to resources that must be handled synchronously.
  • Read-write lock Allows concurrent read access to an object, but requires exclusive access for write operations.
  • Scheduler Explicitly control when threads may execute single-threaded code.
  • Thread pool A number of threads are created to perform a number of tasks, which are usually organized in a queue. Typically, there are many more tasks than threads. Can be considered a special case of the object pool pattern.
  • Thread-specific storage Static or "global" memory local to a thread.
1) The examples are solely for illustrational purposes
2) These patterns are found in Head First: Design Patterns