コードをさまざまなプラットフォームで実行できるように、抽象化レイヤーを作成しようとしています。高レベル コードで最終的に使用したい 2 つのクラスの例を挙げましょう。
class Thread
{
public:
Thread();
virtual ~Thread();
void start();
void stop();
virtual void callback() = 0;
};
class Display
{
public:
static void drawText(const char* text);
};
問題は、低レベルのコードで実装を埋められるようにするには、どのデザイン パターンを使用できるかということです。ここに私の考えと、それらが良い解決策ではないと思う理由があります:
理論的には、上記の定義が含まれ
highLevel/thread.hていて、プラットフォーム固有の実装が含まれていても問題はありませんlowLevel/platformA/thread.cpp。これは、リンク時に解決されるオーバーヘッドの少ないソリューションです。唯一の問題は、低レベルの実装ではメンバー変数やメンバー関数を追加できないことです。これにより、特定のことが実装できなくなります。解決策は、これを定義に追加することです (基本的には Pimpl-Idiom):
class Thread { // ... private: void* impl_data; }これで、低レベル コードは、void ポインターに格納された独自の構造体またはオブジェクトを持つことができます。ここでの問題は、読みにくく、プログラムするのが面倒なことです。
純粋な仮想を作成
class Threadし、それを継承することで低レベルの機能を実装できました。高レベルのコードは、次のようにファクトリ関数を呼び出すことにより、低レベルの実装にアクセスできます。// thread.h, below the pure virtual class definition extern "C" void* makeNewThread(); // in lowlevel/platformA/thread.h class ThreadImpl: public Thread { ... }; // in lowLevel/platformA/thread.cpp extern "C" void* makeNewThread() { return new ThreadImpl(); }これで十分ですが、静的クラスでは失敗します。
Display::drawText(...)私の抽象化レイヤーは、ハードウェアと IO に使用されます。単一のDisplayクラスへのポインターを持ち運ぶ代わりに、それを使用できるようにしたいと考えています。別のオプションは、このようにリンク時に解決できる C スタイルの関数のみを使用すること
extern "C" handle_t createThread()です。これは簡単で、一度しか存在しない低レベルのハードウェア (ディスプレイなど) にアクセスするのに最適です。しかし、複数回存在する可能性のあるもの (ロック、スレッド、メモリ管理) については、ハンドルを隠すか、ハンドルを非表示にする高レベルのラッパー クラスを持つ高レベル コードでハンドルを持ち歩く必要があります。いずれにせよ、高レベル側と低レベル側の両方でハンドルをそれぞれの機能に関連付ける必要があるというオーバーヘッドがあります。私の最後の考えは、ハイブリッド構造です。
extern "C"一度しか存在しない低レベルのもののための純粋な C スタイルの関数。複数回存在する可能性のあるもののファクトリ関数 (3. を参照)。しかし、私はハイブリッドなものが一貫性のない、読めないコードにつながるのではないかと心配しています。
私の要件に合ったパターンを設計するためのヒントをいただければ幸いです。