Appendix 2: A Pattern Catalog

Architectural Patterns

Architectural patterns show common ways to organize subsystems.

Model-View-Control Architecture

Also called the Document-View or Model-View Architecture.

Problem

The presentation logic is volatile, while application data and logic is stable. If application data and logic depends on the user interface, then changes to the user interface will propagate necessitate changes to the application data and logic as well.

Solution

Application data-- implementations of the domain entities, events, descriptions, and roles described in the domain model-- are encapsulated in the Model subsystem.

Application logic-- implementations of the activity sequences represented in the business process model-- is encapsulated in the Model subsystem.

Presentation logic-- the user interface (control panels, windows, menus, etc.)-- is encapsulated in the View (output) and Control (input) subsystems.

The View subsystem depends on the Model and Control subsystems. The Control subsystem depends on the Model subsystem. None of these dependencies go the other way.

Structure

The Model subsystem usually interfaces with the Persistence subsystem so that application data can be saved to a database or file.

Behavior

Of course the View package may contain multiple windows and control panels that all need to be updated when the model is updated. We can solve this problem by introducing some sort of event notification mechanism.

Discussion

The Model-View-Control Architecture was popularized by the Smalltalk language. It is used extensively.

Layered Architecture

Also called Mud-to-Structure

Problem

A library or subsystem is composed of many classes that are highly technical and difficult to understand and use.

Solution

Introduce a layer of more abstract classes that hide the technical details of the lower layer. We can repeat this procedure as often as we like. The result is an N-layer architecture.

Structure

Behavior

Layer N methods call layer N - 1 methods, but not layer N - 2 methods.

Discussion

The layered architecture was popularized by UNIX.

The Internet Architecture consists of the following layers:

Application Layer
Transport Layer
Internet Layer
Network Layer
Data Link Layer
Physical Layer

The Multi-Tier architecture (described below) can be viewed as a multi-layered architecture.

The following layered architecture is typical of many business applications:

Clearly this is just an elaboration of the Model-View-Control architecture where Business Data means Application Data (model), Business Logic means Application logic (control), and User Interface means Presentation Logic (view).

The N-Tier Architecture

Problem

The Client-Server Architecture is the most popular design for distributed applications. As these applications became more complicated too many responsibilities were being assigned to the client or the server. This made these subsystems inefficient and less reusable.

Solution

We can combine the Layered Architecture with the Client-Server Architecture. Layers are called tiers in this context. Each tier runs as a separate program, possibly on different machines. The layers can communicate using standard protocols such as RMI, SOAP, HTTP, TCP/IP, etc.

Structure

The most common N-Tier Architecture is the Three-Tier Architecture:

Notice that this can be viewed as a variation of the Model-View-Control Architecture in which the role of the model is played by the database server, the role of the control is played by the application server, and the role of the view is played by the client.

Behavior

Discussion

A popular variation is the 3.5-Tier Architecture:

Open Architecture

Also called the Container-Component, Reflective, or Plug-N-Play architecture.

Problem

To increase the popularity of their product company A wants to allow third-party developers to create enhancements and sell or give them directly to A's customers. But how can the design of A's product anticipate what these enhancements will be?

Solution

Company A publishes an interface it expects third party developers to implement. The interface only specifies that in addition to their basic functionality, third party components (also called plug-ins) should be able to describe this functionality to A's product (called the Container Application).

Structure

Behavior

Discussion

All Java objects inherit the getClass() method from the Object base class. This method corresponds to the describe() method.

In Open Distributed Architectures such as CORBA or the Web Services Architecture the ability of components to describe their functionality to other components is called discovery.

Multi-Agent Architecture

Problem

Open architecture components need to provide higher levels of adaptability, mobility, discovery, and intelligence in order to support applications that exhibit emergent behavior or that need to function in volatile environments.

Solution

In a multi-agent architecture components become agents embedded in an environment. An agent is an active component that plays one or more roles in the environment. Each role perpetually executes a control loop such as:

