Search  
Tuesday, October 07, 2008 ..:: Articles » GOF Creational Patterns with C# ::..   Login
 Creational Patterns
Introduction | Factory | Abstract factory | Builder | Prototype | Singleton | Links
 
Show as single page

GOF Creational Design Patterns with C#

By Barry Mossman from Primos.com.au

The GOF design patterns help address the following challenges :

    • design ready to accommodate change & growth

    • design flexible systems which come ready to handle reconfiguration and run time tailoring

    • code in manner to facilitate reuse during the development and extension phases ... ie. both external and internal reuse, so that we are rewarded by efficiencies as the project progresses, coming from investments made earlier in the project.

    • implement change in a way that doesn't overly shorten the system's useful lifespan

In a multi-person project the design patterns have the additional utility of providing a shorthand language with which to describe design options and specifications.

This article is the first in a series. It discusses why and when you would want to use the design patterns, and demonstrates a C# implementation of the patterns. There is source code for my demonstration program available (see links section). The program contains annotated example displays. It also displays some brief notes about the patterns, so if you are interested in starting to work with the patterns it may be a useful utility to have on your desktop during the learning period.

The design patterns were defined in the programming classic entitled "Design Patterns" by Gamma, Helm, Johnson & Vlissides. The four authors are commonly described as the Gang Of Four (GOF) for brevity and levity. The subtitle of the book is "elements of reusable object-oriented software". If you are not familiar with the book you have probably seen it in a bookshop somewhere.

The GOF described various categories of patterns:

  • Creational Patterns <=== discussed in this article

  • Structural Patterns

  • Behavioral Patterns

The Creational Patterns are:

  • Factory

  • Abstract Factory

  • Builder

  • Prototype

  • Singleton

General techniques promoted by the GOF

  1. Decouple our client code from the classes of the objects that it uses:

    Why ?

  • Code our client to use like classes generically, so that we reduce the need for switch blocks.

  • Anticipate the virtually certainty that in the future it will become necessary to change the implementation of the classes that our client uses.

  • When this happens maybe:

    • we need to leave the old version 1 class in place as other clients are still using it (a requirement to ensure absolute backwards compatibility is a task that is nice to avoid)

    • our new enhanced system is going to be more flexible, and the actual class which is to be instantiated by our client can now vary at runtime. Perhaps we now have have several subclasses inheriting from the version 1 class, and runtime conditions will determine which of the subclasses that we will need to instantiate.

    • our new release introduces some form of object pooling so that the client is no longer causing the creation of new object for each individual use.

  • The aim is to write our client in such a manner that these kind of changes can occur to the objects that it uses, without forcing code changes within the client itself.

  • The general technique is to outsource object creation to one of these Creational Design Patterns, and then to reference the objects created via a base class rather than addressing them explicitly via their concrete class types.

  1. Favour "object composition" over "class inheritance"

  • in "class inheritance":

    • the issue of code reuse is addressed by breaking our business objects down to generic classes where possible, and then to build up the classes we actually use via class inheritance.

    • has the advantages that this supported by the programming language, is simple to use, and the resulting application architecture is easy to understand

    • has the disadvantages that

      • can lead to an implementation where the parent classes have too much bearing on the subclass's implementation. Encapsulation becomes compromised as the subclasses can have too much knowledge of their parent's implementation. Change at either level is liable to require change at the other level. Reuse of a subclass for a future extension is more likely to require change at the parent level also.

      • hampers runtime flexibility where we would able to change the behaviours being inherited, as this has been decided at compile time.

      • reuse is only available at the whole logical object level, rather than at the level of just one of the behaviours of the logical object

  • "object composition"

    • here the business objects which our client will use are assembled from a number of helper classes working together to assemble the behaviour required which would have been delivered by the class inheritance model used in the class inheritance technique.

    • has the advantages that:

      • our objects can be more flexible because their behaviour can be assembled dynamically at runtime, rather than fixed at compile time through inheritance

      • we are less likely to allow our classes grow into an unmanageable size

      • we are likely to get good levels of reuse, and reduced levels of rework.

    • but has the disadvantage that our system design can be harder to understand as it's operation is delivered via the inter-relationships between the helper classes rather than from just a few business classes

      • the Design Patterns themselves provide a language with which we can describe and document the system design to help overcome this disadvantage

    • Note that the advice is to only to "favour" object composition over class inheritance, not to stop using inheritance altogether. The two techniques work well together

  1. Algorithms that are likely to change should be isolated into a to reduce the impact when this happens.

      • There are various patterns which are designed to isolate such algorithms away into a helper class on their own which is a design technique that is ready for change and likely to minimise impact upon other sections of our code.

The Creational Patterns have an important part to play in the deployment of these techniques that the GOF are advocating

    • the Creational Patterns provide the structures to achieve the objective of decoupling our client from the classes which it uses

    • the Creational Patterns are not involved in the object composition approach to system design, but this approach will result in our application having an increased quantity of physical classes. The success of the strategy when faced with future growth or change, depends upon decoupling, which makes the Creational Patterns crucial.

    • The logic involved in the instantiation and initialisation of the classes that we deploy will be a likely area for future change. This makes these algorithms likely candidates for isolation, and the Creational Patterns are those which achieve this objective.

A summary of the patterns

Pattern Name

General objective

Factory

Most basic creational pattern.

Can be used on it's own, or used within the patterns following.

Delivers all the basic objectives mentioned above.

Abstract Factory

Allows us to group the objects that we want to use into families.

Our client can then decide which family it wants to use based upon some configuration or runtime option.

The Abstract Factory will instantiate objects from just the chosen family.

Our client will operate with objects from the chosen family using generic calls that would work with any other family.

Prototype

We first build and configure a prototype, maybe using one of the other patterns.

Our client can then clone from the prototype to create instances as it requires them.

Our client can operate, with generic code, upon either the prototype, or upon any of the clones.

Facilitates runtime flexibility as we can control how the prototype is configured at runtime, and then our client can create cloned instances as required as if this was a class that was defined into the system at compile time.

Builder

The building of our object is outsourced to two helper classes.

One class controls what is built, and the other controls how it is built.

This means that we can have features and options with the classes that we use, as well as decoupling our client from the physical classes that it is uses.

The mechanics of the features and options assembly is outsourced from our client.

Singleton

This is a specialist pattern that gives the client access to an object that is created with only the one instance, and is shared across the application.

The pattern relieves the client of the responsibility of ensuring that there is just the one instance regardless of how many attempts are made to instantiate the object.


Introduction | Page 1 of 7 | Factory

      

Copyright 2005 by Primos Computer Services   Terms Of Use  Privacy Statement