4.2 Creational Design Patterns

Introduction

Creational Design Patterns are concerned with object creation. They abstract the process of instantiating an object, thus decoupling the system from the mechanisms of creating objects. The creational patterns primarily make use of inheritance to provide the abstraction between the client code requesting the new object, and the specific concrete object which is created.

As the creational design patterns are all "competitors" - in that they are all used to solve the problem of instantiating an object - it is important to understand each of them well, to be able to select the most appropriate one for the specific situation being addressed.


Singleton

Purpose

The Singleton design pattern is used to ensure that only a single instance of a specific class is instantiated.

Description

Many scenarios exist where it is useful to only have a single instance of an object. For example, if you have an Application object, which holds all the various components of the application, or a Database object, which has the connection to the database server and is used to execute SQL queries, or a Configuration object which holds the configuration for an application. In these examples, it would not make sense to have multiple instantiations of each of these classes. Thus, we would want an existing instance of an object to be returned if we tried to instantiate any of these classes.

Solution

The solution to this problem is to define an attribute to hold the single instance of the object. If this instance attribute is null, then a new instance is assigned and returned, otherwise the instance contained in the attribute is returned.

singleton_diagram

Python Implementation

There are a number of ways we can implement a singleton in Python. One convenient way is to define a Singleton class which can be inherited from into other classes in which the Singleton design pattern is to be applied. Here is an example of such an inheritable class.

class Singleton(type):
    def __init__(cls, name, bases, dict):
        super(Singleton, cls).__init__(name, bases, dict)
        cls.instance = None

    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance = super(Singleton, cls).__call__(*args, **kw)
        return cls.instance

To make use of this, we specify the __metaclass__ of our class implementing the singleton design patter. Here is an example.

class MyClass(object):
    __metaclass__ = Singleton

    attrib1 = ""
    attrib2 = 0

    def function1(self):
        pass

    def function2(self):
        pass

Now, to test if the Singleton pattern has worked, we can create two instances of the MyClass class which implements the singleton pattern, and each of the instances should point to the same memory location, indicating that they are all referring to the same instance of the class.

if __name__ == '__main__':
    # Instantiate Object A
    objA = MyClass()

    # Instantiate Object B
    objB = MyClass()

    # Investigate the memory addresses of the two objects
    print "Object A = %d" % (id(objA))
    print "Object B = %d" % (id(objB))

    # Determine if they are the same instance
    if (id(objA) == id(objB)):
        print "Same"
    else:
        print "Different"

When you run this code, you should see that both memory addresses are equivalent, and "Same" is printed out as a result, indicating that the Singleton design pattern has been successfully implemented.


Factory

Purpose

The Factory Method Pattern is intended to be used when we want subclasses to choose which classes they should instantiate when an object is requested. The Factory design pattern abstracts the object instantiation process by allowing subclasses to decide which class to instantiate. The factory pattern introduces a separation between the application and a family of classes, resulting in loose coupling between the concrete child classes and the application.

Description

The Factory design pattern is used in the situation where a class does not know the specific child class to instantiate, or where the child class to instantiate is dependant on the instantiation of another child class.

For example, imagine we are writing an application for a real estate agency. They might have the need to produce various documents (such as lease agreements) depending on the type of property involved. Thus, we might have a Property abstract class, from which the various child classes - representing property types - inherit. Then we might also have a Document abstract class, from which the various child classes - representing specific document templates - inherits. However, the Property parent class will not know exactly which of the specific document sub classes to create. Thus, the instantiation logic needs to reside in the child classes.

Solution

In the Factory design pattern we have a number of "participants" (or classes) defined:

  • The Factory: The parent class from which the client code is requesting the concrete product. In our example above, this would be the Property abstract class.
  • Concrete Factory: The concrete instance of the abstract Factory class. In our above example, this would be a specific property type.
  • Product: This is the abstract class which provides the common interface for the concrete products. In our above example, this would be the Document abstract class.
  • Concrete Product: This is the concrete child class which inherits from the parent Product class, and is created by the Concrete Factory class.

factory_diagram

Python Implementation

Using our example (see above) of the Real Estate application, let's look at how we would implement this using the Factory Design Pattern in Python.

class Property:
    def DocumentFactory(self):
        return self.ConcreteDocumentFactory()

class House(Property):
    def ConcreteDocumentFactory(self):
        return HouseRentalDocument()

class Flat(Property):
    def ConcreteDocumentFactory(self):
        return FlatRentalDocument()

class Document:
    title = "Lease Agreement"

class HouseRentalDocument(Document):
    def __init__(self):
        self.title = "House Lease Agreement"

class FlatRentalDocument(Document):
    def __init__(self):
        self.title = "Apartment Lease Agreement"

if __name__ == '__main__':
    # Test: House
    house = House()
    doc = house.DocumentFactory()
    print "House Document Title: %s" % (doc.title)

    # Test: Flat
    flat = Flat()
    doc = flat.DocumentFactory()
    print "Flat Document Title: %s" % (doc.title)

