6

Pimplはバイナリ互換性に優れており、インターフェイスは実装を簡単に切り替えることができるのに適していることを読みました。これらの手法の両方を組み合わせて、アプリケーションが構成ファイルを介して基盤となる実装を切り替えることができるようにする必要があります。

これが私の現在のデザインのレイアウトです。

クラスFoo:クライアント向けAPIを提供します。ここではABIの互換性に関心があります
。クラスIFoo:インターフェイスクラス(すべての純粋仮想メソッド、仮想dtor)
クラスVendor1Foo:Vendor1のライブラリを使用してIFoo
を実装しますクラスVendor2Foo:Vendor2のライブラリを使用してIFooを実装します

pimplを使用せず、インターフェイスを厳密に使用すると、クライアントコードは次のようになります。

IFoo* foo = new Vendor1Foo();

問題は、私のクライアントコードがVendor1またはVendor2についてまったく知ることができず、Fooは私がこれを行わなければならない多くのクラスの1つにすぎないことです。

私がやろうとしていることの全体的な概念は次のとおりです。

class foo
{
  private:
  QScopedPointer<IFoo> pimpl;
  void initImpl();  // Reads from QSettings and initializes pimpl
}

この問題のエレガントな解決策について何かアイデアはありますか?

これに対処する方法を標準化し、DRYの違反を最小限に抑えるために、いくつかのマクロまたはテンプレートクラス/メソッドを考え出すことを望んでいます。

テンプレートクラスは、ハーブサッターがC ++ 11の一般化されたpimplイディオムを採用するようなpimplヘルパーとして機能する可能性があります:herbsutter.com/gotw/_101また、構成に応じて正しい実装をインスタンス化するためのロジックが含まれている必要があります

ここには、pimplイディオム、ブリッジパターン、およびファクトリパターンの要素があります。上記の例では、initImpl()はファクトリメソッドと考えることができます。これらのパターンのすべてを使用する場合と使用しない場合があるソリューションを探しています。

私はすでにc++pimplイディオムを見てきました:テンプレートパラメータに応じた実装と、SOに関するほとんどのpimplイディオムの質問。タイトルは有望に見えましたが、私の特定のユースケースには役立ちませんでした。

C ++ 11を使用できず、Qtを使用しています。 Dポインターは単一の実装にバインドされているため、私の問題を解決しません。

4

4 に答える 4

1

あなたが探しているのは橋のデザインパターンです

http://en.wikipedia.org/wiki/Bridge_pattern

pimpl イディオムを使用して実装できます。

ヘッダー ファイル:

class IFoo {
public:
  virtual void doA() = 0;
  virtual void dob() = 0;
};

class Foo {
public:
  Foo();
  ~Foo();
  void doA() { impl->doA(); }
  void doB() { impl->doB(); }
private:
  IFoo* impl;
  // if needed - add clone to IFoo...
  Foo(const Foo&);
  Foo& operator = (const Foo&);
};

何処か別の場所:

   class Vendor1Foo : public IFoo { ... }; 
   class Vendor2Foo : public IFoo { ... }; 

.cpp ファイル:

Foo::Foo() : impl(createFooImpl()) {}

テンプレートを 40 クラスに対応させるには:

template <class Interface>
Interface* createInterfaceFromConfig();

template <class Interface>
class ConcreteObject {
public:
   ConcreteObject() : impl(createInterfaceFromConfig<Interface>())
   Interface& interface() { return *impl; }
   const Interface& interface() const { return *impl; }
private:
   Interface* impl;
   // if needed - add clone to IFoo...
   ConcreteObject(const ConcreteObject&);
   ConcreteObject& operator = (const ConcreteObject&);
};

// example
class IFoo { ... };
typedef ConcreteObject<IFoo> Foo;

// somewhere else do specialization (.cpp file)

template <>
IFoo* createInterfaceFromConfig<IFoo>() { ... }

他の 39 のインターフェイスの専門化...

于 2012-10-15T19:07:09.380 に答える
0

私は、あなたはこのすべてのことを過度に複雑にしていると思います。Foosのファクトリを使用するだけです。

//accessible from client code:
struct IFoo
{
    virtual ~IFoo(){}
}

struct FooFactory
{
    IFoo* createFoo() const;

// you may only need pimpl here to fix _factory_ _interface_. 
// And you always have 1 factory
private:
    FooFactroyPrivate* d;
}

//implementation:
IFoo* FooFactory::createFoo() const
{
    //checking settings, creating implementation
}

インターフェイスを修正した限り、新しい実装を自由に追加できます。クライアントはインターフェイスを介してのみアクセスできるため、実装の詳細を自由に変更できます。

于 2012-10-15T19:13:32.530 に答える
0

あなたが求めていることは、私にはDependency Injectionに非常に似ているようです。少し前に、C++ の DI フレームワークを探していて、pococapsuleを見つけました。まだ使っていないのでレビューはできませんが、よろしければご覧ください。

于 2012-10-16T16:36:36.147 に答える