Click here to Skip to main content
11,795,568 members (81,390 online)
Click here to Skip to main content

Tagged as

The Dynamic Registry Factory

, 6 Jan 2010 CPOL 10.6K 82 9
Rate this:
Please Sign up or sign in to vote.
The idea was to write the system in such a way that every format will have a common interface, and adding (or removing) a new format will not a affect the existing code at all.



This paper will discuss a specic design problem I've come across in the course of a hobby programming project, and the solution I have worked out for it. The solution can be viewed as a specic implementation of what can be considered as a far more general design pattern, which I've decided to call "The dynamic registry factory" (I'm open to suggestions of better names at this point).

The suggested solution will be introduced with thorough explanation of its ins and outs. I will of course admit it is not perfect - it can surely be tweaked and generalized further, but this solution and implementation demonstrate the general idea very well, and account for a good showcase.

The Problem

I had to write a program that will be able to handle many different file formats of various types (MP3, WAV, BMP, etc..) in a very robust, general, and easily extensible manner. The idea was to write the system in such a way that every format will have a common interface, and adding (or removing) a new format will not a affect the existing code at all.

The solution suggested in this paper answers all of the presented requirements, and more. It supports a subset of the original interface: Just enough functionality to allow us to name the correct file format - much like the file command under Linux. It is of course possible to extend this interface at will.

Suggested Design

Known Formats

Figure 1: KnownFormat and FormatMP3 class diagrams.

Every implemented file format in the system has to implement a common KnownFormat interface. This interface supports a single method to retrieve the name of the format.

Every implementing class (FormatMP3 implementation is included as an example) will throw a WrongFormatException exception if the given file does not match the implemented format. The construction succeeds if and only if the given file is in the correct format.

Factories for Known Formats

Figure 2: KnownFormatAbstractFactory and KnownFormatTemplatedFactory class diagrams.

The classic factory design pattern is put to good use here: KnownFormatAbstractFactory defines the common interface for any factory class that is able to generate a KnownFormat object upon receiving a filename. We supply a generic (templated) implementation of a factory for any KnownFormat, with two very useful MACROs that will be introduced in the implementation chapter. The KnownFormatTemplatedFactory is templated on a concrete file format type and provides a functionality of creating a new object of that KnownFormat upon invocations of the create() method. It implements the KnownFormatAbstractFactory interface for an arbitrary KnownFormat implementation.

The Dynamic Registry Factory

Figure 3: KnownFormatFactory class diagram

The KnownFormatFactory is the implementation of the dynamic registry factory. Through invocation of the addFormat() method, which is essentially the gateway to the registration process, it allows easy registration of new supported formats at any given time, with incredible ease of use and without affecting any existing code (using the aforementioned two macros introduced below, in the implementation section). Once the create() method is invoked, the factory goes over all registered formats and attempts to generate a new KnownFormat object through them. An UnknownFormatException will be thrown if the file format could not be matched with any supported file format.


As you have seen, the KnownFormatFactory class allows for any concrete format factory to register on the fly, and the KnownFormatTemplatedFactory allows automatic code generation of a factory for any concrete FileFormat. Combining these two facts, we are able to carry out the registration process by using the two following macros:

// taken from knownformat templatedfactory.h
// include folloing macro within class definition 
#define DECLAREFORMAT(T) const static bool  - 
// inc lude following macro in implementat ion file 
#define IMPLEMENTFORMAT(T) const bool T:: - 
        KnownFormatFactory :: inst ( ) . addFormat (
        KnownFormatAbsFactoryHandle (
        new KnownFormatTemplatedFactory<T>()))

Exploiting the fact that static const members are initialized on the loading of the program, we define a boolean member, which registers with the KnownFormatFactory upon initialization. This nifty trick allows every concrete format to register by using these two very simple macros. To illustrate further, heres how FormatMP3 is implemented:

//  taken from formatmp3.h
class FormatMP3 : public KnownFormat {
     // ...
     private : 
         DECLARE_FORMAT ( FormatMP3 ); 

//  taken from

This is crystal clear, simple, maintainable, and easily reusable. The rest of the implementation can be found included with this paper, and is more or less straightforward.

Future Directions

Thread Safety

The propsed design is not thread safe. In order for the design to function correctly in a multi-threaded environment, some minor changes must be made to the KnownFormatFactory class:

  • A thread safe singleton implementation should be used.
  • Proper locking mechanisms should be used within its member functions.


To conclude, I would like to point out the pros and cons of the suggested technique.


  • Adding support for new formats does not require altering existing code nor recompilation.
  • Adding support for a new format is transparent for all users.
  • It is possible to load formats on the fly, even in a lazy manner (only adding formats when needed). It is possible to load shared (dynamically linked) libraries containing more formats as well.
  • Very scalable design.
  • It is possible (and will not require much effort) to change the registration process such that every format will be registered with its name, to allow lookup of specific formats. For example, this feature can be utilized to implement a save option with many supported formats.


  • This solution forces all supported file formats to implement the same interface, which can be limiting at times (although one could use dynamic cast, it is surely not recommended).

Feel free to observe the enclosed implementation. It contains more details that were omitted from the article itself, but may provide better insight of the proposed design.

Source Code


#ifndef _KNOWN_FORMAT_H_ 
#define _KNOWN_FORMAT_H_

#include <string> 
* This is an abstract class (interface) representing
* a file whose format is known and can be identified.
* It is possible to easily extend this interface in
* the future, to offer broader functionality. 
class KnownFormat {
    public : 
        virtual std::string getFormatName () const = 0; 
        virtual ~KnownFormat () {}; 
#endif // _KNOWN_FORMAT_H


#ifndef _FORMAT_MP3_
#define _FORMAT_MP3_ 

#include "knownformat.h" 
#include "knownformattemplatedfactory.h" 

#include <string>
* This class implements the MP3 file format . 
class FormatMP3 : public KnownFormat {
        FormatMP3 (const std::string &filename );
        virtual std::string getFormatName ( ) const ; 
        const static std::string MAGIC; 
        const static std::string NAME; 
        // declare registration
        DECLARE_FORMAT (FormatMP3); 
#endif // _FORMAT_MP3_

#include "formatmp3.h" 
#include "wrongformatexception.h" 
#include "filenotfoundexception.h" 

#include <vector>
#include <fstream> 

// just implement the registration.

const std::string FormatMP3::MAGIC = "ID3" ; 
const std::string FormatMP3::NAME = "MP3" ; 

FormatMP3::FormatMP3 (const std::string &filename) {
    std::ifstream ifs (filename.c_str());
    if (!ifs) 
        throw FileNotFoundException (filename);
    std::vector<char> read (MAGIC.size(), 0); [0], read.size()); 
    if (std::string(&read[0], read.size()) != MAGIC)
        throw WrongFormatException (filename, NAME); 

std::string FormatMP3::getFormatName () const {
    return NAME; 



#include "types.h" 
#include "knownformat.h" 

#include <string> 

* This is an abstract class (interface) representing
* the common interface to any factory class able to
* create a KnownFormat instance from a given filename.
class KnownFormatAbstractFactory {
        virtual KnownFormatHandle create ( const std::
            string &filename ) const = 0; 

        virtual ~KnownFormatAbstractFactory ( ) {}




#include "types.h"
#include "knownformat.h"
#include "knownformatfactory.h"
#include "knownformatabstractfactory.h"

#include <string />

// include following macro within class definition
// include following macro in implementation file
    KnownFormatFactory::inst().addFormat( \
    KnownFormatAbsFactoryHandle(new KnownFormatTemplatedFactory<t />()))

 * Templated implementation of KnownFormatAbstractFactory
 * The only requiremnt of type T is to have a constructor
 * with the filename as a parameter.
 * The constructor may throw WrongFormatException. 
template <typename T>
class KnownFormatTemplatedFactory : public KnownFormatAbstractFactory {
        virtual KnownFormatHandle create (const std::string &filename) const {
            return KnownFormatHandle(new T(filename));	




#include "types.h"
#include "knownformatabstractfactory.h"

#include <vector>
#include <string>

 * This class is a singleton, holding an isntance of 
 * every format factory in the system.
 * Given a filename it is able to go over all known 
 * formats and generate a KnownFormat object. 
class KnownFormatFactory {
        bool addFormat (KnownFormatAbsFactoryHandle factory);

        KnownFormatHandle create (const std::string &filename) const;

        static KnownFormatFactory &inst ();

        typedef std::vector<KnownFormatAbsFactoryHandle> FactoryVector;
        FactoryVector m_factories;

        KnownFormatFactory () {}
        KnownFormatFactory (const KnownFormatFactory &f) {}
        KnownFormatFactory &operator= (const KnownFormatFactory &f);


#include "knownformatfactory.h"
#include "wrongformatexception.h"
#include "unknownformatexception.h"

bool KnownFormatFactory::addFormat (const KnownFormatAbsFactoryHandle factory) {
    return true;

KnownFormatHandle KnownFormatFactory::create (const std::string &filename) const {
    for (FactoryVector::const_iterator it=m_factories.begin();it != m_factories.end();++it) {
        try {
            return (*it)->create(filename);
        catch (const WrongFormatException &) {
            // next one..
    throw UnknownFormatException(filename);

KnownFormatFactory &KnownFormatFactory::inst () {
    static KnownFormatFactory instance;
    return instance;


#ifndef __TYPES_H__
#define __TYPES_H__

#include <tr1/memory>

// forward decl
class KnownFormat;
class KnownFormatAbstractFactory;

// defining the common handlers (shared pointers)
typedef std::tr1::shared_ptr<KnownFormat>
typedef std::tr1::shared_ptr<KnownFormatAbstractFactory>

#endif // __TYPES_H__



#include <string>
#include <stdexcept>

 * This exception will be thrown when a given filename
 * could not be found.
class FileNotFoundException : public std::runtime_error {
        FileNotFoundException (const std::string &filename) 
            : std::runtime_error("Could not find: " + filename) {}




#include <string>
#include <stdexcept>

 * This exception should be thrown by a KnownFormat 
 * implementation when the given filename isn't of 
 * that specific format.
class WrongFormatException : public std::runtime_error {
        WrongFormatException (const std::string &filename, const std::string &formatname) 
            : std::runtime_error("File " + filename + " does not match format " +
                formatname) {}




#include <string>
#include <stdexcept>

 * This exception will be thrown by the 
 * KnownFormatFactory class when a filename is of an 
 * unknown format.
class UnknownFormatException : public std::runtime_error {
        UnknownFormatException (const std::string &filename) 
            : std::runtime_error("File " + filename + " is of an unknown format") {}


#include "types.h"
#include "knownformat.h"
#include "knownformatfactory.h"

#include <string>
#include <vector>
#include <iostream>
#include <stdexcept>

int main () {
    std::vector<std::string> f;

    std::vector<std::string>::iterator it = f.begin();
    std::vector<std::string>::iterator end = f.end();
    for (;it != end;++it)
        try {
            KnownFormatHandle formatted = 
            std::cout << *it << " is: " <<
                formatted->getFormatName() <<
    catch (const std::exception &e) {
        std::cout << "[info] " << e.what() << std::endl;

    return 0;


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Roman Kecher
Software Developer
Israel Israel
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralMy vote of 2 Pin
Alexandre GRANVAUD7-Jan-10 21:38
memberAlexandre GRANVAUD7-Jan-10 21:38 
GeneralArticle's motivation and goals. Pin
Roman Kecher8-Jan-10 1:38
memberRoman Kecher8-Jan-10 1:38 
GeneralMy vote of 1 Pin
haadikhan27-Jan-10 8:49
memberhaadikhan27-Jan-10 8:49 
GeneralRe: My vote of 1 Pin
Pete O'Hanlon7-Jan-10 9:22
mvpPete O'Hanlon7-Jan-10 9:22 
If you have no reason for a 1 vote, then don't vote it. Honestly, people like you make me sick - you contribute nothing, but think you have the right to trash others.

"WPF has many lovers. It's a veritable porn star!" - Josh Smith

As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.

My blog | My articles | MoXAML PowerToys | Onyx

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151002.1 | Last Updated 6 Jan 2010
Article Copyright 2010 by Roman Kecher
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid