Component(抽象构件):定义了所有对象所共有的接口,包括组合对象和叶子对象。声明了所有用来管理子组件的方法,比如添加、删除和获取子组件等,但在组合对象中实现这些方法,而在叶子对象中则可能提供默认或空实现。
Leaf(叶子节点):是组合结构中的基本元素,没有子节点,实现了Component
接口。
Composite(组合节点):包含了多个Component
对象,可以用来存储和管理它的子部件,同时自身也是Component
接口的实现。组合节点提供了用于管理子节点的方法实现。
下面是一个简单的C++代码示例,展示了如何实现组合模式:
// 抽象构件 Component
class Component {
public:
virtual ~Component() {}
virtual void operation() = 0; // 假设这是所有组件都有的通用操作
virtual void add(Component* child) {} // 在组合节点中实现,在叶子节点中可能是空操作
virtual void remove(Component* child) {} // 同上
virtual Component* getChild(int index) { return nullptr; } // 返回指定索引的子组件,叶子节点返回nullptr
};
// 叶子节点 Leaf
class Leaf : public Component {
public:
void operation() override {
// 叶子节点的具体实现
}
};
// 组合节点 Composite
class Composite : public Component {
private:
vector<Component*> children; // 存储子组件的容器
public:
void add(Component* child) override {
children.push_back(child);
}
void remove(Component* child) override {
auto it = find(children.begin(), children.end(), child);
if (it != children.end()) {
children.erase(it);
}
}
Component* getChild(int index) override {
if (index >= 0 && index < children.size()) {
return children[index];
}
return nullptr;
}
void operation() override {
for (auto& child : children) {
child->operation(); // 递归调用子组件的操作
}
// 组合节点自己的具体实现
}
};
// 使用示例
int main() {
Leaf* leaf1 = new Leaf();
Leaf* leaf2 = new Leaf();
Composite* composite = new Composite();
composite->add(leaf1);
composite->add(leaf2);
composite->operation(); // 会同时调用两个叶子节点以及自身的方法
delete leaf1;
delete leaf2;
delete composite;
return 0;
}
在这个例子中,Component
是抽象基类,Leaf
和Composite
都是其派生类。Composite
内部维护了一个容器来保存子Component
对象,并在operation()
方法中通过递归来调用每个子组件的operation()
方法。这样,无论是单独调用叶子节点的操作,还是调用组合节点的操作,客户端代码都可以保持一致性。
在实际项目中,为了更好地管理和资源释放,建议使用智能指针来代替原始指针,尤其是在C++11之后,可以有效避免内存泄漏和悬挂指针的问题。
当然,我们可以进一步完善上述代码示例,引入智能指针以提高内存管理的安全性。以下是如何使用C++11的std::shared_ptr
来重构组合模式的例子:
#include
#include
// 抽象构件 Component
class Component {
public:
virtual ~Component() {}
virtual void operation() = 0;
virtual void add(std::shared_ptr<Component> child) = 0;
virtual void remove(std::shared_ptr<Component> child) = 0;
virtual std::shared_ptr<Component> getChild(int index) = 0;
};
// 叶子节点 Leaf
class Leaf : public Component {
public:
void operation() override {
// 叶子节点的具体实现
}
// 对于叶子节点,下述方法为空实现
void add(std::shared_ptr<Component> child) override {}
void remove(std::shared_ptr<Component> child) override {}
std::shared_ptr<Component> getChild(int index) override {
return nullptr;
}
};
// 组合节点 Composite
class Composite : public Component {
private:
std::vector<std::shared_ptr<Component>> children;
public:
void add(std::shared_ptr<Component> child) override {
children.push_back(child);
}
void remove(std::shared_ptr<Component> child) override {
auto it = std::find(children.begin(), children.end(), child);
if (it != children.end()) {
children.erase(it);
}
}
std::shared_ptr<Component> getChild(int index) override {
if (index >= 0 && index < children.size()) {
return children[index];
}
return nullptr;
}
void operation() override {
for (const auto& child : children) {
child->operation(); // 递归调用子组件的操作
}
// 组合节点自己的具体实现
}
};
// 使用示例
int main() {
auto leaf1 = std::make_shared<Leaf>();
auto leaf2 = std::make_shared<Leaf>();
auto composite = std::make_shared<Composite>();
composite->add(leaf1);
composite->add(leaf2);
composite->operation(); // 会同时调用两个叶子节点以及自身的方法
return 0;
}
通过使用std::shared_ptr
,我们不再需要手动进行内存管理,当组合对象或叶子对象不再被引用时,它们占用的内存会自动释放。这样不仅提高了代码的健壮性和可维护性,还降低了出现内存泄露的风险。
尽管以上代码已经实现了组合模式的核心思想,但在实际应用中,我们可能还需要考虑其他因素,例如访问子组件的方式可能不仅仅是按索引获取,还可以支持更灵活的方式来遍历所有子组件。下面是对上述代码进行扩展,加入迭代器以便更方便地遍历子组件:
#include
#include
#include // 引入迭代器功能
// 抽象构件 Component
class Component {
public:
virtual ~Component() {}
virtual void operation() = 0;
virtual void add(std::shared_ptr<Component> child) = 0;
virtual void remove(std::shared_ptr<Component> child) = 0;
// 提供迭代器接口,使得可以通过范围for循环遍历子组件
virtual std::vector<std::shared_ptr<Component>>::const_iterator begin() const = 0;
virtual std::vector<std::shared_ptr<Component>>::const_iterator end() const = 0;
};
// 叶子节点 Leaf
class Leaf : public Component {
public:
void operation() override {
// 叶子节点的具体实现
}
// 对于叶子节点,下述方法为空实现
void add(std::shared_ptr<Component> child) override {}
void remove(std::shared_ptr<Component> child) override {}
std::vector<std::shared_ptr<Component>>::const_iterator begin() const override {
static std::shared_ptr<Component> emptyList[] = {};
return emptyList;
}
std::vector<std::shared_ptr<Component>>::const_iterator end() const override {
static std::shared_ptr<Component> emptyList[] = {};
return emptyList + 0;
}
};
// 组合节点 Composite
class Composite : public Component {
private:
std::vector<std::shared_ptr<Component>> children;
public:
void add(std::shared_ptr<Component> child) override {
children.push_back(child);
}
void remove(std::shared_ptr<Component> child) override {
auto it = std::find(children.begin(), children.end(), child);
if (it != children.end()) {
children.erase(it);
}
}
std::shared_ptr<Component> getChild(int index) override {
if (index >= 0 && index < children.size()) {
return children[index];
}
return nullptr;
}
std::vector<std::shared_ptr<Component>>::const_iterator begin() const override {
return children.begin();
}
std::vector<std::shared_ptr<Component>>::const_iterator end() const override {
return children.end();
}
void operation() override {
for (const auto& child : children) {
child->operation(); // 递归调用子组件的操作
}
// 组合节点自己的具体实现
}
};
// 使用示例,现在可以使用范围for循环遍历子组件
int main() {
auto leaf1 = std::make_shared<Leaf>();
auto leaf2 = std::make_shared<Leaf>();
auto composite = std::make_shared<Composite>();
composite->add(leaf1);
composite->add(leaf2);
// 遍历并调用所有子组件的操作
for (const auto& child : *composite) {
child->operation();
}
return 0;
}
通过添加迭代器接口,现在可以直接使用范围for循环遍历组合对象的所有子组件,这使得代码更加简洁易读,同时也符合STL容器和算法的设计风格。
另外,对于组合模式的应用场景,通常还包括动态构建和修改组合结构的需求。以下是一个更完整的示例,展示如何在运行时创建和调整组合结构,并演示如何利用组合模式简化客户端代码:
#include
#include
#include
#include
// 抽象构件 Component
class Component {
public:
virtual ~Component() {}
virtual void operation() const = 0;
virtual void add(std::shared_ptr<Component> child) = 0;
virtual void remove(std::shared_ptr<Component> child) = 0;
virtual std::vector<std::shared_ptr<Component>>::const_iterator begin() const = 0;
virtual std::vector<std::shared_ptr<Component>>::const_iterator end() const = 0;
};
// 叶子节点 Leaf
class Leaf : public Component {
public:
explicit Leaf(const std::string& name) : name(name) {}
void operation() const override {
std::cout << "Leaf: " << name << std::endl;
}
// 对于叶子节点,下述方法为空实现
void add(std::shared_ptr<Component> child) override {}
void remove(std::shared_ptr<Component> child) override {}
std::vector<std::shared_ptr<Component>>::const_iterator begin() const override {
static std::shared_ptr<Component> emptyList[] = {};
return emptyList;
}
std::vector<std::shared_ptr<Component>>::const_iterator end() const override {
static std::shared_ptr<Component> emptyList[] = {};
return emptyList + 0;
}
private:
std::string name;
};
// 组合节点 Composite
class Composite : public Component {
public:
void operation() const override {
std::cout << "Composite: " << std::endl;
for (const auto& child : children) {
child->operation();
}
}
void add(std::shared_ptr<Component> child) override {
children.push_back(child);
}
void remove(std::shared_ptr<Component> child) override {
auto it = std::find(children.begin(), children.end(), child);
if (it != children.end()) {
children.erase(it);
}
}
std::vector<std::shared_ptr<Component>>::const_iterator begin() const override {
return children.begin();
}
std::vector<std::shared_ptr<Component>>::const_iterator end() const override {
return children.end();
}
private:
std::vector<std::shared_ptr<Component>> children;
};
// 客户端代码
int main() {
auto leaf1 = std::make_shared<Leaf>("Leaf1");
auto leaf2 = std::make_shared<Leaf>("Leaf2");
auto composite1 = std::make_shared<Composite>();
auto composite2 = std::make_shared<Composite>();
composite1->add(leaf1);
composite1->add(composite2);
composite2->add(leaf2);
// 调用组合结构的操作
composite1->operation();
// 动态修改组合结构
composite1->remove(leaf1);
composite2->add(leaf1);
composite1->operation(); // 结构改变后重新调用操作
return 0;
}
这个示例中,我们创建了一个包含两个叶子节点和一个嵌套组合节点的组合结构,并能够在运行时根据需求动态添加、删除组件。客户端代码只需直接调用组合结构的operation()
方法,而无需关心组合的具体结构和内部细节。
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(11-20)
50个开发必备的Python经典脚本(21-30)
50个开发必备的Python经典脚本(31-40)
50个开发必备的Python经典脚本(41-50)
————————————————
最后我们放松一下眼睛