0

次の問題に対する設計上のアドバイスを探しています。

ブーストジオメトリを使用しています。ブーストジオメトリと互換性のあるカスタムジオメトリタイプがいくつかあります(特性を介して)が、使用しているタイプのほとんどはtypedefです。

class MyPoint
{
  // custom stuff
};
// declare traits for MyPoint for use wih boost geometry here

class MyTaggedPoint : public MyPoint
{
  // more custom stuff
};
// declare traits for MyTaggedPoint for use wih boost geometry here

// example typedefs
typedef boost::geometry::model::polygon<MyPoint>        Polygon;
typedef boost::geometry::model::polygon<MyTaggedPoint>  TaggedPolygon;

私の問題は、ジオメトリをシリアル化/逆シリアル化する場合です。

すべてのジオメトリがデータベースのバイナリフィールドに格納されているとしましょう。基本ジオメトリクラスがある場合は、おそらくg-> type()(4バイト)を記述してg-> save(some_outputstream)を呼び出し、そのすべてをバイナリフィールドに書き込みます。次に、バイナリフィールドを読み取るときに、バイトを読み取り、適切なジオメトリタイプにキャストします。

ただし、Boostジオメトリには共通の基本クラスがありません。

バイナリとして格納できる複数のタイプがあり、共有基本クラスがない場合、通常、皆さんはどのようにシリアル化にアプローチしますか?

ブーストを返すシリアライザークラスを作成することを考えていました。その後、(デ)シリアライザーに格納されるタイプを使用してジオメトリをキャストできますか?しかし、シリアライザーは、ジオメトリタイプごとにsaveメソッドを必要としますか?例:Save(myPolygon)、Save(myPoint)

何かアイデア/経験はありますか?

4

2 に答える 2

2

Boostのシリアル化は、ホイールを再実装したくない場合に非侵襲的なシリアル化をサポートします。どこかでそれらのジオメトリタイプのライブラリサポートを見つけることができるかもしれません。残念ながら、XMLの問題により、インターフェイスはやや複雑です。

于 2011-09-07T18:15:53.060 に答える
0

オブジェクトをバイトとの間でシリアル化するには、最終的に、サポートする必要のあるタイプごとに2つの関数(プリミティブ、オブジェクトなど)が必要です。これらは「Load()」と「Store()」です。

理想的には、バイトに固定インターフェース(iostream、char *、一部のバッファーオブジェクトなど)を使用します。論理的にはそれがその役割であるため、読みやすくするために「ByteBuffer」と呼びましょう。

これで、Serializableコンセプトのテンプレート関数のようなものができました。

template<typename T>
ByteBuffer Store(const T& object) { // BUT, What goes here...? }

template<typename T>
T Load(const ByteBuffer& bytes);

さて、これはプリミティブ型以外では機能しません。たとえこれらの「訪問者」または何かを作成したとしても、彼らは文字通り、オブジェクトの内部に関するすべての詳細を知って仕事をする必要があります。さらに、「Load()」は論理的にコンストラクターです(実際には、簡単に失敗する可能性があるため、FACTORYです)。これらを実際のオブジェクトに関連付ける必要があります。

Serializableを基本クラスにするには、「不思議なことに繰り返されるテンプレート」パターンを使用する必要があります。これを行うには、すべての派生クラスに次の形式のコンストラクターが必要です。

T(const ByteBuffer& bytes);

エラーをチェックするために、派生コンストラクターが設定できる基本クラスに保護フラグ「valid」を提供できます。Load()が適切に機能するには、オブジェクトがファクトリスタイルの構築をサポートしている必要があることに注意してください。

これで、これを正しく実行でき、ファクトリとして「ロード」を提供できます。

template<typename T>
class Serializable // If you do reference-counting on files & such, you can add it here
{
protected:
    bool valid;

    // Require derived to mark as valid upon load
    Serializable() : valid(false) {}
    virtual ~Serializable() { valid = false; }

public:
    static T Load(const ByteBuffer& bytes); // calls a "T(bytes)" constructor

    // Store API
    virtual ByteBuffer Store() = 0;  // Interface details are up to you.
};

さて、そのように基本クラスから派生するだけで、必要なものすべてを手に入れることができます。

class MyObject : public Serializable<MyObject>
{
protected:
   // .. some members ...

   MyObject(const ByteBuffer& bytes)
   {
      //... Actual load logic for this object type ...
      // On success only:
      valid = true;
   }

public:
   virtual ByteBuffer Store() {
      //... store logic 
   }
};

すばらしいのは、「MyObject :: Load()」を呼び出すことができ、期待どおりに動作することです。さらに、「ロード」をオブジェクトを構築する唯一の方法にすることができ、読み取り専用ファイルなどのAPIをクリーンアップできます。

これを完全なファイルAPIに拡張するには、もう少し作業が必要です。つまり、より大きなバッファーから読み取ることができる「Load()」(他のものを保持する)と、既存のバッファーに追加する「Store()」を追加します。

ちなみに、これにはBoostのAPIを使用しないでください。優れた設計では、シリアル化可能なオブジェクトは、ディスク上のプリミティブ型のパックされた構造に1対1でマップする必要があります。これが、結果のファイルを他のプログラムまたは他のマシンで実際に使用できる唯一の方法です。Boostは、後で後悔することをほとんど実行できる恐ろしいAPIを提供します。

于 2013-11-12T23:01:33.037 に答える