Click here to Skip to main content
Click here to Skip to main content

Templates for Design Patterns

By , 31 Jan 2006
 

Introduction

Any Computer Science student at any university will, at some point, be faced with Design Patterns. Design Patterns are generic principles or best practices in software development. This article is not an introduction to Design Patterns, since others have already covered that in longer and better written articles. Instead, this article deals with implementing and re-using C++ templates when thinking Design Patterns.

Why use templates for Design Patterns?

The basic idea is to split up in functionality and interaction. By this, I mean we are able to implement a fully working class, e.g., a TCP/IP class, and at some point decide to use it as a singleton in one application and through a factory in another application. Using templates, the same base class can be used for either application without writing derivates and only adding a one-liner.

Singleton

Singleton is the most primitive Design Pattern ever made. The Singleton Design Patterns is a buzz-word for a global variable, a variable reachable from all other code. In C++, we could write the following code to generate a simple singleton:

class my_singleton
{
private:
 std::string my_string;
public:
 my_singleton() : my_string("foo bar bash") {}

 static my_singleton &instance()
 {
  static my_singleton global_instance;
  return global_instance;
 }
 
 std::string get_string() { return my_string; }
};

Calling the global singleton to obtain access to the associated string is done as follows:

...
cout << my_singleton::get_instance().get_string() << endl;

This is fairly simple and straightforward to implement and use. What happens when you want to refactor your code, or by some chance you learn that singleton is not the solution to all your prayers? Or, what if the code you work with to make a singleton is third party? Using the templated design pattern library, you are able to refactor code and change the design without having to worry about this. It's quite easy to create a singleton and use it, just watch and learn:

class third_party_code
{
public:
 third_party_code();
 bool execute_heavy_code();
};
typedef template_pattern::singleton<third_party_code> global_third_party_code;

In the above snippet, the class third_party_code is supplied by an external developer, and we do not have access or rights to alter the code. Instead, we declare a type name global_third_party_code which is an alias for our singleton instance globalizing the third_party_code instance. Using the singleton is done as follows:

...
if ((*global_third_party_code()).execute_heavy_code())
{
 ...
}

The library supplied with this article supports a simple implementation of the Singleton pattern, and does not handle the multitude of issues that may arise as a side effect of the Singleton pattern.

Implementing the singleton in the primitive case, i.e., with no mutex guarding against multi-threading, is shown in this code snippet:

...
template <class T><CLASS T> class singleton
{
  public:
    T & instance()
    {
      static T object;
      return object;
    }
    T & operator* ()
    {
      return instance();
    }
};
...

As for whiter the singleton Design Patterns is a good design choice or not is left for others to decide. However, it may come in handy in some cases. A weapon to kill singletons is injection.

Factory

In contrast to the Singleton Design Pattern, we now take a look at the Dactory Design Pattern. The basic idea of the Factory Design Pattern is to have a central repository for instantiating objects implementing a given interface. Having the instantiation in a central location makes it easy to swap components, e.g., change the real database object with a stub object that doesn't persist information in the database. A straightforward way of using this Factory Design Pattern is shown below:

class data_source
{
public:
 virtual std::vector<std::string> get_string_rows(std::string query) = 0;
 virtual void put_string_rows(const std::vector<std::string> data, 
                              const std::string query) = 0;
};

class database_data_source
{
public:
 database_data_source() { (*db_singleton()).prepare(); }
 virtual std::vector<std::string> get_string_rows(std::string query) { ... }
 virtual void put_string_rows(const std::vector<std::string> data, 
                              const std::string query) { ... };
};

class data_source_factory
{
public:
 static data_source * create()
 {
  return new database_data_source;
 }
};

void do_stuff()
{
 data_source * ds = data_source_factory::create();
 ...
 delete ds;
}

Obviously, this is nice and very easy to read. Changing this to some more generic code, using the Design Pattern template library, we get the following code, which is shorter and easier to read:

class data_source
{
public:
 virtual std::vector<std::string> get_string_rows(std::string query) = 0;
 virtual void put_string_rows(const std::vector<std::string> data, 
                              const std::string query) = 0;
};

class database_data_source
{
public:
 database_data_source() { (*db_singleton()).prepare(); }
 virtual std::vector<std::string> get_string_rows(std::string query) { ... }
 virtual void put_string_rows(const std::vector<std::string> data, 
                              const std::string query) { ... };
};

