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

An Implementation of the Service Locator Pattern in C++

, 19 Feb 2008
Rate this:
Please Sign up or sign in to vote.
The Service Locator can be used to decouple classes, which improves the overall design and significantly helps with unit testing.

Introduction

This article assumes knowledge of the Service Locator pattern. The article uses terminology and source examples from Martin Fowler's Inversion of Control Containers and the Dependency Injection Pattern. Also see the CodeProject article A Basic Introduction on Service Locator Pattern.

Background

Typical examples are in C# and Java. This article provides a simple but complete Service Locator framework in C++.

The basic idea behind the Service Locator is to be able to register one or more classes with a repository and then ask the repository to create instances of those classes using an ID rather than the actual class name. By doing this, it makes the client code decoupled from the actual implementation of the class, allowing clients to register different implementations of the same interface and thus being able to swap different sets of functionality without changing the code that uses the class. This also helps with unit testing because references to a class that would ordinarily be hard-coded no longer needs to be.

And finally, this also reduces build dependencies.

Sneak peak at usage

In this article, Martin Fowler's example classes are used: MovieFinder is an interface (abstract pure-virtual class) and ColonDelimitedMovieFinder is a class which implements MovieFinder.

The Service Locator code will allow us to register ColonDelimitedMovieFinder with a string ID such as "finder", and then create instances of the ColonDelimitedMovieFinder classes by just using the string name "finder", assigning the referencing to a MovieFinder pointer.

Example registering the class, storing it under the string ID "finder":

locator.register_class<ColonDelimitedMovieFinder>( "finder" );

Example creating an instance of this class:

MovieFinder* finder = locator.get_single_instance<MovieFinder>( "finder" );

Using the Code

(You just need the single header, servicelocator.h. The namespace sl is used.)

Derive your interfaces (pure-virtual abstract classes) from interface_t. Example:

struct MovieFinder : sl::interface_t
{
    virtual vector<Movie> findAll() = 0;
};

Derive your template classes from member_t, passing in the class name as the template parameter. Example:

class ColonDelimitedMovieFinder : public sl::member_t<ColonDelimitedMovieFinder>
{ ...

Create an instance of servicelocator_t. Example:

sl::servicelocator_t locator;

Register classes using the register_class method. The class to be registered is the template parameter. The function parameter is the string ID representing the class. Example:

locator.register_class<ColonDelimitedMovieFinder>( "finder" ); 

Now, the string ID (such as "finder") above can be created with an instance of ColonDelimitedMovieFinder, without referencing ColonDelimitedMovieFinder by name. Assuming that ColonDelimitedMovieFinder is redefined to implement the MovieFinder interface like so:

class ColonDelimitedMovieFinder : public sl::member_t<ColonDelimitedMovieFinder>, 
                                  public MovieFinder

Then, there are two methods for creating an instance of ColonDelimitedMovieFinder. One as a singleton (so that subsequent calls to create all return the same instance), and one as a transient instance, where a new instance is created with each call.

The call to create a singleton instance is get_single_instance, and it looks like this:

MovieFinder* finder = locator.get_single_instance<MovieFinder>( "finder" );

(Again, note that the class ColonDelimitedMovieFinder is not referenced, but that's what's created because the string ID "finder" was registered with ColonDelimitedMovieFinder above.) Note that the object returned from get_single_instance does not need to be freed. Only a single instance is created and is owned by the Service Locator. When the locator object goes out of scope, or is freed, all singletons are freed.

The second way to create an instance is via get_new_instance, and it looks like this:

auto_ptr<MovieFinder> finder = locator.get_new_instance<MovieFinder>( "finder" );

For convenience, get_new_instance returns an auto_ptr, which is safer to return than a raw pointer. However, if the client doesn't want an auto_ptr object, it's simple enough to call release() on the auto_ptr and get the raw object, which then can be managed by the client as desired. But in that case, the client is responsible for calling delete on the raw object eventually.

License

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

About the Author

Kenneth Kasajian

United States United States
My interests mostly revolve around making machines do work for people. I'm a computer programmer, software architect, development manager, program manager and a computer programmer. I said programmer twice because I believe you need to be able to do the work yourself if you're going to direct others. I started my career creating software for abstract art, followed by work in embedded systems and HMI. In the 90s I created a successful product called Visual DLL and helped develop the Sales Force Automation product, Arsenal. I've often been involved in online communities, creating games, utilities, and collaboration software. I'm passionate about agile requirements management, acceptance testing through executable specification, and anything that will make developers more productive. My current role is Principal Scientist where I get to work on different technologies with an awesome team, to solve real-world practical problems. I'm Armenian, so talking is in my nature -- if you see me online or offline, say hi and we'll geek out about the latest tools and libraries. If you learned something cool recently (and you should if you're a lifelong learner), then I'd like to hear about it.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralFix for VS2010 Pinmemberglassy18-Feb-11 0:50 
GeneralRe: Fix for VS2010 PinmemberKenneth Kasajian18-Feb-11 10:07 
GeneralRe: Fix for VS2010 Pinmemberglassy28-Feb-11 21:22 

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 | Mobile
Web04 | 2.8.140721.1 | Last Updated 19 Feb 2008
Article Copyright 2008 by Kenneth Kasajian
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid