Composer Pattern

Intent

A Composer is a structural pattern that may be used to employ composition when implementing an interface rather than using multiple inheritance.

In particular, member function name clashes may arise when a particular context object attempts to inherit and implement many different interfaces. In fact, the more interfaces that such an object inherits, the more likely that such a name clash will arise.

Such a clash can be a real show-stopper for large concrete implementation objects, and renaming the operations in one of the conflicting interfaces is not only impractical, but often impossible when using third party libraries.

The Composer pattern makes use of C++ member function pointers to solve this problem in a general way that does not require changing an interface.

Also Known As

There are no other known names for this pattern.

Motivation

Imagine an class named Context, which would use multiple-inheritance to implement the pure-virtual methods from two different classes Api1 and Api2 as shown in Figure 1.

Motivation 1
Figure 2

However, both of the interfaces Api1 and Api2 have an operation named foo() with the same signature. This creates ambiguity and the class Context cannot be implemented.

This problem can be solved by using composition, and this can be done generically by applying member function pointers and the C++ template facility.

First, we create the Composers as shown in Figures 2 and 3.

Motivation 2
Figure 2

Motivation 3
Figure 3

It is interesting to note that the individual Composers (Composer1 and Composer2) are associated with the interface that they implement, and are general enough to be used in other contexts. This is an improvement over a more context specific composition solution.

Finally, we show how the individual Composers are used by the a context in Figure 4.

Motivation 4
Figure 4

The first important feature to notice is that the Context (aContext) implements two member functions with signatures that match the Api1 and Api2 interface foo() operations.

The next important feature are the public operations that export references to the Api1 and Api2 interfaces to the application context.

The note containing the implementation code in Figure 4, illustrates some details of how a Context makes use of a Composer.

The initializers in the constructor aContext::aContext() illustrate how the (rather bizzare) C++ syntax for member function pointers is used to satisfy the constructors for _composer1 and _composer2. Also note that the first argument to each is a reference to the Context aContext using the *this syntax.

Finally, the operations void aContext::fooApi1() and void aContext::fooApi2() do the actual implementation work within the aContext class.

Applicability

What are the situations in which the design pattern can be applied? What are examples of poor designs that the pattern can address? How can you recognize these situations?

Structure

Structure
Figure 4

Participants

Client
While technically not a part of the Composer pattern, the Client represents an entity that invokes the operations of the Api class.
Composer
The Composer is an implementation of the Api, which converts each Api method/operation into a corresponding member function pointer call. For general reuse, the Context should be associated with the Api that it implements. This allows the Composer to be reused in many Contexts.

The Composer is implemented as a C++ template, which may be used in any Context specified by its ctxt template parameter.

Api
The Api is the interface that is implemented by the Composer to allow Contexts to use composition rather than mulitple inheritance.
Context
The Context is the software that implements the actual functionality of the Api through the member function callbacks that it implements and passes through the Composer constructor.

Collaborations

The Context implements the abstraction described by the Api interface. This abstract interface is defined so as to enable the Client to take advantage of different implementations of the Api through polymorphism. The Composer enables the Context to use composition rather than inheritance. The composition technique avoids issues with method name clashes. This is especially important when the Context implements many different Api interfaces of either the same or different type.

When the Client invokes the foo() operation of the Api, the foo() operation of the Composer is executed via polymorphism. The implementation of the foo() operation within the Composer invokes the associated member function pointer, which, in this case invokes the foo1() operation of the Context. It is this foo1() operation that actually implements the concrete operation.

Consequences

The Composer achieves its goals through the use of the C++ template mechanism and the use of member function pointers. This has several consequences.

The Composer pattern allows the user to vary implementations of the Api without resorting to modification of an Api. A Composer can be written once for a corresponding Api and reused in any Context.

Implementation

A Composer for an Api with many operations and many different function signatures is quite tedious to code. However, since the Composer is a write-once reuse many construct, it is usually well worth the effort.

The Composer lends itself to code generation, and it is conceivable that a Composer template could be generated directly from its corresponding Api header file.

Sample Code

api.h


#ifndef _apih_
#define _apih_

class Api {
    public:
        virtual void foo()=0;
	};

#endif

composer.h


#include "api.h"

template 
class Composer : public Api {
    public:
        typedef void    (ctxt::* fooOp)();
    private:
        ctxt&       _ctxt;
        fooOp       _fooOperation;
	public:
        Composer(   ctxt&   context,
                    fooOp   fooOperation
                    );
    private: // Api
         void foo();
	};

template 
Composer::Composer(   ctxt&   context,
                            fooOp   fooOperation
                            ):
        _context(context),
        _fooOperation(fooOperation)
        {
    }

template 
void Composer::foo() {
    (_context.*_fooOperation)();
    }

context.h


#ifndef _contexth_
#define _contexth_
#include "context.h"

class Context {
    private:
        Composer   _composer;

    public:
        Context();

    private:
        void	foo1();
    };

#endif

context.cpp


#include "context.h"
#include 

Context::Context():
        _composer(*this,&Context::foo1)
        {
    }

void Context::foo1() {
    printf("foo implementation!\n");
    }