(注:このカテゴリの問題を読むための適切な検索用語に関する提案を実際に探しています。 「オブジェクト リレーショナル マッピング」は、優れた先行技術を見つけることができる場所として思い浮かびました...しかしこのシナリオに完全に適合するものはまだ見たことがありません。)
私は非常に一般的な を持っていclass Node
ますが、これは今のところ DOM ツリーの要素のようなものと考えることができます。これは実際に起こっていることではありません。メモリ マップ ファイル内のグラフ データベース オブジェクトです。しかし、この類推はすべての実用的な目的でかなり近いので、簡単にするために DOM 用語に固執します。
ノードに埋め込まれた「タグ」は、(理想的には) ノードで実行できる特定の操作セットを意味します。現在、これを行うために派生クラスを使用しています。たとえば、HTML リストのようなものを表現しようとしていた場合:
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
基になるツリーは 7 つのノードになります。
+--UL // Node #1
+--LI // Node #2
+--String(Coffee) // Node #3 (literal text)
+--LI // Node #4
+--String(Tea) // Node #5 (literal text)
+--LI // Node #6
+--String(Milk) // Node #7 (literal text)
getString()
はすでにノード自体のプリミティブ メソッドであるため、おそらく , だけを作成しclass UnorderedListNode : public Node
ますclass ListItemNode : public Node
。
この仮説を続けて、プログラマーが手元にあるノードの「タイプ」/タグについて詳しく知っているときに、プログラマーがあまり一般的でない機能を使用できるようにしたいと考えてみましょう。おそらく、順序付けられていないリストに文字列アイテムを追加したり、文字列として抽出したりするなど、ツリーの構造イディオムで彼らを支援したいと思います。 (これは単なる例えですので、ルーチンをあまり真剣に考えないでください。)
class UnorderedListNode : public Node {
private:
// Any data members someone put here would be a mistake!
public:
static boost::optional<UnorderedListNode&> maybeCastFromNode(Node& node) {
if (node.tagString() == "ul") {
return reinterpret_cast<UnorderedListNode&>(node);
}
return boost::none;
}
// a const helper method
vector<string> getListAsStrings() const {
vector<string> result;
for (Node const* childNode : children()) {
result.push_back(childNode->children()[0]->getText());
}
return result;
}
// helper method requiring mutable object
void addStringToList(std::string listItemString) {
unique_ptr<Node> liNode (new Node (Tag ("LI"));
unique_ptr<Node> textNode (new Node (listItemString));
liNode->addChild(std::move(textNode));
addChild(std::move(liNode));
}
};
これらの新しい派生クラスにデータ メンバーを追加することは、悪い考えです。情報を実際に永続化する唯一の方法は、ノードの基本ルーチン (たとえば、addChild
上記の呼び出しまたはgetText
) を使用してツリーと対話することです。したがって、実際の継承モデルは (存在する範囲で) C++ 型システムの外部にあります。<UL>
ノード「maybeCast」UnorderedListNode
を vtables/etc とは何の関係もありません。
C++ の継承は、正しいように見えることもありますが、通常は間違っていると感じます。継承の代わりに、Node とは独立して存在するクラスを用意し、「アクセサ ヘルパー」として何らかの方法で Node と連携する必要があるように感じます...しかし、それがどのようなものになるかはよくわかりません。