1

理論的には複合およびイテレータの設計パターンに最適な状況がありますが、これらのパターンで発生する問題は、取引を妨げる可能性のある基になるデータ構造にアクセスできないことです。

確かに、私はある国の都市のモールに店を構えることができます。これは全体の関係を作り、それの複合パターンを作成すると、店舗/モールの時間など、すべてのオブジェクト (ほとんどの部分) に対して共通のメソッドを実行できます。開いたり閉じたりしますが、実際にはそれ以上のものが必要です。

たとえば、既に保存されているファイルからこのような複合構造をツリー コントロールにロードする単純なタスクを考えてみましょう。現在、どのコンポーネントが何であるかさえわからないため、コンポーネントがツリー内の親、兄弟、または子であるかどうかを判断することさえできません。基本的に、どの複合パターンが最初に違反しているかを調べるために、ある種の型チェックを行う必要があります。これは特に外部反復子に当てはまります。

最初は、これら 2 つのパターンを組み合わせると大きな可能性があるように見えましたが、今ではほとんど役に立たないようです。

私は、これら 2 つのパターンの真の正当性を見つけようとしています。関数のような単純な教科書の例以外に、どこで最もよく使用できますかPrint() cost()。ファイルからロードされたときに複合体の階層を反映するために、複合体を型キャストしてツリー コントロールを埋める必要があるというのは正しいですか?

4

2 に答える 2

4

iteratorは必要ありません。visitorが必要です。

イテレータは均一なオブジェクト用です。あなたのオブジェクトは間違いなく均一ではありません。さらに、複合は、オブジェクトが均一な方法で使用されている場合にうまく機能する傾向があります。古典的な例の 1 つは、計算する式です。もう 1 つは、画面上にレンダリングする幾何学図形です。繰り返しますが、あなたのケースは古典的な複合パターンにはあまり適合しません。なぜなら、店舗と郡には共通点があまりないからです。

幸いなことに、ビジターはすべてを解決します。都市、郡、ショッピング モール、お店をどう処理するかを知っているビジター クラスを定義します。これらの各クラスを「参照可能」にし、それらを複合的に配置します。コンポジット内のクラスの統一特性は、各クラスにアクセスできることです。リーフ クラスはビジターをコールバックし、自分自身を引数として渡します。ブランチ クラスは最初に自分自身を渡し、次にすべてのコンポーネントにビジターを渡します。これにより、階層全体を適切かつクリーンな方法でトラバースできます。

class County;
class City;
class Mall;
class Shop;

struct ShoppingVisitor {
    virtual void visitCounty(const County& county);
    virtual void visitCity(const City& city);
    virtual void visitMall(const Mall& mall);
    virtual void visitShop(const Shop& shop);
};
struct ShoppingVisitable {
    virtual void accept(ShoppingVisitor& visitor) const;
};
class County : public ShoppingVisitable {
    vector<ShoppingVisitable*> children;
public:
    virtual void accept(ShoppingVisitor& visitor) const {
        visitor.visitCounty(*this);
        for (int i = 0; i != children.size() ; i++) {
            children[i]->accept(visitor);
        }
    }
};
class City : public ShoppingVisitable {
    vector<ShoppingVisitable*> children;
public:
    virtual void accept(ShoppingVisitor& visitor) const {
        visitor.visitCity(*this);
        for (int i = 0; i != children.size() ; i++) {
            children[i]->accept(visitor);
        }
    }
};
struct Mall : public ShoppingVisitable {
    virtual void accept(ShoppingVisitor& visitor) const {
        visitor.visitMall(*this);
    }
};
struct Shop : public ShoppingVisitable {
    virtual void accept(ShoppingVisitor& visitor) const {
        visitor.visitShop(*this);
    }
};
于 2013-10-18T21:19:53.167 に答える
0

コンポジットの stl 準拠の外部イテレータの例については、 githubのこのコンポジット イテレータリポジトリを参照してください。前方反復子です。*iter は基本クラス Node を返します。コンポジットは、パターン ハッチングのファイル システムの例です。参照。これらのスライドのうち 25枚は、説明とクラス図です。ディレクトリはコンポジットです。リーフ ノードは File インスタンスであり、両方の基本コンポーネント クラスは Node.js です。例

Directory::iterator iter_current = top.begin();
Directory::iterator iter_end = top.end();

for (;iter_current != iter_end; ++iter_current) {

      Node &node = *iter_current;

      cout << "[address: " << hex << &node << "] " << node.getName();

      if (dynamic_cast<Directory*>(&node) ) {

            cout << " is a Directory ";
      } else {
            cout << " is a File ";
      }
      cout << endl;
}
于 2014-01-01T00:58:39.220 に答える