问题
I know about the Strategy and Abstract Factory design patterns - however they don't solve my current problem:
I'm creating a C++ library that offers a very basic GUI. However I want the user to be able to choose at compile time which GUI library to use (say Qt or FLTK) to actually render the GUI. The user should however only need to know about the methods in my library.
It should be possible to compile the same code without any changes using either a Qt backend or an FLTK backend.
I thought of something like:
class A
{
// do things that are not specific to QT or FLTK here as there are many
// methods I will need independent of the backend
}
class QT_A : public A
{
// Implement the actual creation of a window, display of a widget here using Qt
}
class FLTK_A : public A
{
// Implement the actual creation of a window, display of a widget here using FLTK
}
The problem is that I do not want the user to know about QT_A
or FLTK_A
. The user (developer) should just deal with A
. Also, I can't have both variants at the same time as I don't want my library to depend on both Qt and FLTK; just whichever was chosen at compile time.
回答1:
One option is the Pimpl idiom described in another answer.
Another option is a factory returning a pointer to the interface class:
std::unique_ptr<A> make_A()
{
#if defined(USING_QT)
return std::unique_ptr<A>(new QT_A(...));
#elif defined(USING_FLTK)
return std::unique_ptr<A>(new FLTK_A(...));
#else
#error "No GUI library chosen"
#endif
}
回答2:
The Pimpl idiom may be an alternative. It allows you to create a common interface without framework dependent members.
class A
{
struct impl;
std::unique_ptr<impl> pimpl; // or scoped_ptr/auto_ptr on non-C++11
public:
A();
~A();
void do_sth();
};
Then, the source file can provide different implementations of impl depending on the backend.
#ifdef QT
struct A::impl : QWidget { // Make it polymorphic, if you need
QImage img;
QString data;
};
void A::do_sth()
{
impl->make_it(); // full access to the Qt things
}
A::A()
: pimpl(new ...)
{
}
A::~A() {} // no need for delete thanks the smart pointer
#endif
回答3:
No need of fancy patterns.
You distribute
- headers of A;
- a library that contains
A
,QT_A
, andmake_A
function; - another library that contains
A
,FLTK_A
and another implementation ofmake_A
function.
The user links to either library.
来源:https://stackoverflow.com/questions/14486080/hiding-multiple-implementations-behind-a-single-interface