Showing posts with label singleton. Show all posts
Showing posts with label singleton. Show all posts

c++ development slide deck

Here's the slide deck for a presentation I recently did for a large gathering of C++ developers.

A singleton refactoring

Here's a refactoring I often teach. It's particularly applicable if you're wanting to refactor legacy code. I'll show it in C++ in honour of the excellent developers at Promethean.

I'll start with a typical Singleton:

class singleton
{
public:
    static singleton & instance();
    void f(int value);
    int g(const std::string & path);
private:
    singleton();
    ~singleton();
};

Together with typical piece of client client code that I'm wanting to unit-test:

int client::eg1()
{
    stuff();
    more_stuff();
    int r = singleton::instance().g("Hello world");
    return yet_more_stuff(r);
}

My problem is that singleton leads to one or more external dependencies I'd like my unit-tests to bypass. My first step is to create an interface for the singleton:

class singleton_interface
{
public:
    virtual void f(int value) = 0;
    virtual int g(const std::string & path) = 0;
    ...
};

And then make singleton implement the interface. (The saving grace of singleton is that its methods are at least instance methods.)

class singleton : public singleton_interface
{
public:
    static singleton & instance();
    void f(int value);
    int g(const std::string & path);
private:
    singleton();
    ~singleton();
};

Now I can overload eg1 as follows:

int client::eg1(singleton_interface & instance)
{
    stuff();
    more_stuff();
    int r = instance.g("Hello world");
    return yet_more_stuff(r);
}

int client::eg1()
{
    return eg1(singleton::instance());
}

And finally, I can create singleton_interface sub-classes and use them in my unit-tests:

struct my_mock_singleton : singleton_interface
{
    explicit my_mock_singleton(int g_result) 
        : g_result(g_result) 
    {
    }
    void f(int value) 
    {
    }
    int g(const std::string & s) 
    { 
        return g_result; 
    }
    int g_result;
};

void test_client_eg1_hitch_hiker_is_42()
{
    assert(42 == client().eg1(my_mock_singleton(6*9)));
}


Lean on the Compiler by Hiding (C++)

My Lean on the Java Compiler by Hiding post has proved quite popular so I've been thinking about if it could also work for C++... It can. I'll use Singleton as a example again. Suppose you have a C++ class like this:



class legacy
{
public:
    legacy();
    void eg1();
    void eg2();
    ...
};
#include "legacy.hpp"
#include "singleton.hpp"

void legacy::eg1()
{
    singleton::instance()->call();
}

void legacy::eg2()
{
    singleton::instance()->call();
}

Again, you want to create a seam for singleton access. The first step is to introduce the hiding identifier in the header file:

class legacy
{
public:
    legacy();
    void eg1();
    void eg2();
    ...
private:
    class singleton;  // <-----
};


Now Lean on the Compiler. All the calls to singleton::instance() no longer compile because the global singleton class is now hidden by the local singleton class just introduced. Next, in the source file add a global variable called instance of type singleton* and refactor all occurrences of singleton::instance() to instance.
#include "legacy.hpp"
#include "singleton.hpp"

singleton * instance;

void legacy::eg1()
{
    instance->call();
}

void legacy::eg2()
{
    instance->call();
}

Then Lean on the Compiler again to make sure there are no typos. Next remove the global variable called instance from the source file and refactor the header file to this:

class singleton; // <-----

class legacy
{
public:
    legacy();
    void eg1();
    void eg2();
    ...
private:
    singleton * instance; // <-----
};

Finally, initialize the instance member in the constructor definition.

legacy::legacy()
    : instance(singleton::instance())
{
}

I haven't tried this on real legacy code either. Caveat emptor!

Lean on the Compiler by Hiding (Java)

Here's a small trick which might not be out of place in Michael Feather's excellent book. I'll use Singleton as a example. Suppose you have a class like this (Java):



public class Legacy
{
    public void eg1()
    {
        stuff(Singleton.getInstance().call());
    }
    public void eg2()
    {
        more_stuff(Singleton.getInstance().call());
    }
}

And you want to create a seam for the singleton access. The first step is to introduce two public fields:

public class Legacy
{
    public int Singleton;
    public Singleton instance;

    public void eg1()
    {
        stuff(Singleton.getInstance().call());
    }
    public void eg2()
    {
        more_stuff(Singleton.getInstance().call());
    }
}

Now Lean on the Compiler. All the calls to Singleton.getInstance() no longer compile because the Singleton class is now hidden by the int Singleton just introduced. Next refactor all occurences of Singleton.getInstance() to instance (the other identifier just introduced, you can pick any name for this one but it's type must be Singleton).

public class Legacy
{
    public int Singleton;
    public Singleton instance;

    public void eg1()
    {
        stuff(instance.call());
    }
    public void eg2()
    {
        more_stuff(instance.call());
    }
}

Then Lean on the Compiler again to make sure there's no typos. Finally refactor to this:

public class Legacy
{
    public Singleton instance = Singleton.getInstance();

    public void eg1()
    {
        stuff(instance.call());
    }
    public void eg2()
    {
        more_stuff(instance.call());
    }
}

The name lookup rules for Java allow this to work but I don't think this idea will work in C++ (for example). I haven't got time to try it now as I'm heading off to the NDC conference in Oslo. I only thought of it yesterday. I haven't tried this on real legacy code. Caveat emptor!

Update. I have a C++ version aswell.