本文主要的思路和代码,来自于对以下连接的学习和实现:
组合模式
组合模式是一种行为型设计模式,它将对象组合成树形结构以表示部分 - 整体的层次结构。这种模式使得用户对单个对象和组合对象的使用具有一致性。组合模式主要应用于需要表示复杂对象结构或者需要将对象组合成树形结构的场景。
组合模式的定义和作用:
定义:组合模式通过一种巧妙的设计方案,可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点。
作用:组合模式主要解决了在对象组合树中,如何实现一致性的操作和处理的问题。它使得用户可以方便地对对象树进行操作,而不需要考虑对象的具体类型。组合模式还提供了一种灵活的方式来表示对象结构,可以方便地添加和删除对象。
组合模式是行为型设计模式的一种,它将对象组合成树形结构以表示部分 - 整体的层次结构。在实际应用中,组合模式与其他设计模式有着紧密的联系,常常共同出现在同一个解决方案中。以下是组合模式与其他设计模式的一些关系:
组合模式是一种行为型设计模式,适用于多种场景,如树形对象结构、统一对象处理、动态责任、可变责任和 UI 工具包等。在实际应用中,组合模式与其他设计模式密切相关,共同解决各种问题。以下是组合模式与其他设计模式的一些关系:
CompoundGraphic
类是一个容器,可以包含任意数量的子形状,包括其他复合形状。复合形状具有与简单形状相同的方法。但是,与简单形状不同,复合形状会将请求递归地传递给所有子项,并将结果“求和”。
客户端代码通过与所有形状共享的单一接口与所有形状进行交互。因此,客户端不知道自己正在处理简单形状还是复合形状。客户端可以在不与组成该结构的具体类耦合的情况下处理非常复杂的对象结构。
代码结构分析:
// The component interface declares common operations for both
// simple and complex objects of a composition.
interface Graphic is
method move(x, y)
method draw()
// The leaf class represents end objects of a composition. A
// leaf object can't have any sub-objects. Usually, it's leaf
// objects that do the actual work, while composite objects only
// delegate to their sub-components.
class Dot implements Graphic is
field x, y
constructor Dot(x, y) { ... }
method move(x, y) is
this.x += x, this.y += y
method draw() is
// Draw a dot at X and Y.
// All component classes can extend other components.
class Circle extends Dot is
field radius
constructor Circle(x, y, radius) { ... }
method draw() is
// Draw a circle at X and Y with radius R.
// The composite class represents complex components that may
// have children. Composite objects usually delegate the actual
// work to their children and then "sum up" the result.
class CompoundGraphic implements Graphic is
field children: array of Graphic
// A composite object can add or remove other components
// (both simple or complex) to or from its child list.
method add(child: Graphic) is
// Add a child to the array of children.
method remove(child: Graphic) is
// Remove a child from the array of children.
method move(x, y) is
foreach (child in children) do
child.move(x, y)
// A composite executes its primary logic in a particular
// way. It traverses recursively through all its children,
// collecting and summing up their results. Since the
// composite's children pass these calls to their own
// children and so forth, the whole object tree is traversed
// as a result.
method draw() is
// 1. For each child component:
// - Draw the component.
// - Update the bounding rectangle.
// 2. Draw a dashed rectangle using the bounding
// coordinates.
// The client code works with all the components via their base
// interface. This way the client code can support simple leaf
// components as well as complex composites.
class ImageEditor is
field all: CompoundGraphic
method load() is
all = new CompoundGraphic()
all.add(new Dot(1, 2))
all.add(new Circle(5, 3, 10))
// ...
// Combine selected components into one complex composite
// component.
method groupSelected(components: array of Graphic) is
group = new CompoundGraphic()
foreach (component in components) do
group.add(component)
all.remove(component)
all.add(group)
// All components will be drawn.
all.draw()
组合模式是使用抽象基类或接口Component
实现的,它声明了公共操作。两个具体类Leaf
和Composite
继承自Component
。以下是这些概念的伪代码描述:
class Component {
public:
virtual void Add(Component a) { }
virtual void Remove() { }
virtual void Delete(Component a) { }
};
class Leaf : public Component {
public:
void Add(Component a) {
cout << "something is added to the leaf" << endl;
}
void Remove() {
cout << "something is removed from the leaf" << endl;
}
void Delete(Component a) {
cout << "something is deleted from leaf" << endl;
}
};
class Composite : public Component {
vector<Component> compositeComponents;
public:
void AddElement(Component a) {
compositeComponents.push_back(a);
}
void Add(Component a) {
cout << "something is added to the composite" << endl;
}
void Remove() {
cout << "something is removed from the composite" << endl;
}
void Delete(Component a) {
cout << "something is deleted from the composite";
}
};
在这个伪代码中,Component
是一个抽象基类,具有三个方法:Add
、Remove
和Delete
。Leaf
和Composite
类继承自Component
并实现这些方法。Composite
类还包含一个表示其子组件的Component
对象向量¹。
这种结构允许您统一处理单个对象(Leaf
)和对象的组合(Composite
)。
Composite 模式的真实案例是树形数据结构,例如目录树。在这种情况下,抽象部分将表示一个目录,具体部分将表示文件或其他目录。以下是使用组合模式的伪代码示例:
# 抽象部分
class Directory:
def add_file(self, file):
pass
def remove_file(self, file):
pass
def list_files(self):
pass
# 具体部分
class File:
def __init__(self, name):
self.name = name
class DirectoryNode:
def __init__(self, directory):
self.directory = directory
self.children = []
def add_child(self, child):
self.children.append(child)
def remove_child(self, child):
self.children.remove(child)
def list_children(self):
for child in self.children:
print(child.name)
# 客户端代码
directory = Directory()
file1 = File("file1.txt")
file2 = File("file2.txt")
directory_node = DirectoryNode(directory)
directory_node.add_child(file1)
directory_node.add_child(file2)
directory.list_files() # 输出:file1.txt, file2.txt
在上述代码中,Directory
类是抽象部分,它定义了目录的基本操作,如添加文件、删除文件和列出文件。File
类是具体部分,表示一个文件对象。DirectoryNode
类是具体部分的组合体,它包含一个Directory
对象和一个子节点列表。通过调用add_child
和remove_child
方法,可以向目录树中添加或删除子节点。最后,客户端代码创建了一个目录对象和两个文件对象,并将这两个文件对象作为子节点添加到目录节点中。然后,通过调用list_files
方法,列出了目录中的所有文件。
#include
class Component {
public:
virtual void operation() = 0;
};
class Leaf : public Component {
public:
void operation() override {
std::cout << "I am a leaf." << std::endl;
}
};
class Composite : public Component {
public:
void operation() override {
std::cout << "I am a composite." << std::endl;
for (auto& child : children) {
child->operation();
}
}
这段代码展示了组合模式的实现。组合模式是一种结构型设计模式,它允许将对象组织成树形结构,使得客户端可以以统一的方式处理单个对象和组合对象。
代码中定义了一个抽象基类Component
,其中包含一个纯虚函数operation()
。这个函数在子类中被重写,用于执行具体的操作。
接下来定义了两个子类:Leaf
和Composite
。Leaf
类表示叶子节点,它从Component
类继承,并重写了operation()
函数,输出"I am a leaf.“。Composite
类表示复合节点,它也从Component
类继承,并重写了operation()
函数。在这个函数中,首先输出"I am a composite.”,然后通过循环遍历子节点(children
),对每个子节点调用operation()
函数。
通过组合模式,可以将叶子节点和复合节点统一对待,无论它们是单独使用还是作为其他节点的一部分。这种灵活性使得代码更加可扩展和易于维护。
#include
#include
class Graphic {
public:
virtual void move(int x, int y) = 0;
virtual void draw() = 0;
};
class Dot : public Graphic {
protected:
int x, y;
public:
Dot(int x, int y) : x(x), y(y) {}
void move(int x, int y) override {
this->x += x; this->y += y;
}
void draw() override {
std::cout << "Draw a dot at " << x << " and " << y << std::endl;
}
};
class Circle : public Dot {
protected:
int radius;
public:
Circle(int x, int y, int radius) : Dot(x, y), radius(radius) {}
void draw() override {
std::cout << "Draw a circle at " << x << " and " << y << " with radius " << radius << std::endl;
}
};
class CompoundGraphic : public Graphic {
protected:
std::vector<Graphic*> children;
public:
void add(Graphic* child) {
children.push_back(child);
}
void remove(Graphic* child) {
children.erase(std::remove(children.begin(), children.end(), child), children.end());
}
void move(int x, int y) override {
for (Graphic* child : children)
child->move(x, y);
}
void draw() override {
for (Graphic* child : children)
child->draw();
// Draw a dashed rectangle using the bounding coordinates.
// This part is left as an exercise.
}
};
class ImageEditor {
protected:
CompoundGraphic* all;
public:
void load() {
all = new CompoundGraphic();
all->add(new Dot(1, 2));
all->add(new Circle(5, 3, 10));
// ...
}
void groupSelected(std::vector<Graphic*> components) {
CompoundGraphic* group = new CompoundGraphic();
for (Graphic* component : components) {
group->add(component);
all->remove(component);
}
all->add(group);
all->draw();
}
};
这段代码定义了一个抽象基类Component
,其中包含三个方法:Add
、Remove
和Delete
。Leaf
和Composite
类继承自Component
并实现了这些方法。Composite
类还包含一个Component
指针的向量,表示其子组件。这种结构允许您统一处理单个对象(Leaf
)和对象的组合(Composite
)。
需要注意的是,这段代码是Composite Pattern的基本实现,并没有包含任何特定的功能。需要用自己逻辑替换占位符方法。同时,请记住在使用C++中的原始指针时正确管理内存。如果适用,可以考虑使用智能指针。
我们可以在任何支持C++11或更高版本的C++环境中编译和运行此代码。如果需要想查看这些方法的输出,需要创建Leaf
和Composite
的实例,调用它们的方法,并将输出打印到控制台。
#ifndef _GEOM_EXAMPLE_H_
#define _GEOM_EXAMPLE_H_
#include
// The component interface declares common operations for both
// simple and complex objects of a composition.
class Graphic
{
public:
virtual void move(int x, int y) = 0;
virtual void draw() = 0;
};
// The leaf class represents end objects of a composition. A
// leaf object can't have any sub-objects. Usually, it's leaf
// objects that do the actual work, while composite objects only
// delegate to their sub-components.
class Dot : public Graphic
{
protected:
int x, y;
public:
Dot(int x, int y);
void move(int x, int y) override;
void draw() override;
};
// All component classes can extend other components.
class Circle : public Dot
{
private:
int radius;
public:
Circle(int x, int y, int radius);
void draw() override;
};
// The composite class represents complex components that may
// have children. Composite objects usually delegate the actual
// work to their children and then "sum up" the result.
class CompoundGraphic : public Graphic
{
private:
std::vector<Graphic*> children;
public:
void add(Graphic* child);
void remove(Graphic* child);
void move(int x, int y) override;
void draw() override;
};
// The client code works with all the components via their base
// interface. This way the client code can support simple leaf
// components as well as complex composites.
class ImageEditor
{
private:
CompoundGraphic all;
public:
void load();
// Combine selected components into one complex composite
// component.
void groupSelected(std::vector<Graphic*> components);
};
class GeomCompositeTest
{
public:
static void GeomCompositeExample();
};
#endif // _GEOM_EXAMPLE_H_
#include "geom_example.h"
#include
Dot::Dot(int x, int y)
: x(x), y(y)
{
}
void Dot::move(int x, int y)
{
this->x += x;
this->y += y;
}
void Dot::draw()
{
std::cout << "Draw a dot at (" << x << ", " << y << ")." << std::endl;
}
Circle::Circle(int x, int y, int radius)
: Dot(x, y), radius(radius)
{
}
void Circle::draw()
{
std::cout << "Draw a circle at (" << x << ", " << y << ") with radius " << radius << "." << std::endl;
}
void CompoundGraphic::add(Graphic* child)
{
children.push_back(child);
}
void CompoundGraphic::remove(Graphic* child)
{
for (auto it = children.begin(); it != children.end(); ++it) {
if (*it == child) {
children.erase(it);
break;
}
}
}
void CompoundGraphic::move(int x, int y)
{
for (Graphic* child : children) {
child->move(x, y);
}
}
void CompoundGraphic::draw()
{
std::cout << "1. For each child component:" << std::endl;
for (Graphic* child : children) {
child->draw(); // Draw the component.
// Update the bounding rectangle. (Not shown in the code.)
}
std::cout << "2. Draw a dashed rectangle using the bounding coordinates." << std::endl;
}
void ImageEditor::load()
{
all = CompoundGraphic();
all.add(new Dot(1, 2));
all.add(new Circle(5, 3, 10));
// ...
}
void ImageEditor::groupSelected(std::vector<Graphic*> components)
{
CompoundGraphic group;
for (Graphic* component : components) {
group.add(component);
all.remove(component);
}
all.add(&group);
// All components will be drawn.
all.draw();
}
void GeomCompositeTest::GeomCompositeExample()
{
ImageEditor editor;
editor.load();
std::vector<Graphic*> components;
components.push_back(new Dot(1, 2));
components.push_back(new Circle(5, 3, 10));
components.push_back(new Dot(7, 8));
components.push_back(new Circle(10, 11, 20));
editor.groupSelected(components);
}
提供的C++代码是组合模式的实现,组合模式是一种设计模式,用于将一组对象以与单个对象的相同方式处理。组合模式的概念允许您将对象组合成树形结构,以表示部分-整体层次结构。
在此代码中,我们有以下类:
Component
:这是一个抽象基类,声明了简单和复杂对象的组合的共同操作。它声明了一个纯虚函数operation()
。
Leaf
:这个类代表组合的结束对象(叶子对象)。它从Component
类继承并实现了operation()
方法。在这个方法中,它只是打印出"I am a leaf."。
Composite
:这个类代表可能有子对象的复杂组件。它也从Component
类继承并实现了operation()
方法。在这个方法中,它首先打印出"I am a composite.",然后遍历其子组件并调用它们的operation()
方法。
这种结构允许您统一对待单个对象(Leaf
)和对象的组合(Composite
)。您可以对所有复合对象执行的操作通常具有最低公共分母关系。
请注意,这段代码是不完整的。Composite
类应该包含一个容器(如向量或列表)来保存其子组件,并提供添加或删除子组件的方法。此外,代码目前缺少与之交互的客户端。
提供的C++代码是组合模式的一个实现,组合模式是一种设计模式,用于在需要以单个对象的方式处理一组对象的情况。组合模式的概念是允许您将对象组合成树形结构,以表示部分-整体层次结构。
在此代码中,我们有以下几个类:
Component
:这是一个抽象基类,声明了简单和复杂对象的共同操作。它声明了一个纯虚函数operation()
。它还具有设置和获取组件父级的方法和添加或删除子组件的方法。
Leaf
:这个类代表组合的结束对象(叶子对象)。它从Component
类继承并实现了operation()
方法。在此方法中,它只是打印出"I am a leaf."。
Composite
:这个类代表可能有子组件的复杂组件。它也从Component
类继承并实现了operation()
方法。在此方法中,它首先打印出"I am a composite.",然后遍历其子组件并调用它们的operation()
方法。
ClientCode
函数接受一个Component
对象并调用其operation()
方法。ClientCode2
函数接受两个Component
对象。如果第一个是一个复合对象,它将第二个添加为其子对象。然后它调用第一个的operation()
方法。
CompositeConceptionalExample
函数演示了如何使用这些类。它创建了一个简单的叶子组件和一个包含叶子节点和复合节点的复合树,然后将它们传递给客户端代码。
请注意,此代码未正确管理内存。它使用new
创建了几个对象,但没有使用delete
删除它们。在现实世界的代码中,应始终记住使用delete
删除用new
创建的对象,以防止内存泄漏。如果适用,请考虑使用智能指针。
提供的代码是C++中组合模式的一个实现,它用于统一处理单个对象和对象的组成。代码分为两个文件:geom_example.h
(头文件)和geom_example.cpp
(实现文件)。
在geom_example.h
中,我们有以下几个类:
Graphic
:这是一个抽象基类,声明了组合中简单和复杂对象的常见操作。它声明了两个纯虚函数:move(int x, int y)
和draw()
。Dot
:这个类代表组合的结束对象(叶子对象)。它从Graphic
类继承并实现了move(int x, int y)
和draw()
方法。Circle
:这个类扩展了Dot
类,代表一个更复杂的对象,也可以是组合的一部分。它重写了Dot
类中的draw()
方法。CompoundGraphic
:这个类代表可能具有子组件的复杂组件。它也从Graphic
类继承并实现了add(Graphic* child)
、remove(Graphic* child)
、move(int x, int y)
和draw()
方法。ImageEditor
:这个类通过其基接口与所有组件一起工作。它具有加载组件和将选定的组件组合成一个复杂复合组件的方法。在geom_example.cpp
中,这些类被实现:
Dot
和Circle
类有构造函数来初始化它们的特性,它们实现了在Graphic
接口中声明的move(int x, int y)
和draw()
方法。CompoundGraphic
类实现了添加或删除子组件、移动所有子组件和绘制所有子组件的方法。ImageEditor
类将组件加载到复合对象中,将选定的组件组合成一个新的复合对象,从旧的复合对象中删除它们,将新的复合对象添加到旧的复合对象中,并绘制所有组件。这段代码演示了如何使用组合模式统一处理单个对象(Dot
和Circle
)和对象的组成(CompoundGraphic
)。
追寻与内心共鸣的生活,未来会逐渐揭晓答案。
Pursue the life that resonates with your heart, and the future will gradually reveal the answer.