typedef template_patterns::factory<data_source, 
        database_data_source> data_source_factory;

void do_stuff()
{
 data_source * ds = data_source_factory::create();
 ...
 delete ds;
}

Again, the advantage is the flexibility within the code. Using templates, we no longer need to worry about maintaining the factory classes, and additionally, the templates can be reused over and over without duplicating code.

The basic factory template provided supports instantiation of new objects; in some cases, it is useful to initialize the newly instantiated object. This behaviour can be achieved through the factory_with_initializer template, as demonstrated below:

class string_initializer
{
public:
  std::string * operator() (std::string *input)
  {
    (*input) = "I have been initialized";
    return input;
  }
};

typedef template_patterns::factory_with_initializer<std::string, std::string, 
                           string_initializer> string_factory;

void do_stuff()
{
 std::string * str = string_factory::create();
 cout << (*str) << endl;
 delete str;
}

The class string_initializer is parsed to the definition of the string factory; when the create function of the factory is called, it will automatically call the initializer function. The output of the do_stuff-function is "I have been initialized".

Mixing patterns

Say, what if you redesign the application and find that it would be nice if the factory was a singleton instance? No problem: having Design Patterns as templates makes it easy to change code design. Extending the data source example from above, we end up with the following code:

typedef template_patterns::factory<data_source, database_data_source> data_source_factory;
typedef template_patters::singleton<data_source_factory> data_source_singleton_factory;
...
void do_stuff()
{
 data_source * ds = (*data_source_singleton_factory()).create();
 ...
 delete ds;
}

In the end

So, this concludes my tiny introduction to the template Design Pattern library. I have attached version 0.1 of the library, which will be enhanced when time is right. The most recent version of the library is available from my code-blog page found here:

Thanks for reading.

History

  • 01-02-06: Second edition. Library version 0.2. Added factory_with_initializer text.
  • 31-01-06: First edition. Library version 0.1.

License

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

About the Author

Rasmus Kaae
Web Developer
Denmark Denmark
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionHave you tried... ?memberChulips14 Sep '06 - 9:21 
Hi!
 
Have you tried having a factory and some classes that use that factory all inside a library, and a project using that library factory?
 
I'm having problem with classes registering themselfes within the factory when these classes reside inside the library. It seems that the linker cut out the code which enables the classes registering...
 

Regards
 
__________
Chulips

AnswerRe: Have you tried... ?memberrasmus21 Sep '06 - 21:38 
Try posting a code snippet, that might help me answering your question.Smile | :)
 
---
Rasmus Kaae
http://www.3kings.dk
http://kalchas.dk
http://www.hestebasen.com

GeneralLoki & Boost might be a better choicememberMiles Davies1 Feb '06 - 3:26 
Loki is an excelent template based design pattern library and offers mutithreading support also.
 
Boost is also an excellent STL based library and parts of it will be included in the next C++ standard.
 
You seem to be re-inventing the wheel here a little.
 
Not the view of my employer
GeneralRe: Loki & Boost might be a better choicememberrasmus1 Feb '06 - 6:52 
Hello
 
I'm glad that you've already found other alternatives for embedding design patterns into your applications. My library is not intended as a competitor or re-invention, instead it's intended as a fly weight alternative to the existing giants. Boost adds quite an overhead to your program and offers many other features than simply design patterns. I've never heard of loki, but will give it a look when time is right.
 
---
Rasmus Kaae
http://www.3kings.dk
http://kalchas.dk
http://www.hestebasen.com
GeneralRe: Loki & Boost might be a better choicememberPaulius Maruška5 Feb '06 - 6:12 
Loki is realy worth looking at.
 
You can find it here: http://sourceforge.net/projects/loki-lib/[^]

GeneralRe: Loki & Boost might be a better choicememberrasmus5 Feb '06 - 19:52 
Ah yes, Lokis is that template library fro Alexandrescus book. Loki is indeed very nice and versatile, still my template library is just a simple and easy way to use design patterns without much costs.
 
I am not a big fan of installing large libraries, I'd rather pick a wide range of small libraries. Perhaps that's a flaw in my head Smile | :)
 
---
Rasmus Kaae
http://www.3kings.dk
http://kalchas.dk
http://www.hestebasen.com/kaae/code.xml
GeneralCommentmemberWeaponX200631 Jan '06 - 7:09 
Hi!
 