1. Observe state of the environment
2. If environment state = goal state, then quit
3. Select an action
4. Perform action
5. Goto 1

An agent may observe all or part of the environment in step 1. This may involve observing what the other agents in the environment are up to.

Different agents may have different goals.

The action selected in step 3 depends on the observation made in step 1. It may also depend on the internal state of the agent. This internal state could be a simple one-bit memory or a complex knowledge base system.

Performing the action in step 4 modifies the state of the environment. It may also modify the agent's internal state and goals. The action may involve sending messages to other agents.

Structure

In the FIPA reference architecture the environment consists of interconnected platforms. A platform provides communication services as well as white page and yellow page services.

An agent may play many roles. Each role has its own control loop like the one described earlier. An agent merely acts as a job scheduler for these roles. Roles are also called behaviors.

Roles are often defined by the communication protocols in which they can participate. A protocol defines the types of message exchanges between various roles.

Behavior

Discussion

FIPA has defined a reference architecture for multi-agent systems. There are several implementations of the FIPA architecture, including JADE and Zeus. The Semantic Web Services Architecture (SWSA) is couched in the concepts of multi-agent architectures.

 

Creational Patterns

Factory Method

Also known as virtual constructor.

Problem

A class or framework can't anticipate the kind of objects it must create.

Solution

Structure

Behavior

Discussion

All products implement a common interface:

interface Product {...}

The creator class postpones decisions about what types of products are created by using a virtual constructor/abstract factory method:

abstract class Creator {
   //virtual constructor:
   abstract Product makeProduct();
   // etc.
}

A concrete creator replaces the abstract factory method with a concrete factory method. In this example the details of the concrete product are hidden as a private inner class:

class ConcreteCreator extends Creator {
   private class ConcreteProduct implements Product {...}
   Product makeProduct() { return new ConcreteProduct(); }
}

Generic Constructors

In C++ template parameters can represent constructors as well as classes, so generic constructors can be used to delay decisions about the types of products to create:

template<typename Product>
class Creator
{
public:
   // generic constructor:
   Product* makeProduct() { return new Product(); }
};

In this case there is no need to introduce an abstract Product base class. Here is how a client creates a concrete product:

Creator<ConcreteProduct> creator;
ConcreteProduct* p = creator.makeProduct();

Abstract Factory

Also called a kit.

Problem

An assembly can't anticipate the types of components it uses.

Solution

Structure

Behavior

Discussion

Assume abstract base classes are introduced for a family of related components/products:

class ComponentA {...};
class ComponentB {...};

An abstract factory/kit provides abstract factory methods for each of these components:

class Factory
{
public:
   virtual ComponentA* makeComponentA() = 0;
   virtual ComponentB* makeComponentB() = 0;
   // etc.
};

An assembly constructor can now be parameterized by a factory that makes the necessary components:

class Assembly
{
private:
   ComponentA* a;
   ComponentB* b;
   // etc.
public:
   Assembly(Factory* f)
   {
      a = f->makeComponentA();
      b = f->makeComponentB();
      // etc.
   }
};

Builder

Problem

We want to separate the construction of an assembly from the construction of its components.

Solution

Encapsulate the assembly construction process in a component called the director. Encapsulate the construction of the components in a component called the builder.

Structure

Behavior

Discussion

Builders are similar to abstract factories. There are two differences. First, the job of building the assembly is given to a component called the Director. Second, the components are created and added to the assembly by the builder.

Here is the abstract base class for all builders:

class Builder
{
protected:
   Assembly* a = 0;
public:
   virtual void addComponentA() = 0;
   virtual void addComponentB() = 0;
   // etc.
   Assembly* getAssembly() { return a; }
};

A concrete builder instantiates a concrete assembly and implements the methods for building and adding concrete components to this assembly:

class ConcreteBuilder: public Builder
{
private:
   class ConcreteComponentA: ComponentA { ... };
   class ConcreteComponentB: ComponentB { ... };
   class ConcreteAssembly: Assembly { ... };
public:
   ConcreteBuilder(){ a = new ConcreteAssembly(); }
   void addComponentA() { a->add(new ConcreteComponentA(); }
   void addComponentB() { a->add(new ConcreteComponentB(); }
};

The process for adding components to the assembly is implemented by the director:

class Director
{
public:
   void makeAssembly(Builder* b)
   {
      b->addComponentA();
      b->addComponentB();
      // etc.
   }
};

Here is how a client builds an assembly:

Builder* b = new ConcreteBuilder();
Director d;
d.makeAssembly(b);
Assembly a = b->getAssembly();

Singleton

Problem

Multiple instances of a class may not make sense or may create confusion.

Solution

Hide all constructors. Provide a static factory method that returns a pointer to the single instance of the class.

Structure
Behavior

Discussion

Assume an instance of the Manager class will be responsible for managing all components of an application. Having multiple managers could create confusion, so we hide all of the constructors. Java and C++ classes have a public implicit default constructor (i.e., a parameterless constructor) that must be made explicit and private. C++ classes also have an implicit copy constructor that must be made public.

class Manager
{
private:
   static Manager* theManager;
   Manager() { ... }
   Manager(const Manager& m) { }
   ~Manager() { }
public:
   // factory method:
   static Manager* makeManager()
   {
      if (!theManager) { theManager = new Manager(); }
      return theManager;
   }
   // etc.
};

Obviously the factory method and the pointer must be made static. In C++ memory must be allocated and initialized for the pointer separately:

Manager* Manager::theManager = 0;

Here is some sample client code:

Manager* m1 = Manager::makeManager();
Manager* m2 = Manager::makeManager(); // m1 == m2

delete m1; // error, destructor can't be called here
m1 = new Manager(); // error, constructor can't be called here

Assume the following function is declared:

void display(Manager m) { ... }

However calling the function isn't allowed:

display(*m1); // error, copy constructor can't be called here

Managers must be passed by reference:

void display(Manager& m) { ... }

Interning

A variation of the Singleton is Intern. Assume a class of

class Symbol
{
private:
   string name;
   Symbol()
  
   // etc.
};

class Intern
{
private:
   map<string, Symbol> symbols;
public:
   Symbol makeSymbol(string name)
   {
      map<string, Symbol>::iterator p;
      p = symbols.find(name);
     

Prototype

Smart factory methods.

Problem

We can't anticipate the types of the objects we wish to create at runtime.

Solution

The Prototype Pattern is like the factory method pattern. Instead of an abstract factory method a concrete factory method builds products based on product descriptions such as class names.

The basic idea is simple, although it sounds complicated. A Product base class maintains a static table that associates product descriptions with product prototypes. The factory method merely searches the table for a prototype. It then asks the prototype to clone itself and returns the clone.

Structure

 

Behavior

Discussion

 

Behavioral Patterns

The Publisher-Subscriber Pattern

Publishers are also called senders, observables, subjects, broadcasters, and notifiers. Subscribers are also called receivers, listeners, observers and callbacks.

Problem

Various monitors need to be notified when a device changes state, but the number and types of monitors can vary dynamically. We want to avoid polling, and we don't want to make assumptions in the device code about the numbers and types of monitors.

Solution

The device should maintain a list of pointers to registered monitors. Monitors can be different, but each must implement the same interface, which includes an update() function that the device will call when it changes state. The list of monitor pointers can be managed by a reusable Publisher base class. An abstract Subscriber base class defines the interface monitors must implement.

Structure

Subscriber is an abstract class because update() is a pure virtual function that will be implemented differently in different derived classes. Alternatively, we could have stereotyped Subscriber as an interface.

Behavior

Assume two monitors subscribe to a device. When the device changes state, monitor1.f() and monitor2.g() must be called:

Discussion

Pattern catalog entries don't usually include implementations, because they are meant to be language independent. It is the programmer's job to provide the implementation. Some patterns are so useful, they are provided in well known libraries. For example, publisher and subscriber classes are provided in the Java utility package, where they are called Observable and Observer. Specializations of publisher and subscriber classes are also provided in the Microsoft Foundation Class library, where they are called CDocument and CView, and IBM's Visual Age library, where they are called Notifier and Subscriber. Unfortunately, the standard C++ library doesn't include Publisher and Subscriber, so we'll have to implement them ourselves. There are many approaches, we follow one loosely based on the Java implementation.

pubsub.h

We place the publisher and subscriber class declarations in a header file called pubsub.h. Here is the structure of the file:

/*
 * File:            pop\util\pubsub.h
 * Programmer:      Pearce
 * Copyright (c):   2000, all rights reserved.
 */
#ifndef PUBSUB_H
#define PUBSUB_H
#include <list>  // for our subscriber list
using namespace std;
class Publisher; // forward reference

class Subscriber { ... };
class Publisher { ... };

#endif

In addition to a do-nothing virtual destructor, the subscriber interface contains a pure virtual update function. To allow for the possibility that a subscriber might subscribe to multiple publishers, we pass a pointer to the notifying publisher. To allow messages to be sent from the publisher, we provide an optional generic "message" pointer:

class Subscriber
{
public:
  virtual ~Subscriber() {}
  virtual void update(Publisher* who, void* what = 0) = 0;
};

A publisher maintains a list of pointers to subscribers. Monitors implementing the subscriber interface can add themselves to the list using subscribe(), and remove themselves using unsubscribe(). Devices can call the update() function of each registered monitor by calling notify(). A client may need to change the state of a device without notifying the monitors. This can be done by first setting the notifyEnabled flag to false.

class Publisher
{
public:
   Publisher() { notifyEnabled = true; }
   virtual ~Publisher() {}
   void subscribe(Subscriber* s) { subscribers.push_back(s); }
   void unsubscribe(Subscriber* s) { subscribers.remove(s); }
   void notify(void* what = 0, Subscriber *s = 0);
   void setNotifyEnabled(bool flag) { notifyEnabled = flag; }
   bool getNotifyEnabled() const { return notifyEnabled; }
private:
   list<Subscriber*> subscribers;
   bool notifyEnabled;
};

pubsub.cpp

Including the implementation of notify() in the Publisher class declaration would make it inline, but some compilers won't allow inline functions containing iterative statements. Therefore, we move the implementation to a file called pubsub.cpp. We must not forget to include pubsub.h in this file:

/*
 * File:            pop\util\pubsub.cpp
 * Programmer:      Pearce
 * Copyright (c):   2000, all rights reserved.
 */
#include "pubsub.h"

Here is our implementation of notify(). Notice that notifyEnabled is automatically set to true at the end of the function. This protects against clients who may forget to set the flag back to true after setting it to false. The notify function has two parameters. The first parameter is an optional, generic message. The second parameter points to a subscriber that is not to be notified. This feature is useful when a subscriber wants to send a message to its fellow subscribers through the publisher. In this case the sender calls the notify function passing a message and its address. Every subscriber receives the message except the sender. Recall that both parameters have the null pointer as a default argument.

void Publisher::notify(void* what, Subscriber* s)
{
   if (notifyEnabled)
   {
      list<Subscriber*>::iterator p;
      for(p = subscribers.begin(); p != subscribers.end(); p++)
         if (*p != s) (*p)->update(this, what);
   }
   notifyEnabled = true;
}

Pluggable Adapter

Problem

The behavior of a function or method needs to be alterable.

Solution

Some languages allow functions to be treated as data. In this case we can declare functions to be fields instead of methods. Of course fields can be updated.

Structure
Behavior

Discussion

Assume objects are to represent function tests. By making the function to be tested a member variable rather than a member function we can reuse the same test class.

Using Function Pointers in C++

The run method compares the expected output-- as determined by the oracle-- with the actual output-- as determined by the function pointer. If one discrepancy is found, the test fails:

class Test
{
private:
   int (*fun)(int); // pluggable adapter
   map<int, int> oracle;
public:
   Test(int (*fun)(int)) { this->fun = fun; }
   void setFun(int (*fun)(int)) { this->fun = fun; }
   void add(int input, int output) { oracle[input] = output; }
   bool run()
   {
      bool pass = true;
      map<int, int>::iterator p;
      for(p = oracle.begin(); pass && (p != oracle.end()); p++)
         pass = pass && (p->second == fun(p->first));
      return pass;
   }
};

Assume two functions are declared:

int fact(int n)
{
   int result = 1;
   for(int i = 1; i <= n; i++) result *= i;
   return result;
}

int tri(int n)
{
   int result = 0;
   for(int i = 1; i <= n; i++) result += i;
   return result;
}

This function tests both functions:

void testAllFuns()
{
   Test factTest(fact);
   factTest.add(3, 6);
   factTest.add(4, 24);
   factTest.add(5, 120);
   Test triTest(tri);
   triTest.add(3, 6);
   triTest.add(4, 10);
   triTest.add(5, 15);
   cout << "pass = " << (factTest.run() && triTest.run()) << endl;
}

This code can be improved by using the composite pattern to distinguish between composite tests (called test suites) and primitive tests (called test cases).

Another improvement is to make the TestCase class a template parameterized by the domain and range of the pluggable adapter.

Using Functors in C++

Objects representing functions are called functors:

class Functor
{
private:
   int (*fun)(int);
public:
   Functor(int (*fun)(int) = 0) { this->fun = fun; }
   int operator()(int x)
   {
      if (!fun) throw exception("function not defined");
      return fun(x);
   }
};

Here is a modified version of Test that uses functors:

class Test
{
private:
   Functor fun;
   map<int, int> oracle;
public:
   Test(Functor fun) { this->fun = fun; }
   void add(int input, int output) { oracle[input] = output; }
   bool run()
   {
      bool pass = true;
      map<int, int>::iterator p;
      for(p = oracle.begin(); pass && (p != oracle.end()); p++)
         pass = pass && (p->second == fun(p->first));
      return pass;
   }
};

Using Reflection in Java

Structural Patterns

The Facade Pattern

Problem

A single dependency arrow running from package A to package B actually represents many dependency arrows running from the classes of A to the classes of B. This can lead to content coupling between A and B-- A needs to know too much about the contents of B.

Solution

Introduce a facade class in the provider package. This serves as a kind of gateway from client packages to the classes in the provider package. The implementer of the provider package is free to change the content of his package. This will necessitate changes to the facade, but not to the client packages.

Structure

Behavior

Discussion

The front controllers of web applications are facades.

The Mediator Pattern

Problem

The dependencies between classes within a package can become tangled. For example, if a package contains N classes and if each class depends on every other class, that leads to N! dependencies that must be maintained.

Solution

A mediator is like a virtual post office. If class A wants to send a message to class B, it posts the message to the mediator which either forwards the message to B or places the message in B's message queue where it can be retrieved if and when B needs it.

Structure

Behavior

Discussion

Brokers and dispatchers are mediators.

The Composite Pattern

Problem

Trees are commonly used to represent assemblies and other types of hierarchies.

Solution

The Composite Pattern introduces an abstract Component interface. There are two types of components: primitive or simple components and composite components (also called assemblies or aggregates). A composite component maintains a list of references (or copies) of its parts or children. These parts may be primitives or composites.

Structure

Behavior

Discussion

The following Java implementation introduces Component as an empty interface:

interface Component { }

Alternatively, the Component base class could maintain a reference to its parent:

class Component {
   protected Composite parent = null;
   // etc.
}

Primitive components are generics that can contain any type of data:

class Primitive<Data> implements Component {
   private Data data;
   public Primitive(Data data) {
      this.data = data;
   }
   public Data getData() { return data; }
   public void setData(Data data) { this.data = data; }
}

A composite maintains a set of children which may be primitives or composites:

public class Composite implements Component {
   private Set<Component> children = new HashSet<Component>();
   public void add(Component child) { children.add(child); }
   public void remove(Component child) { children.remove(child); }
   public Iterator iterator() { return children.iterator(); }
};

Here's some sample client Code:

      Primitive<String> leaf1 = new Primitive<String>("Leaf 1");
      Primitive<String> leaf2 = new Primitive<String>("Leaf 2");
      Primitive<String> leaf3 = new Primitive<String>("Leaf 3");
      Composite parent1 = new Composite();
      Composite parent2 = new Composite();
      parent1.add(leaf1);
      parent1.add(leaf2);
      parent2.add(parent1);
      parent2.add(leaf3);

Here is a drawing of the tree the client constructed:

The Bridge Pattern

Handle-Body

Problem

Inheritance hierarchies can be hierarchies of concepts or hierarchies of implementations. For example:

Mixing concepts with implementations can lead to hierarchies that are confusing and difficult to maintain.

Solution

Create two hierarchies: a conceptual hierarch and a hierarchy of implementations. The base of the implementation hierarchy is an Implementer interface. Use delegation to connect the two hierarchies:

Structure

Behavior

Discussion

Assume we want to define a portable GUI library. Our conceptual hierarchy might use the Composite Pattern to define a conceptual hierarchy of GUI components:

The draw() methods in the subclasses call upon protected utility methods inherited from the component base class:

class Button: public Component
{
private:
   string label;
public:
   void draw()
   {
      drawRectangle();
      drawText(xc, yc, label);
   }
};

The protected utility methods in the Component base class delegate to a private peer that implements a utility interface:

Here's the interface:

class ComponentImplementer
{
public:
   virtual void drawRectangle(int xc, int yc, int h, int w) = 0;
   virtual void drawText(int xc, int yc, string text) = 0;
};

Here's the complete code for the conceptual Component base class:

class Component
{
private:
   ComponentImplementer* peer;
protected:
   int height, width;
   int xc, yc; // co-ordinates of upper left corner
   ComponentImplementer* getPeer() { return peer; }
   void setPeer(ComponentImplementer* peer)
   {
      this->peer = peer;
   }
   // some utilities:
   void drawRectangle()
   {
      peer->drawRectangle(xc, yc, height, width);
   }
   void drawText(int xc, int yc, string text)
   {
      peer->drawText(xc, yc, text);
   }
public:
   Component(ComponentImplementer* peer = 0)
   {
      xc = yc = 0;
      height = width = 150;
      this->peer = peer;
   }
   virtual void draw() = 0;
};


Suppose X-Kit and Y-Lib are two libraries for creating platform-dependent GUIs. For each library we will need to provide an implementation of the Implementer interface. This can be regarded as a special case of the Adapter Pattern:

class XComponent: public ComponentImplementer
{
public:
   void drawRectangle(int xc, int yc, int h, int w)
   {
      // X-kit specific code goes here
   }
   void drawText(int xc, int yc, string text)
   {
      // X-kit specific code goes here
   }
};

The Adapter Pattern

Problem

A component exists that provides the functionality required by a client, but doesn't implement the interface expected by the client.

Solution

Create an adapter that sits between the client and the component. The adapter translates client requests into a messages understood by the client and vice-versa.

Structure

The adapter can inherit from the component:

Or the adapter can delegate to the component:

Behavior

Discussion

The client expects a component that implements the IComponent interface:

class Client {
   private IComponent component;
   public task() {
      component.serviceA();
      component.serviceB();
   }
}

Where:

interface IComponent {
   void serviceA();
   void serviceB();
}

A particular component provides the functionality needed by Client, but not the interfaces:

class Component {
   void serviceX() { /* serviceA functionality */ }
   void serviceY() { /* serviceB functionality */ }
}

An Adapter implements the IComponent interface by invoking inherited Component methods:

class Adapter extends Component implements IComponent {
   public void serviceA() { serviceX(); }
   public void serviceB() { serviceY(); }
}

Alternatively, delegation can be used:

class Adapter implements IComponent {
   private Component component = new Component();
   public void serviceA() { component.serviceX(); }
   public void serviceB() { component.serviceY(); }
}