【问题标题】:Hiding multiple implementations behind a single interface在单个接口后面隐藏多个实现
【发布时间】:2013-01-07 07:23:36
【问题描述】:

我知道策略和抽象工厂设计模式 - 但是它们并不能解决我当前的问题:

我正在创建一个提供非常基本的 GUI 的 C++ 库。但是我希望用户能够在编译时选择使用哪个 GUI 库(比如 Qt 或 FLTK)来实际呈现 GUI。然而,用户应该只需要了解我的库中的方法。

应该可以使用 Qt 后端或 FLTK 后端编译相同的代码而无需任何更改。

我想到了类似的东西:

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
}

问题是我不希望用户知道QT_AFLTK_A。用户(开发人员)应该只处理A。此外,我不能同时拥有这两种变体,因为我不希望我的库同时依赖于 Qt 和 FLTK;只是在编译时选择的那个。

【问题讨论】:

  • 首先想到的就是使用预处理器……希望你能得到更好的答案。
  • 不叫QT,叫Qt(QT = QuickTime, Qt = cute ;))。

标签: c++ design-patterns inheritance cmake


【解决方案1】:

Pimpl 成语可能是另一种选择。它允许您创建一个不依赖于框架的成员的通用接口。

class A
{
  struct impl;
  std::unique_ptr<impl> pimpl; // or scoped_ptr/auto_ptr on non-C++11
public:
  A();
  ~A();
 void do_sth();
};

然后,源文件可以根据后端提供不同的impl实现。

#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

【讨论】:

  • 等等,你有一个指向 QWidget 的指针,这不是 pimpl 通常的工作方式。
  • 没错,但这就是 Qt 的工作方式(可悲)。我会做一个更好的例子。
【解决方案2】:

一个选项是另一个答案中描述的 Pimpl 成语。

另一种选择是工厂返回指向接口类的指针:

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
}

【讨论】:

    【解决方案3】:

    不需要花哨的图案。

    你分发

    1. A 的标头;
    2. 一个包含AQT_Amake_A函数的库;
    3. 另一个包含AFLTK_Amake_A 函数实现的库。

    用户链接到任一库。

    【讨论】:

    • 图案很“花哨”?严重地?四人帮是 19 年前的事,被评为十年来最重要的书……是时候走出洞穴了……
    • @Rob:这本书出版的那一年我就读过了。它实际上非常好,但这里不需要它,因此“花哨”。无论如何感谢您的建议。
    • 我不确定我是否理解...如果使用 A 的标头,那么只有 A 的实例会由我创建,因为我需要相应派生类(QT_A 或 FLTK_A)的实例。
    • A.h 具有A* makeA(); 声明。这两个定义QT_A.cppFLTK_A.cpp中。它们分别返回指向QT_AFLTK_A 的指针,转换为A*。用户不应该链接这两个库,所以没有冲突。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 2017-07-09
    • 2016-10-30
    • 1970-01-01
    相关资源
    最近更新 更多