Some Structural Design Patterns

Brioche/Aspirine

00 - Table of Contents

01 - Introduction
02 - Composite
03 - Decorator
04 - Proxy
05 - Other Structural Patterns

01 - Introduction

In the good old times of non Object Oriented applications, code and data were two different things. People used to write routines to manipulate given data structures while in the OO world, we just write operations on classes that represents an abstract view of the stored data of the data structure itself.

The new concepts introduced by OOP added a new challenge to software design: coders would have now to cope with complex structures of class hierarchies.

Just like records in a database, your objects are linked to other objects using references and/or pointers.

02 - Composite

Before we start, you have to know that this pattern is one of my favorite! =)

In demos, we often have to deal with hierarchical structures and that's exactly what the Composite Pattern is about. The composite allows any client application to treat the same way both hierarchy components and parts of the hierarchy itself.


			       ---------
			      |Component|--------------------------+
			       ---------			   |
				   |				   |
		inherits . . . . . |		   contains . . . .|
				   |				   |
				  /_\				   |
	      +-----------------------------------------+	   |
	      | 	    |		   |		|	   |
	  ----------	----------    ----------    ---------	   |
	 |Component1|  |Component2|  |ComponentN|  |Composite|<>---+
	  ----------	----------    ----------    ---------

The Composite class holds the references to all the components stored into it.

Let's say the context is a Ray-Tracing system and we'd like to be able to apply geometrical transforms to the objects as much as t.


	class Component {
	public:
		virtual void apply_transform( Matrix *m ) = 0;
	};

	class Composite : public Component {
		vector members;
	public:
		void add( Component *c );
		virtual void apply_transform( Matrix *m );
	};

	class Plane : public Component {
	public:
		// ...
		virtual void apply_transform( Matrix *m );
	};

	class Sphere : public Component {
	public:
		// ...
		virtual void apply_transform( Matrix *m );
	};

Of course, the problem is simplified here since all the primitives should actually inherit from a Model interface that defines the operations required by the rendering engine as such as finding the hit distance for a given ray, calculating the color of the hit point and so on.

In the primitive objects (Plane and Sphere here), the result of this method will be some vector arithmetic operation on the internal representation of the 3-dimensional model.

Now, let's take a closer look on how to implement the composite object. What we have to do when the method apply_transform() is called is to call that method on all the object referenced in this composite.


	void Composite::add( Component *c )
	{
		members.push_back( c );
	}

	void Composite::apply_transform( Matrix *m )
	{
		for ( int i = 0; i < members.size(); i++ )
			members[i]->apply_transform( m );
	}

If this method is called on another composite object, the transformation will naturally bo propagated to contained objects.

This pattern is heavily used in the Java Abstract Windowing Toolkit GUI framework.

Btw, did you already think about the screen being a container of effects? Imagine having a "root" effect (whose action would be to clear the screen or draw some background bitmap or effect) and then you just add several layers of effects (first layer 3D objects, second layer,...). With such a class architecture, the mainloop is the same for the whole demo, only the contents of the "root" container changes... just take a couple of minutes to think about it, you all scripted demo addicts! =)

03 - Decorator

This Pattern is used to add responsibilities to an object in a dynamic and flexible way.

Remember this: "A decorator changes the skin of an object, not its guts."

Basically, a Decorator is a container of Components as such as the Composite Pattern we've studied previously. The Decorator is in fact a degenerated form of Composite patterns with only one type of concrete Component.


			    ---------
			   |Component|
			   |---------|-------------+
			   |  foo()  |		   |
			    ---------		   |
	     inherits . . . . . |		   |
			       /_\		   |. . . contains
			+---------------+	   |
			|		|	   |
		    ----------	    ---------	   |
		   |AComponent|    |Decorator|<>---+
		    ----------	    ---------
					|
				       /_\
			   +--------------------------+
			   |		|	      |
		      ----------    ----------	  ----------
		     |Decorator1|  |Decorator2|  |DecoratorN|
		      ----------    ----------	  ----------

The DecoratorX are actually Strategy Patterns (see Behavioural Patterns).

The Pattern Decorator allows you to easily add (or remove) responsibility from an object. It's also useful when you need to extend the behaviour of a class and when the inheritance is not available (too many sub-classes or non virtual methods in the super-class).

