Hierarchical Composition with Composite
The Composite pattern is designed to let you compose objects into tree structures to represent part-whole hierarchies. This is especially useful when you want to treat individual objects and compositions of objects uniformly. Common scenarios include representing directories and files in a file system, graphical scene graphs, or organizational charts. By using the Composite pattern, you can build structures where both simple and complex elements conform to the same interface, allowing you to process them in a consistent way.
main.cpp
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677#include <iostream> #include <vector> #include <memory> #include <string> // Base Component class FileSystemEntity { public: virtual ~FileSystemEntity() = default; virtual void display(int indent = 0) const = 0; virtual size_t getSize() const = 0; }; // Leaf class File : public FileSystemEntity { std::string name_; size_t size_; public: File(const std::string& name, size_t size) : name_(name), size_(size) {} void display(int indent = 0) const override { std::cout << std::string(indent, ' ') << "- " << name_ << " (" << size_ << " bytes)" << std::endl; } size_t getSize() const override { return size_; } }; // Composite class Directory : public FileSystemEntity { std::string name_; std::vector<std::shared_ptr<FileSystemEntity>> children_; public: Directory(const std::string& name) : name_(name) {} void add(const std::shared_ptr<FileSystemEntity>& entity) { children_.push_back(entity); } void display(int indent = 0) const override { std::cout << std::string(indent, ' ') << "+ " << name_ << "/" << std::endl; for (const auto& child : children_) child->display(indent + 2); } size_t getSize() const override { size_t total = 0; for (const auto& child : children_) total += child->getSize(); return total; } }; int main() { auto root = std::make_shared<Directory>("root"); auto home = std::make_shared<Directory>("home"); auto user = std::make_shared<Directory>("user"); auto file1 = std::make_shared<File>("file1.txt", 1200); auto file2 = std::make_shared<File>("file2.txt", 800); auto file3 = std::make_shared<File>("notes.md", 500); user->add(file1); user->add(file2); home->add(user); root->add(home); root->add(file3); root->display(); std::cout << "Total size: " << root->getSize() << " bytes" << std::endl; }
Using the Composite pattern greatly simplifies client code that needs to work with tree-like structures. Instead of writing separate logic for handling files and directories, you interact with the base FileSystemEntity interface. Whether you traverse a single file or an entire directory tree, the same methods—such as display and getSize—can be called. This uniformity makes it easy to extend the hierarchy, add new types of components, or process the structure recursively without changing client code.
Obrigado pelo seu feedback!
Pergunte à IA
Pergunte à IA
Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo
Can you give an example of how the Composite pattern is implemented in code?
What are some real-world use cases for the Composite pattern?
How does the Composite pattern differ from other structural patterns?
Awesome!
Completion rate improved to 10
Hierarchical Composition with Composite
Deslize para mostrar o menu
The Composite pattern is designed to let you compose objects into tree structures to represent part-whole hierarchies. This is especially useful when you want to treat individual objects and compositions of objects uniformly. Common scenarios include representing directories and files in a file system, graphical scene graphs, or organizational charts. By using the Composite pattern, you can build structures where both simple and complex elements conform to the same interface, allowing you to process them in a consistent way.
main.cpp
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677#include <iostream> #include <vector> #include <memory> #include <string> // Base Component class FileSystemEntity { public: virtual ~FileSystemEntity() = default; virtual void display(int indent = 0) const = 0; virtual size_t getSize() const = 0; }; // Leaf class File : public FileSystemEntity { std::string name_; size_t size_; public: File(const std::string& name, size_t size) : name_(name), size_(size) {} void display(int indent = 0) const override { std::cout << std::string(indent, ' ') << "- " << name_ << " (" << size_ << " bytes)" << std::endl; } size_t getSize() const override { return size_; } }; // Composite class Directory : public FileSystemEntity { std::string name_; std::vector<std::shared_ptr<FileSystemEntity>> children_; public: Directory(const std::string& name) : name_(name) {} void add(const std::shared_ptr<FileSystemEntity>& entity) { children_.push_back(entity); } void display(int indent = 0) const override { std::cout << std::string(indent, ' ') << "+ " << name_ << "/" << std::endl; for (const auto& child : children_) child->display(indent + 2); } size_t getSize() const override { size_t total = 0; for (const auto& child : children_) total += child->getSize(); return total; } }; int main() { auto root = std::make_shared<Directory>("root"); auto home = std::make_shared<Directory>("home"); auto user = std::make_shared<Directory>("user"); auto file1 = std::make_shared<File>("file1.txt", 1200); auto file2 = std::make_shared<File>("file2.txt", 800); auto file3 = std::make_shared<File>("notes.md", 500); user->add(file1); user->add(file2); home->add(user); root->add(home); root->add(file3); root->display(); std::cout << "Total size: " << root->getSize() << " bytes" << std::endl; }
Using the Composite pattern greatly simplifies client code that needs to work with tree-like structures. Instead of writing separate logic for handling files and directories, you interact with the base FileSystemEntity interface. Whether you traverse a single file or an entire directory tree, the same methods—such as display and getSize—can be called. This uniformity makes it easy to extend the hierarchy, add new types of components, or process the structure recursively without changing client code.
Obrigado pelo seu feedback!