views:

134

answers:

3

I'm working on a library that defines a client interface for some service. Under the hood I have to validate the data provided by users and then pass it to "engine" process using Connection class from another library (note: the Connection class isn't known to the users of our library). One of my colleagues proposed using PIMPL:

class Client {
public:
    Client();
    void sendStuff(const Stuff &stuff) {_pimpl->sendStuff(stuff);}
    Stuff getStuff(const StuffId &id) {return _pimpl->getStuff(id);}
private:
    ClientImpl *_pimpl;
}

class ClientImpl { // not exported
public:
    void sendStuff(const Stuff &stuff);
    Stuff getStuff(const StuffId &id);
private:
    Connection _connection;
}

However, I find it very hard to test - even if I link my tests to some mocked implementation of Connection, I don't have an easy access to it to set and validate expectations. Am I missing something, or the much cleaner and testable solution is using interface + factory:

class ClientInterface {
public:
    void sendStuff(const Stuff &stuff) = 0;
    Stuff getStuff(const StuffId &id) = 0;
}

class ClientImplementation : public ClientInterface { // not exported
public:
    ClientImplementation(Connection *connection);
    // +implementation of ClientInterface
}

class ClientFactory {
    static ClientInterface *create();
}

Are there any reasons to go with PIMPL in this situation?

+1  A: 

GoTW15

GoTW28

From Herb Sutter. Good pointers to get you started.

DumbCoder
+2  A: 

AFAIK the usual reason to use the Pimpl idiom is to reduce compile/link time dependencies to the implementation of the class (by removing the implementation details from the public header file altogether). Another reason may be to enable the class to change its behaviour dynamically (aka the State pattern).

The second does not seem to be the case here, and the first can be achieved with inheritance + a factory as well. However, as you noted, the latter solution is much easier to unit test, so I would prefer this.

Péter Török
Another reason to use the Pimpl idiom is to separate the implementation details from the public interface of a class : only the public members are visible in the class header.
Luc Touraille
The only reason to use Pimpl idiom is when you cannot use abstract base class. For example when you implement class which is meant to be instantiated as value on stack or as a member of another class. In that situation you can still have 'compilation firewall' thanks to pimpl.
Tomek Szpakowicz
If I export only abstract interface + factory, doesn't that reduce compile/link time dependencies as well?
chalup
@Luc, that is what I meant by "reduce compile/link time dependencies to the implementation of the class", apparently not clearly enough - updated.
Péter Török
@chalup, yes it does, that's why I suggested it is a better solution overall.
Péter Török
@tomekszpakowicz: I can initialize pointer member in class constructor (either with pointer passed in argument or by invoking factory method on constructor list). And instead of value on stack I can use scoped pointer.
chalup
@chalup Of course you can. But C++ gives us unique power of defining abstract datatypes that can be used just like built-in types, e.g.: `complex a(1, -2); complex b = 2 * a; complex c = a + b - complex(4, 1);` Can you use abstract base class trick with them?
Tomek Szpakowicz
@tomek: no I can't, good point. But on the other hand I don't need such syntax in the situation described in my question.
chalup
@Peter: I think it is my comment that was not clear enough :). What I wanted to stress is that separating implementation details from the public interface is not only useful to reduce compile/link time, but also to provide a much cleaner in-code documentation: when a user/developer that uses the class look into the header, he only sees what he should see, i.e. the public members. If he truly needs more information about the class internals, he can look up the implementation class but both aspects (interface/implementation) are well isolated.
Luc Touraille
A: 

Yes this is a good place to use the Pimpl pattern, and yes it will be difficult to test as is.

The problem is that the two concepts oppose one another:

  • Pimpl is about hiding dependencies from the client: this reduces compile/link time and is better from an ABI stability point of view.
  • Unit Testing is usually about surgical intervention in the dependencies (use of mock ups, for example)

However, it does not mean that you should sacrifice one for another. It merely means that you should adapt your code.

Now, what if Connection was implemented with the same idiom ?

class Connection
{
private:
  ConnectionImpl* mImpl;
};

And delivered through a Factory:

// Production code:

Client client = factory.GetClient();

// Test code:
MyTestConnectionImpl impl;
Client client = factory.GetClient(impl);

This way, you can access the nitty gritty details of your test implement of connection while testing client without exposing the implementation to the client or breaking the ABI.

Matthieu M.
The problem is, the people up the food chain doesn't want any kind of factory method/class nor any constructors that take dependencies - there should be only Client::Client() constructor...
chalup
In this case you can use the factory internally (making it singleton) to generate the right `ClientImpl`. This way the interface does not change, but the client constructor does.
Matthieu M.