从文件系统、UI 树到宏命令,聊聊如何用统一接口抹平‘整体’与‘部分’的差异,让递归逻辑在对象内部自然生长。
你是个将军。
这是个假设。
但请你带入这个角色。
你想发起一场总攻。
你手下有 3 个师。
每个师有 4 个旅。
每个旅有 5 个团。
一直到最底层的列兵。
如果你的代码逻辑是这样的:
1 2 3 4 5 6 7 8 9 10 11
| void General::attack() { for (auto& division : divisions) { for (auto& brigade : division.brigades) { for (auto& regiment : brigade.regiments) { soldier.fire(); } } } }
|
那你这个将军当得太累了。
你不仅要认识师长。
还得认识旅长。
还得知道团长下面是营长。
一旦编制改了。
比如团下面多加了个“特战队”。
你的 attack 方法就得重写。
这不叫指挥。
这叫微操。
真正的指挥是什么?
是你只管下令:“全军出击”。
师长听到命令。
传给旅长:“全旅出击”。
旅长传给团长。
一直传到列兵。
列兵没有下属了。
他听到命令。
就是扣动扳机。
对你来说。
指挥一个师。
和指挥一个兵。
动作应该是一样的。
这就是组合模式 (Composite)。
它想解决的问题只有一个:
如何把“整体”和“部分”,当成同一个东西来用。
无论是排长,班长,士兵,大家都是军人,从代码来讲,我们可以抽象出一个abstructSoldier基类,把士兵当作叶子节点,排长为根节点,我们就构造出一颗树,只需要树根发号施令,并把命令依次传递给自己的子节点即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include <iostream> #include <vector> #include <memory>
class abstructSoldier { public: virtual void attack() = 0; virtual void addSubordinate(std::shared_ptr<abstructSoldier> soldier) {} virtual ~abstructSoldier() {}
protected: std::vector<std::shared_ptr<abstructSoldier>> m_soldiers; };
class Soldier : public abstructSoldier { public: void attack() override { std::cout << "我是士兵,发起冲锋" << std::endl; } };
class Commander : public abstructSoldier { public: void addSubordinate(std::shared_ptr<abstructSoldier> soldier) override { m_soldiers.push_back(soldier); } void attack() override { std::cout << "我是班长,大家随我上" << std::endl; for(auto &item : m_soldiers) { item->attack(); } } };
class PlatoonLeader : public abstructSoldier { public: void addSubordinate(std::shared_ptr<abstructSoldier> soldier) override { m_soldiers.push_back(soldier); } void attack() override { std::cout << "我是排长,指挥大家发起进攻" << std::endl; for(auto &item : m_soldiers) { item->attack(); } } };
int main() { std::shared_ptr<abstructSoldier> p = std::make_shared<PlatoonLeader>();
for(int i = 0; i < 3; i++) { std::shared_ptr<abstructSoldier> c = std::make_shared<Commander>(); for(int j = 0; j < 15; j++) { std::shared_ptr<abstructSoldier> s = std::make_shared<Soldier>(); c->addSubordinate(s); } p->addSubordinate(c); }
p->attack();
return 0; }
|