真实世界中,像企业组织、文档、图形软件界面等案例,它们在结构上都是分层次的。将系统分层次的方式使得统一管理和添加不同子模块变得容易,在软件开发中,组合模式的设计思想和它们类似。
组合模式是一种结构型设计模式,该模式将对象组合成树状结构,以便于分层和统一管理。
组合模式用于为复杂的分层的系统结构定义基本的蓝图,并对外提供统一的接口,简化了系统组件的使用方法。

1.组件类(Component):声明了统一的抽象接口。它定义了Leaf类和Composite类的通用函数接口。
2.叶子节点类(Leaf):提供了Component类的接口实现,组合模式中的最小单元。
3.组合类(Composite):也提供了Component类的接口实现,其中包含多个Component对象。它对子组件进行了封装,使用客户端(Client)可以像操作单个组件一样使用整个组合。
对应UML类图:

Demo1:先操作叶子节点,后操作主节点
- #include
- #include
-
- class Component {
- public:
- virtual void operation() const = 0;
- virtual ~Component() {}
- };
-
- class Leaf : public Component {
- public:
- Leaf(const std::string& name) : name_(name) {}
- virtual void operation() const override {
- std::cout << "Operation on leaf: " << name_ << std::endl;
- }
- private:
- std::string name_;
- };
-
- class Composite : public Component {
- public:
- Composite(const std::string& name) : name_(name), children_{} {}
- void add(Component* component) {
- children_.push_back(component);
- }
- void operation() const override {
- for (const auto& child : children_) {
- child->operation();
- }
- std::cout << "Operation on composite: " << name_ << std::endl;
- }
- private:
- std::vector
children_; - std::string name_;
- };
-
- int main() {
- Composite root("Composite Root");
- Leaf leaf1("Leaf 1");
- Leaf leaf2("Leaf 2");
- Leaf leaf3("Leaf 3");
-
- root.add(&leaf1);
- root.add(&leaf2);
- root.add(&leaf3);
-
- root.operation();
- return 0;
- }
运行结果:
- Operation on leaf: Leaf 1
- Operation on leaf: Leaf 2
- Operation on leaf: Leaf 3
- Operation on composite: Composite Root
Demo2:先操作主节点,后操作叶子节点
- #include
- #include
-
- class Component {
- public:
- virtual ~Component() {}
- virtual void operation() const = 0;
- };
-
- class Leaf : public Component {
- public:
- Leaf(const std::string& name) : name(name) {}
- virtual void operation() const override {
- std::cout << "Operation on leaf: " << name << '\n';
- }
- private:
- std::string name;
- };
-
- class Composite : public Component {
- public:
- Composite(const std::string& name) : Component(), children(), _name(name) {}
- void add(Component* component) {
- children.push_back(component);
- }
- void remove(Component* component) {
- children.erase(std::remove(children.begin(),
- children.end(),
- component),
- children.end());
- }
- void operation() const override {
- std::cout << "Operation on composite: " << _name << '\n';
- for (auto& child : children)
- child->operation();
- }
-
- private:
- std::vector
children; - std::string _name;
- };
-
- int main() {
- Composite root("Composite1");
- root.add(new Leaf("Leaf1"));
- root.add(new Leaf("Leaf2"));
- root.add(new Composite("Composite2"));
- root.add(new Leaf("Leaf3"));
- root.operation();
-
- return 0;
- }
运行结果:
- Operation on composite: Composite1
- Operation on leaf: Leaf1
- Operation on leaf: Leaf2
- Operation on composite: Composite2
- Operation on leaf: Leaf3
平面设计软件开发:在Photoshop等应用程序中,形状、线条和文本等图形元素可以组合成复杂的设计。
文件系统:使用组合模式来表示文件和目录,从而形成可以统一处理和查询的分层结构。
UI框架开发:基于组合模式,可以让UI组件(如按钮、标签和面板等)组合成复杂的布局或界面。
文档编辑器:使用组合模式来实现文档的段落和文本等层次结构。
企业软件开发:企业软件通常对组织结构进行建模,包括部门、团队和员工。组合模式用于实现组织单位及其内部员工的层次结构。
组合模式的优点:
1.便于维护和重构,修改单个组件的代码不会影响整个系统的功能。
2.有树形结构的先天优势,可以很方便地统一添加、删除或修改子节点。
3.通过拆分子组件,提高了模块间的独立性和可重用性。
4.符合"单一职责原则",组合中的每个对象只关注自己的职责,不需要考虑整个组合中的功能配合。
组合模式的缺点:
1.性能开销大,该模式涉及了对象的动态创建和管理,频繁操作可能会引起性能问题。
2.增加了代码的复杂度,当组合的层次过深的时候,代码的结构会很复杂。
3.类型安全问题,当管理多个组件对象时,可能需要额外的类型转换编码。
代码实战:基于组合模式实现的文件系统
- #include
- #include
-
- class FileSystemComponent {
- public:
- virtual void display() const = 0;
- };
-
- class File : public FileSystemComponent {
- public:
- File(const std::string& name, int size)
- : name(name), size(size)
- {
- }
- void display() const override
- {
- std::cout << "File: " << name <<
- " (" << size << " bytes)" <<
- std::endl;
- }
- private:
- std::string name;
- int size;
- };
-
- class Directory : public FileSystemComponent {
- public:
- Directory(const std::string& name)
- : name(name)
- {
- }
- void display() const override
- {
- std::cout << "Directory: " << name << std::endl;
- for (const auto& component : components) {
- component->display();
- }
- }
- void addComponent(FileSystemComponent* component)
- {
- components.push_back(component);
- }
- private:
- std::string name;
- std::vector
components; - };
-
- int main()
- {
- FileSystemComponent* file1
- = new File("document.txt", 1024);
- FileSystemComponent* file2
- = new File("image.jpg", 2048);
-
- Directory* directory = new Directory("My Documents");
-
- directory->addComponent(file1);
- directory->addComponent(file2);
-
- directory->display();
- return 0;
- }
运行结果:
- Directory: My Documents
- File: document.txt (1024 bytes)
- File: image.jpg (2048 bytes)