Pracuję nad biblioteką, która definiuje interfejs klienta dla niektórych usług. Pod maską muszę zweryfikować dane dostarczone przez użytkowników, a następnie przekazać je do procesu "engine", używając klasy Connection z innej biblioteki (uwaga: klasa Connection nie jest znana użytkownikom naszej biblioteki). Jeden z moich kolegów zaproponował korzystania PIMPL:Czy to dobre miejsce na wzór 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;
}
Jednak uważam, że to bardzo trudne do badania - nawet jeśli mogę połączyć moje testy jedni się naśmiewali realizacji połączenia, nie mieć do niego łatwy dostęp, aby ustawić i sprawdź oczekiwania. Ja czegoś brakuje, lub znacznie czystsze i sprawdzalne rozwiązaniem jest użycie interfejsu + fabryczne:
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();
}
czy są jakieś powody, aby przejść z PIMPL w tej sytuacji?
Mogę się mylić, ale jeśli masz członka typu 'Connection' (a nie' Connection * '), musisz dołączyć jego definicję do swojego nagłówka, więc" Connection "jest znane użytkownikom twojej biblioteki. – ereOn
Zobacz http: // stackoverflow.com/questions/825018/pimpl-idiom-vs-pure-virtual-class-interface –
@ereOn: w nagłówku klienta używam tylko deklaracji forward klasy ClientImpl (jest to możliwe, ponieważ element jest wskaźnikiem), więc nagłówek ClientImpl może być ukryte przed moimi klientami bibliotecznymi, więc mogę korzystać z połączenia jako członek ClientImpl. – chalup