Check out the following instance chart:


	    ----------
	   |Decorator1|
	   |----------|        ----------
	   |component-+------>|Decorator2|
	    ----------	      |----------|	  ----------
			      |component-+------>|AComponent|
			       ----------	  ----------

You have to notice that the final component doesn't hold any reference to its decorators. So if you had any other decorators, you don't have to change a bit in the implementation of the class AComponent.

The Java I/O stream API is a good example of Decorators. First you get some sort of raw stream, you decorate it with a buffered stream to increase performance and you finally decorate it with a higher level data access strategy to consider the streams as lines of text or as fixed block records or whatever. So we have something like (class names are pure fiction):


	HigherLevelReader hlr = new BufferedReader(
					new StreamReader(
						something.getStream()
					)
				);
	customBlock = hlr.readCustomBlockOrSomething();

You just customize (decorate) the objects by adding new features between the original component (a stream here) and the end user.

04 - Proxy

I'm sure that lots of you are familiar with the concept of Proxy in the world of the Internet. The Proxy Pattern has much the same function as the Proxy server of your ISP. Its goal is to be a surrogate to another object in order to check the access to this object.

So we have something like the following instance diagram:


		   ------	  ----- 	 ------
		  |Client|------>|Proxy|------->|Object|
		   ------	  ----- 	 ------

There's no point writing a Proxy that does a 1-to-1 mapping between its methods and the methods of the "hidden" object. The Proxy should be a "value-added" object. The Proxy can:

- perform some pre or post-processing before/after calling the service;
- check the arguments before passing them to the real object;
- operate access control on the resource (like handling semaphores);
- hide technical details (distributed objects);
- cache data to avoid to call the service on the "hidden" object
- ...

When writing Proxies in C++, it might be useful to think about overloading the dereference operators : * and ->. This will give a real transparent access to the object from the client application.

Let's imagine you have to render a very large interactive 3D scene which use lots of different 256x256 32-bpp textures. Since you are a nice coder, you won't oblige people to have 256 megs of memory to enjoy your smashing production and you'll only keep unpacked the texture actually needed to rasterize the current image and others will be left compressed in memory.


				------------
			       |Texture_Base|
				------------
	       inherits . . . . . .  |
				    /_\
			    +-----------------+
			    |		      |
		       -------------	    -------
		      |Texture_Proxy|<>----|Texture|
		       -------------	.   -------
					.
				    contains one

As you can see, with this common interface, we can use Proxies as if they were the real object (the class Texture here).

And now, let's examine some tasty chunks of source code for all this:


	// Texture.h

	class Texture_Base {
		// ...
	public:
		Texture_Base( char *filename );
		virtual ~Texture_Base();
		// ...
		virtual unsigned *pixelmap() const = 0

	};

	class Texture : public Texture_Base() {
	public:
		// ...
		// these method is specific to this class
		void unpack_data();
		bool is_unpacked() const;

		// Texture implements pixelmap;
		unsigned *pixelmap() const;
	};

	class Texture_Proxy : public Texture_Base {
		Texture *text;
	public:
		Texture_Proxy( char *filename );
		// ...
		unsigned *pixelmap() const;
	};

	// Texture.cc

	// We take a closer look at the implementation
	// of the Proxy object

	Texture_Proxy::Texture_Proxy( char *filename )
	{
		text = new Texture( filename );
	}

	// unpack data whenever required
	unsigned *Texture_Proxy::pixelmap() const
	{
		if ( text->is_unpacked() )
			text->unpack_data();
		return text->pixelmap();
	}

Of course, this is not the most efficient way to handle this problem - using a texture cache is obviously better and we didn't took care here about the way useless unpacked data is flushed - but this was only an example and I'm sure that you'll find lots of other exciting applications for this Pattern!

05 - Other Structural Patterns

There are much more Structural Patterns but I'm kinda busy for the moment and I miss time to cover them in this document. Drop me email if you want to see other Patterns developed in your favorite column!

For your information, here's a brief description of some other Structural Patterns:

- Adapter, the interface of an object
- Bridge, the implementation of an object
- Facade, the interface of a sub-system
- Flyweight, the storage cost of objects

brioche of the aspirine d-zign international demo brigade