未能在复合/迭代器设计模式中看到真正的价值

Failing to see real value in Composite/Iterator design pattern

本文关键字:复合 设计模式 迭代器      更新时间:2023-10-16

理论上我的情况可能非常适合复合和迭代器设计模式,但我对这些模式的问题是无法访问底层数据结构,这可能是一个交易破坏者。

当然,我可以在一个国家/地区的城市中的购物中心中开设一家商店,这构成了整体关系,如果我制作它的复合模式,我可以在所有对象上运行通用方法(在大多数情况下),例如商店/购物中心何时开放和关闭,但实际上我们需要的不止于此。

以一个简单的任务为例,将这种复合结构从已保存的文件加载到树控件中。现在我们甚至不知道哪个组件是什么,所以我们甚至无法确定一个组件应该是树中的父组件、兄弟组件还是子组件。我们基本上必须进行某种类型检查,以找出首先反对哪种复合模式。对于外部迭代器尤其如此。

起初,这两种模式的组合似乎具有更大的潜力,但现在它们似乎没有什么用处。

我试图为这两种模式找到真正的理由。除了简单的教科书示例(如Print() cost()函数)之外,在哪里可以最好地使用它。我是否正确,必须将复合类型转换回来以填充树控件以反映从文件加载复合时的层次结构?

你不需要

迭代器,你需要一个访问者

迭代器用于统一的对象;你的对象绝对不是统一的。此外,当以统一的方式使用对象时,复合往往效果更好。一个典型的示例是您计算的表达式;另一个是您在屏幕上渲染的几何图形。同样,您的情况不适合经典的复合模式,因为商店和县没有太多共同点。

幸运的是,访客解决了这一切:定义一个知道如何处理城市、县、商场和商店的访客类。使这些类中的每一个都"可访问",并将它们排列成复合。现在,复合类的统一属性是可以访问每个类。叶类将回调访问者,并将自身作为参数传递。分支类将首先传递自身,然后将访问者传递给其所有组件。这将使您能够以一种漂亮而干净的方式遍历整个层次结构。

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);
    }
};

复合的 stl 兼容外部迭代器的示例,请参阅 github 上的这个复合迭代器存储库。它是一个前向迭代器。*iter 返回基类 Node。复合是图案剖面线中的文件系统示例。有关说明和类图,请参阅这些幻灯片的第 25 页。目录是复合的。叶节点是文件实例,两者的基本组件类是 Node。例

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;
}