Mirror reflection library 0.5.13

Factory generator utility

Introduction

The factory generator utility allows to easily create implementations of object factories at compile-time by using the meta-data provided by Mirror. By object factories we mean here classes, which can create instances of various types (Products), but do not require that the caller supplies the parameters for the construction directly. Factories pick or let the application user pick the Product 's most appropriate constructor, they gather the necessary parameters in a generic, application-specific way and use the selected constructor to create an instance of the Product.

Obviously the most interesting feature of these factories is, that they separate the caller (who just needs to get an instance of the specified type) from the actual method of creation which involves choosing of right constructor and supplying the required parameters, which in turn can also be constructed or supplied in some other way (for example from a pool of existing objects).

This is useful when we need to create instances of (possibly different) types having multiple constructors from a single point in code and we want the method of construction to be determined by parameters available only at run-time.

Here follows a brief list of examples:

The factories generated by this utility can then be used for example for the implementation of the Abstract factory design pattern, where even the exact type of the created object is not known.

Because the factory classes are created by a generic meta-program at compile-time a good optimizing compiler can generate source code, which is as efficient as if the factories were hand-coded. This however depends on the implementation of the application-specific parts that are supplied to the factory generator.

Principles

As we mentioned in the introduction, the factory must handle two important tasks during the construction of an instance:

The implementation of these tasks is also the most distinctive thing about a particular factory. The rest of the process is the same regardless of the Product type. This is why the factory generator utility provides all the common boilerplate code and the application only specifies how a constuctor is selected and how the arguments are supplied to it.

Furthermore there are two basic ways how to supply a parameter value:

In order to create a factory, the application needs to supply the factory generator with two template classes with the following signature:

  template <class Product, class SourceTraits>
  class constructor_parameter_source;

The first one is referred to as a Manufacturer and is responsible for the creation of new parameter values. The second template is referred to as Suppliers and is responsible for returning of an existing value.

One of the specializations of the Manufacturer template, namely the one having the void type as Product is referred to as Manager. This Manager is responsible for the selecting of the constructor that to be used.

Both of these templates have the following parameters:

Whether these sources (Manufacturer or Suppliers) are going to be used for the supplying of a constructor parameter and if so, which of them, depends on the selected constructor:

The Manufacturer

The application-defined Manufacturer template should have several distinct specializations, which serve for different purposes.

As mentioned before, a Manufacturer with the void type as Product serves as a manager which is responsible for choosing the constructor that is ultimately to be used for the construction of an instance of the Product. This means that besides the regular Manufacturer which in fact creates the instances, there is one instance of the Manager for every Product in the generated factory. The Manager has also a different interface then the other Manufacturers.

Other specializations of the Manufacturer should handle the creation of values of some special types (like the native C++ types; boolean, integers, floating points, strings, etc), considered atomic (i.e. not eleborated) by the factory. Values of such types can be input directly by the user into some kind of UI, they can be converted from some external representation like the value of row/column in a database dataset, or a value of an XML attribute, etc.

The default implementation of the Manufacturer is for elaborated types and it uses a generated factory to recursively create instances of the constructor parameters.

The Suppliers

The Suppliers template is responsible for returning existing instances of the type passed as the Product parameter. Depending on the specific factory and the Product, the suppliers may or may not have means to get instances of that particular Product type and should be implemented accordingly. If there are multiple possible sources of values of a type then the specialization of Suppliers must provide some means how to select which of the external sources is to be used.

The parameter source traits

For additional flexibility both the Manufacturer and the Suppliers template have (besides the Product type they create) an aditional template type parameter called SourceTraits. This type is usually defined together with the Manufacturer and Suppliers and is passed to the instantiations of these templates by the factory generator when a new factory is created. The factory generator treats this type as opaque. If a concrete implementation of the parameter sources (Manufacturer and Suppliers) has no use for this additional parameter, the void type can be passed to the factory generator.

Factory and Factory Maker

The Manufacturers, the Suppliers, the SourceTraits and the boilerplate code common to all factories is tied together by the mirror::factory template, with the following definition:

  template <
          template <class, class> class Manufacturer,
          template <class, class> class Suppliers,
          class SourceTraits,
          typename Product
  > class factory
  {
  public:
      Product operator()(void);
      Product* new_(void);
  };

Perhaps a more convenient way how to create factories, especially when one wants to create multiple factories of the same kind (with the same Manufacturers, Suppliers and SourceTraits) for constructing different Product types is to use the mirror::factory_maker template class defined as follows:

  template <
          template <class, class> class Manufacturer,
          template <class, class> class Suppliers,
          class SourceTraits
  > struct factory_maker
  {
      template <typename Product>
      struct factory
      {
        typedef factory<Manufacturer, Suppliers, SourceTraits, Product> type;
      };
  };

Usage

The basic usage of the factory generator utility should be obvious from the above; It is necessary to implement the Manufacturer and the Suppliers templates (and possibly also the SourceTraits) and then use either the mirror::factory template directly or the mirror::factory_maker 's factory nested template to create an instantiation of a factory constructing instances of a Product type:

  // use the factory directly ...
  mirror::factory<my_manuf, my_suppl, my_traits, my_product_1> f1;
  my_product_1 x1(f1());
  my_product_1* px1(f1.new_());

  // ...
  // or use the factory_maker
  typedef mirror::factory_maker<my_manuf, my_suppl, my_traits> my_fact_maker;
  my_fact_maker::factory<my_product_1>::type f1;
  my_fact_maker::factory<my_product_2>::type f2;
  my_fact_maker::factory<my_product_3>::type f2;
  //
  my_product_1 x1(f1());
  my_product_1* px1(f1.new_());
  my_product_2 x2(f2());
  my_product_3* px3(f3.new_());

Tutorials and other resources

Here follows a list of references to other pages dealing with the factory generator utility in depth and also tutorials showing how to write the plugins (the Managers, Manufacturers and Suppliers) for the factory generator:

Existing Manufacturers and Suppliers

The Mirror library provides several working sample implementations of the Manufacturer and Suppliers templates. The following example shows the usage of the wx_gui_factory template with the factory generator utility in a simple wxWidgets-based application. The generated factory creates a wxDialog containing all necessary widgets for the selection of the constructor to be used and for the input of all parameters required by the selected constructor. Screenshots of dialogs generated by this implementation can be found here.


Copyright © 2006-2011 Matus Chochlik, University of Zilina, Zilina, Slovakia.
<matus.chochlik -at- fri.uniza.sk>
<chochlik -at -gmail.com>
Documentation generated on Fri Dec 16 2011 by Doxygen (version 1.7.3).
Important note: Although the 'boostified' version of Mirror uses the Boost C++ libraries Coding Guidelines and is implemented inside of the boost namespace, it IS NOT an officially reviewed and accepted Boost library. Mirror is being developed with the intention to be submitted for review for inclusion to the Boost C++ libraries.