In the above code, although we are calling the DocumentFactory() factory method from the Factory class, the responsibility for instantiation is in reality being delegated to the child classes.


Builder

Purpose

The builder pattern is used to separate the logic for creating complex objects from the logic that constructs the various parts of the object. The builder patterns allows flexibility in construction of the object by allowing for different versions of the complex object to be built.

Description

When we have the need to build a complex object - such as an email with various attachments, or a web form, with various input types - a flexible creational pattern needs to be implemented to allow for an object to be created using a common interface,

Solution

The Builder design pattern has the following components:

  • Builder: A common interface for building parts of a Product.
  • Concrete Builder: Children of the abstract Builder class, which build and assemble the various components of the Product.
  • Director: Utilizes the Builder to construct a Product.
  • Product: The complex object being built. This is a composite class, containing other classes which are the components being built into the instance of the Product object.

The client code will create a Director object, which then constructs the various components of the Product, which is then accessed by the client code.

builder_activity

Here is the class diagram of the Builder design pattern.

builder_diagram

Python Implementation

Let's take a look at an example in Python. In our example, we are going to apply the Builder design pattern to create a Form builder class. This will be able to build either a static form for printing, or a web form. We will be able to construct a product, the Form HTML, with varying input components. Let's take a look at the code:

from abc import ABCMeta, abstractmethod

class AbstractFormBuilder:
    __metaclass__ = ABCMeta

    product = 0

    def __init__(self):
        self.product = Product()

    @staticmethod
    def Factory(type):
        if type == "web":
            return WebFormBuilder()
        elif type == "static":
            return StaticFormBuilder()

    def add(self, type, label, name, default_value):
        self.concrete_add(type, label, name, default_value)

    @abstractmethod
    def getResult(self):
        pass

class WebFormBuilder(AbstractFormBuilder):

    def concrete_add(self, type, label, name, default_value):
        if type == "text":
            self.add_text(label, name, default_value)
        elif type == "textarea":
            self.add_textarea(label, name, default_value)
        elif type == "select":
            self.add_select(label, name, default_value)

    def add_text(self, label, name, value):
        html_segment = "%s " % (label, name, value)
        self.product.add(html_segment)

    def add_textarea(self, label, name, value):
        html_segment = "%s %s" % (label, name, value)
        self.product.add(html_segment)

    def add_select(self, label, name, value):
        html_segment = "%s " % (label, name)
        options = value.split(',')
        for option in options:
            html_segment = html_segment + "%s" % (option, option)
        html_segment = html_segment + ""
        self.product.add(html_segment)

    def getResult(self):
        return "%s" % (self.product.get_html())

class StaticFormBuilder(AbstractFormBuilder):

    def concrete_add(self, type, label, name, default_value):
        if type == "text":
            self.add_text(label, name, default_value)
        elif type == "textarea":
            self.add_textarea(label, name, default_value)
        elif type == "select":
            self.add_select(label, name, default_value)

    def add_text(self, label, name, value):
        html_segment = "%s ________________________________" % (label)
        self.product.add(html_segment)

    def add_textarea(self, label, name, value):
        html_segment = "%s ________________________________________________________________________________________________" % (label)
        self.product.add(html_segment)

    def add_select(self, label, name, value):
        html_segment = "%s " % (label)
        options = value.split(',')
        for option in options:
            html_segment = html_segment + "_ %s " % (option)
        html_segment = html_segment + ""
        self.product.add(html_segment)

    def getResult(self):
        return self.product.get_html()

class Form:

    builder = 0

    def __init__(self, type):
        self.builder = AbstractFormBuilder.Factory(type)

    def add(self, type, label, name, value):
        self.builder.add(type, label, name, value)

    def generate(self):
        return self.builder.getResult()

class Product:
    name = ""
    html = ""

    def add(self, html_segment):
        self.html = self.html + html_segment

    def get_html(self):
        return self.html

if __name__ == '__main__':
    myForm = Form("web")
    myForm.add("text", "Username", "username", "")
    myForm.add("text", "Password", "password", "")
    myForm.add("select", "User Type", "user_type", "admin, employee, manager")
    print myForm.generate()

In the above coding example, we can identify the four classes involved in the Builder pattern:

  1. Builder: This is the AbstractFormBuilder class.
  2. Concrete Builder: These are the WebFormBuilder and StaticFormBuilder classes which inherit from the AbstractFormBuilder class.
  3. Director: This is the Form class, which directs the utilization of the other classes.
  4. Product: This contains the HTML for the form being built.

Exercises

For the following examples, specify which design pattern is the most applicable, and describe how to use it to solve the specified problem.

  1. Storing the configuration for an application.
  2. Exporting data into multiple formats.
  3. Dynamically creating a survey.

Continue to next section.


Comments

comments powered by Disqus