更新 :コメントで正しく指摘されているように、継承とポリモーフィズムを1つのパイルに混在させました。 非常に重大なエラーを削除して新しいエラーを追加するには、テキストを少し変更しました。 したがって、一部のコメントがテキストに関連していないように思われる場合は、おそらく以前のバージョンを指しているだけです。 ご不便をおかけして申し訳ありません。
NB :この記事は 、「Googleプロトコルバッファーとは」という質問には答えておらず 、特定のプログラミング言語に関係していません。
だから、問題の声明:
- プロトコルバッファを操作するときにポリモーフィズムを実装する方法
- メッセージ付きの大きなファイルを使用して、必要なデータを検索して見つける方法は?
NB:ここでは、英語のメッセージの代わりに、「メッセージ」という単語または「構造」という単語が使用されます。 一部の文では、「メッセージ」という言葉は奇妙に聞こえます。
パートI:ポリモーフィズム
プロトコルにSquare、Circle、Polygonの3つのクラスのオブジェクトが含まれているとします。 また、すべてにカラーフィールドとidフィールドがあるとします。 この場所では、Shapeの共通の祖先からそれらを継承し、
擬似コード
enum Color { RED, GREEN, BLUE } struct Point { int x; int y; } struct Shape { int id; Color color; } struct Square extends Shape { Point corner; int width; } struct Circle extends Shape { Point center; int radius; } struct Polygon extends Shape { Point [] points; }
残念ながら、Googleプロトコルバッファは階層をサポートしていません。 Jon Parise は 、この制限に対する3つの回避策を検討しています。
オプションのフィールドを使用する
このアプローチでは、後継クラスごとに個別の構造を作成し、Shape構造には各ケースのオプションフィールドが含まれます。
このアプローチには、いくつかの重大な欠点があります。
- 基本クラスを変更せずに新しいクラス継承を作成することはできません。 ちなみに、他の人のプロトコルを拡張すると、これが問題になる可能性があります。
- 両方の(正方形と円)フィールドを初期化することにより、未知の正方形の円を作成できます。
- 取得したタイプを判別するには、フィールドの存在をチェックするコードを作成する必要があります。
geom-1.proto
enum Color { RED = 1; GREEN = 2; BLUE = 3; } message Point { required fixed32 x = 1; required fixed32 y = 2; } message Square { required Point corner = 1; required fixed32 width = 2; } message Circle { required Point center = 1; required fixed32 radius = 2; } message Polygon { repeated Point points = 1; } message Shape { required TYPE type = 1; required fixed32 id = 2; optional Color color = 3; // optional Square square = 4; optional Circle circle = 5; optional Polygon polygon= 6; }
ネストされたシリアル化
別のアプローチでは、相続人に共通のフィールドを持つShape構造を作成し、相続人のシリアル化されたフィールドが既にある別のフィールドを追加します。
また、「シリアライザー」はサブクラスフィールドの内容を自動的に「アンパック」しないため、これは最も成功したオプションではありません。したがって、整合性チェックは実行されません。
とにかく、それは何とか美しくありません。
geom-2.proto
enum TYPE { SQUARE = 1; CIRCLE = 2; POLYGON = 3; } enum Color { RED = 1; GREEN = 2; BLUE = 3; } message Point { required fixed32 x = 1; required fixed32 y = 2; } message Square { required Point corner = 1; required fixed32 width = 2; } message Circle { required Point center = 1; required fixed32 radius = 2; } message Polygon { repeated Point points = 1; } message Shape { required TYPE type = 1; required fixed32 id = 2; optional Color color = 3; // required bytes subclass = 4; }
ネストされた拡張機能
3番目(推奨)のアプローチは最初のアプローチと似ていますが、オプションのフィールドの代わりにネストされた拡張機能が使用されます。 四角い円と戦うために、タイプフィールドが入力されます。
geom-final.proto
enum TYPE { SQUARE = 1; CIRCLE = 2; POLYGON = 3; } enum Color { RED = 1; GREEN = 2; BLUE = 3; } message Point { required fixed32 x = 1; required fixed32 y = 2; } message Shape { required TYPE type = 1; required fixed32 id = 2; optional Color color = 3; extensions 4 to max; } message Square { extend Shape { required Square shape = 5; } required Point corner = 1; required fixed32 width = 2; } message Circle { extend Shape { required Circle shape = 6; } required Point center = 1; required fixed32 radius = 2; } message Polygon { extend Shape { required Polygon shape = 7; } repeated Point points = 1; }
このアプローチの利点を詳しく見てみましょう。
- オプションのフィールドの代わりに拡張子を使用すると、次のことができます。
- 他の人の定義を「継承」する(プロトコル)
- 他のファイルにクラス「heirs」を記述します。 そのようなクラスが多数ある場合、これは重要です。
- 拡張機能がネストされているという事実により、実際には異なるレキシカルスコープ内にあるため、フィールドに同じ名前を付けることができます。 この例では、これらはSquare.shape、Circle.shape、Polygon.shapeです。 テンプレートでサポートされている言語では、非常に便利です。
- 2番目のアプローチとは異なり、すべてがフレームワークによって逆シリアル化されます。
パートII:検索
そのため、メッセージ構造の説明を含むファイル(geom.proto)があります。 私たちのプログラムは機能し、メッセージ自体を含む大きなファイルを作成しました。 その中に必要な情報を見つけたいのですが、これは単純なテキスト検索では常に可能とは限りません。
例:
- 座標軸と交差する円を見つけます。
- 空のポイントセットを持つポリゴンを検索する
- 10ポイント以上のポリゴンを見つけます。
同意して、通常のgrepはここでは役に立ちません。
もちろん、そのようなタスクごとに小さなプログラムを書くのは簡単で、指定されたプロパティを持つファイル内の数字を探します。 ただし、構造化されたデータとその形式があるため、独自のクエリ言語を作成してみませんか?
タスクの例を返します。
-
type == "CIRCLE" && ((center.x - radius) < 0 || (center.y - radius) < 0))
//座標軸と交差する円を見つけます。 -
type == "POLYGON" && #points == 0
//空のポイントセットを持つポリゴンを検索する -
type == "POLYGON" && #points > 10
// 10ポイントを超えるポリゴンを検索します。
これだけでなく、はるかに多くが自作の自転車を作ることができます。
また、彼はできる
- ファイルをバイナリ形式からテキスト形式に、またはその逆に転送します
- メッセージから特定のフィールドのみを切り取り、印刷します
- 1つの要求で複数の連続したメッセージを使用します。 たとえば、円の直後にあるすべての正方形を見つけます。
自転車がユーザーを見つけ、それとともに自転車の構文と機能に関する詳細なトピックが必要になることを願っています。
ありがとう