The Singleton template mechanism definitely makes sense, and is the state of the art of an "evasive" programming style.
 
I have to disagree on the factory though. It is most useful for a factory to know what object it creates. And most of the time this is more than just calling "new". (i.e. calling virtual functions)
 
So to actually round up your factory idea I guess a static PostCtor() function in each class would do the job.
 
p.s. i'm used to factories being singleton as well. e.g. "Singleton<IPManager>::GetInstance()->CreateConnection()";
 

 
-- modified at 13:32 Tuesday 31st January, 2006
QuestionI don't get it?memberJim Crafton31 Jan '06 - 3:45 
I don't really see how templates help here at all, especially in the singleton example? It just seems like using templates for the sake of using templates. You don't explain your code at all or how (or even what) its doing.
 
¡El diablo está en mis pantalones! ¡Mire, mire!
 
Real Mentats use only 100% pure, unfooled around with Sapho Juice(tm)!
 
SELECT * FROM User WHERE Clue > 0
0 rows returned

Save an Orange - Use the VCF!
AnswerRe: I don't get it?memberrasmus31 Jan '06 - 6:42 
I'm sorry that you didn't see the point of using templates. Perhaps I'm a bit vague in the article.
 
The basic idea is to split up in functionality and interaction. By this I mean that one is able to implement a fully working class, e.g. a TCP/IP class, and at some point decide to use it as a singleton in one application and through a factory in another application. Using templates, the same base class can be used for either application without writing derivates and only adding a one-liner.
 
Example:
 
class tcpip { ... };
class tcpip_factory { ... };
class tcpip_singletong { ... };

 
or
 
class tcpip { ... };
typedef template_patterns::factory tcpip_factory;
typedef template_patters::singleton tcpip_singleton;

 
It's true that it's possible to implement code supporting design patterns without facilitating templates.
 
---
Rasmus Kaae
http://hestebasen.com/kaae/code.xml
http://www.hestebasen.com
GeneralRe: I don't get it?memberrasmus31 Jan '06 - 6:43 
Add <tcpip> to the factory and singleton typedefs.
 
---
Rasmus Kaae
http://www.3kings.dk
http://kalchas.dk
http://www.hestebasen.com
GeneralRe: I don't get it?memberJim Crafton31 Jan '06 - 6:45 
I think what might help the article, is showing what the template code is actually doing, just putting "typedef template_patterns::factory tcpip_factory" doesn't help as much. What exactly does the template_patters::singleton class do? What advantages does it give over not using it? That kind of thing.
 
¡El diablo está en mis pantalones! ¡Mire, mire!
 
Real Mentats use only 100% pure, unfooled around with Sapho Juice(tm)!
 
SELECT * FROM User WHERE Clue > 0
0 rows returned

Save an Orange - Use the VCF!
GeneralRe: I don't get it?memberrasmus31 Jan '06 - 6:51 
Ok, I've left the tedious details as an exercise for the reader (i.e. download the files and observe). The code behind these templates is actually not that interesting, I guess most people will know how to implement their own singleton, factory, decorator etc. if they needed it. What I find worth sharing is the concept of using templates rather than inheritance when incorporating design patterns into the application design.
 
---
Rasmus Kaae
http://www.3kings.dk
http://hestebasen.com/kaae/code.xml
http://www.hestebasen.com
GeneralRe: I don't get it?memberJim Crafton31 Jan '06 - 7:03 
Well what you refer to as the "tedious bits" are actually the interesting bits! You can find many places and articles that suggest using templates to do this or that, but how did you implement it? For example, I can envision a singleton template class that also allowed for some sort of policy template that controlled certain aspects of it's implementation. Did you use something like this? What if someone isn't aware of some the pitfalls common to singleton implementations? Does your class address that or make allowance for them? If not, why not? Do you address threading (i.e. is it safe to use in multi-threaded code)? Could this be resolved using a policy class? Etc, etc. Seeing any or all of this is what potentially makes an article like this interesting, but you've left it all out, in terms of explaining what's going on how you thought about it! And that's kind of the point of publishing the article on CP in the first place.
 
¡El diablo está en mis pantalones! ¡Mire, mire!
 
Real Mentats use only 100% pure, unfooled around with Sapho Juice(tm)!
 
SELECT * FROM User WHERE Clue > 0
0 rows returned

Save an Orange - Use the VCF!

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 31 Jan 2006
Article Copyright 2006 by Rasmus Kaae
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid