1

現在、特定の API (libpq) を介してデータベースに接続するために使用する実行中のコードがあります。

基本的に 2 つのクラスがあります。メイン アプリケーション クラス CMain と、CDbConnectorPq と呼ばれるデータベース関連クラス (データベースへの接続、クエリの発行、結果の保存を担当) です。

私の CMain コンストラクターでは、現在、CDbConnectorPq 型のクラス メンバーをインスタンス化し、そのオブジェクトを使用して、CMain オブジェクトから直接、接続とクエリをトリガーします。

main->dbConnectorPq->connect();

問題は、libpq に加えて、データベース (ODBC) に接続するための別の API を実装する必要があることです。私は、libpq コードを odbc コードから分離し続けるための適切なモデリングとは何かを理解しようとしていますが、それでもメイン オブジェクトとまったく同じインターフェイスを使用しています。

私は継承について考えましたが、CDbConnectorPq と CDbConnectorODBC の 2 つのクラスを持つことになり、メインでは libpqxx 用と odbc 用の 2 つのメンバーを持つことになり、強制的に:

if ( gl_use_config_odbc )
  dbConnectorOdbc = new CDbConnectorODBC();
else if ( gl_use_config_libpq )
  dbConnectorPq = new CDbConnectorPq();

その後 :

if ( gl_use_config_odbc ) {
  dbConnectorOdbc->connect();
  dbConnectorOdbc->query();
}
else if ( gl_use_config_pq ) {
  dbConnectorPq->connect();
  dbConnectorPq->query();
}

ここで継承を利用して、メイン オブジェクトから API 固有のロジックをマスクする方法がわかりません。

理想的には、インターフェースは(私が思うに)次のようにする必要があります:

( gl_use_config = PQ の場合) dbConnector->setType(gl_use_config); dbConnector->connect(....); dbConnector>接続(...);

または ( gl_use_config = ODBC の場合) dbConnector->setType(gl_use_config); dbConnector->connect(param1,param2); dbConnector>接続 (クエリ 1、クエリ 2);

はい、引数番号は、PQ と ODBC の間で数と型が異なる可能性があるためです...

では、この場合のスマート モデリングとはどのようなものでしょうか?

4

2 に答える 2

2

これはあなたの典型的なSOの答えではありませんが、これについて私が感じていることです. 過去 15 年間に OCI、OCCI、OTL、RogueWave、libpq、libpqxx を使用してさまざまな企業向けにいくつかのデータベース層を作成してきた私のアドバイスは次のとおりです。真剣に。

PostgreSQL に接続する場合でも ODBC のみを使用するか (これは個人的には好きではありません)、完全に分離された 2 つのデータベース アクセス レイヤーを開発する必要があります。インターフェイスと使い方を統一しようとすると、多くの問題に直面し、長年の経験が必要になります。それでも、新しいプロジェクトごとに別の問題が見つかり、インターフェイスが必要以上に頻繁に変更されます。

別のレイヤーを開発したい場合は、アプリケーションをあるレイヤーから別のレイヤーに移植しやすくするために、いくつかのことを行うことができます。

  • できるだけたものにしますが、強制しないでください。
  • 両方のレイヤーが同じセマンティックで同じ機能を持つ場合は、同じ名前を使用します。
  • 両方のレイヤーが異なるセマンティックで同じ機能を持っている場合は、異なる名前を使用してください。
  • データベース層を使用するアプリケーションでは、データベースヘッダーを含む1 つtypedefのヘッダーを使用し、それらをs を介して使用するか、名前空間エイリアスを使用することをお勧めします。

これにより、移植が容易になります。アプリケーションをあるレイヤーから別のレイヤーに移植するときtypedefは、ヘッダーの s または名前空間エイリアスを変更し、手動で適応させる必要があるものをコンパイラーが見つけられるようにします。

于 2013-03-28T00:11:41.573 に答える
0

それを行う方法は、CMain クラスに、両方のサブクラスの派生元である抽象基本クラスのポインターを保持させることだと思います。例えば

class IDatabase
{
public:
   virtual void connect() = 0;

   [...]
};

次に、if/then ロジックを実行する必要がある唯一の場所は、適切なクラスのオブジェクトを作成するときです。

if ( gl_use_config_odbc ) {
    dbConnector = new CDbConnectorODBC();
} else {
    dbConnector = new CDbConnectorPq();
}

その後はすべて前と同じです。

dbConnector->connect();

...そして、C++ の virtual-method-lookup メカニズムは、(dbConnector) が指しているオブジェクトのタイプに基づいて、適切なメソッドを自動的に呼び出します。

引数の数が異なる限り、そのような実装の詳細のコードを 2 つのサブクラス内に保持して、メイン コードがそれらを気にする必要がないようにしてください。CMain が認識する IDatabase インターフェイスは、実装に依存しない必要があります。

于 2013-03-27T23:51:02.407 に答える