周口学做网站,门户网站系统设计,一步步教你为网站开发android客户端,网页设计的五大原则C 设计模式 —— 组合模式 0. 引用连接
本文主要的思路和代码#xff0c;来自于对以下连接的学习和实现#xff1a;
组合模式
1. 引言
1.1 什么是组合模式#xff1f;
组合模式的定义组合模式的作用
组合模式是一种行为型设计模式#xff0c;它将对象组合成树形结构以…C 设计模式 —— 组合模式 0. 引用连接
本文主要的思路和代码来自于对以下连接的学习和实现
组合模式
1. 引言
1.1 什么是组合模式
组合模式的定义组合模式的作用
组合模式是一种行为型设计模式它将对象组合成树形结构以表示部分 - 整体的层次结构。这种模式使得用户对单个对象和组合对象的使用具有一致性。组合模式主要应用于需要表示复杂对象结构或者需要将对象组合成树形结构的场景。 组合模式的定义和作用 定义组合模式通过一种巧妙的设计方案可以一致性地处理整个树形结构或者树形结构的一部分也可以一致性地处理树形结构中的叶子节点不包含子节点的节点和容器节点。 作用组合模式主要解决了在对象组合树中如何实现一致性的操作和处理的问题。它使得用户可以方便地对对象树进行操作而不需要考虑对象的具体类型。组合模式还提供了一种灵活的方式来表示对象结构可以方便地添加和删除对象。
1.2 组合模式与其他设计模式的关系
组合模式是行为型设计模式的一种它将对象组合成树形结构以表示部分 - 整体的层次结构。在实际应用中组合模式与其他设计模式有着紧密的联系常常共同出现在同一个解决方案中。以下是组合模式与其他设计模式的一些关系
装饰者模式 : 装饰者模式与组合模式在结构上有相似之处但它们的目的不同。装饰者模式通过动态地给一个对象添加职责使其具有更多的功能而组合模式关注的是将对象组合成树形结构以表示部分 - 整体的层次结构。两者都依赖于递归组合来组织大量对象。在某些情况下装饰者模式和组合模式可以结合使用以实现更加灵活的对象结构。责任链模式 : 责任链模式用于处理具有多个处理步骤的问题它将请求沿着处理器链进行传递。组合模式则关注将对象组合成树形结构以表示部分 - 整体的层次结构。虽然这两个模式的用途不同但它们可以结合使用。例如可以使用组合模式构建一个复杂的对象结构然后使用责任链模式处理该结构中的请求。迭代器模式 : 迭代器模式允许在不暴露底层数据结构的情况下遍历和访问数据。在组合模式中可以使用迭代器来遍历复合对象的子元素。迭代器模式抽象了遍历组件的过程确保每个元素都被访问到同时不暴露底层数据结构的细节。访问者模式 : 访问者模式允许在不改变对象结构的前提下定义新的操作。在组合模式中可以将访问者模式应用于复合结构以便在不更改现有类层次结构的情况下对元素执行操作。访问者模式使您可以在现有代码中添加新行为而无需修改现有代码。 总之在实际软件开发中设计模式往往不会孤立存在。组合模式与其他设计模式之间的紧密联系使得开发人员可以根据具体需求和场景将这些模式结合使用以实现更加灵活、高效和可扩展的软件系统。
1.3 组合模式适用的场景
组合模式是一种行为型设计模式适用于多种场景如树形对象结构、统一对象处理、动态责任、可变责任和 UI 工具包等。在实际应用中组合模式与其他设计模式密切相关共同解决各种问题。以下是组合模式与其他设计模式的一些关系
树形对象结构 : 组合模式适用于实现树形对象结构如组织结构、文件系统、UI 元素等。这种结构可以方便地表示部分 - 整体的层次关系。在组合模式中对象通过递归组合形成树状结构使得客户代码可以统一处理简单元素和复杂元素。统一对象处理 : 组合模式允许客户代码以统一的方式处理简单元素和复杂元素。这种统一处理方式可以简化客户端代码提高代码的可维护性和可扩展性。通过组合模式客户端可以忽略对象的复杂内部结构而仅关注对象的整体行为。动态责任 : 组合模式允许在运行时动态地为单个对象添加责任而无需修改现有代码。这种动态责任分配可以提高系统的灵活性使其能够适应不断变化的需求。在组合模式中可以通过将新的责任分配给现有的对象来实现动态责任。可变责任 : 组合模式适用于责任可能随时间变化的场景。在组合模式中对象可以具有不同的责任这使得系统能够适应不断变化的需求。通过组合模式可以轻松地为对象添加新的责任而无需修改现有代码。UI 工具包 : 组合模式在 UI 工具包中具有广泛的应用。在这种场景下顶级 UI 元素由许多较小的独立底层 UI 元素组成这些元素都响应相同的事件和操作。通过使用组合模式可以轻松地管理 UI 元素的层次结构并确保它们以一致的方式响应事件。计费系统 : 在计费系统中组合模式可以应用于处理复杂的活动记录。在这种场景下重要的是能够生成正确的计费而不关心活动的具体细节。通过使用组合模式可以将复杂的活动记录组织成一个树形结构以便生成正确的计费。 组合模式与其他设计模式密切相关它们共同解决各种实际问题。在实际应用中可以根据具体需求和场景将组合模式与其他设计模式结合使用以实现更加灵活、高效和可扩展的软件系统。
2. 组合模式的实现
2.1 组合模式概念伪代码
2.1.1 图形概念组合伪代码
CompoundGraphic 类是一个容器可以包含任意数量的子形状包括其他复合形状。复合形状具有与简单形状相同的方法。但是与简单形状不同复合形状会将请求递归地传递给所有子项并将结果“求和”。 客户端代码通过与所有形状共享的单一接口与所有形状进行交互。因此客户端不知道自己正在处理简单形状还是复合形状。客户端可以在不与组成该结构的具体类耦合的情况下处理非常复杂的对象结构。
代码结构分析
定义复合图形类包含初始化方法和递归调用方法。定义简单图形类包含初始化方法和基本操作方法。定义客户端代码通过与所有形状共享的单一接口与所有形状进行交互。在客户端代码中根据需要创建复合图形对象和简单图形对象。使用复合图形对象和简单图形对象执行各种操作如添加、删除、修改等。验证客户端代码是否正确处理了复合图形对象和简单图形对象的操作。
// The component interface declares common operations for both
// simple and complex objects of a composition.
interface Graphic ismethod move(x, y)method draw()// The leaf class represents end objects of a composition. A
// leaf object cant have any sub-objects. Usually, its leaf
// objects that do the actual work, while composite objects only
// delegate to their sub-components.
class Dot implements Graphic isfield x, yconstructor Dot(x, y) { ... }method move(x, y) isthis.x x, this.y ymethod draw() is// Draw a dot at X and Y.// All component classes can extend other components.
class Circle extends Dot isfield radiusconstructor 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 isfield 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) isforeach (child in children) dochild.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// composites 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 isfield all: CompoundGraphicmethod load() isall 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) isgroup new CompoundGraphic()foreach (component in components) dogroup.add(component)all.remove(component)all.add(group)// All components will be drawn.all.draw()2.1.2 叶子组合伪代码
组合模式是使用抽象基类或接口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 {vectorComponent 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。
3. 组合模式的优点和缺点
Composite 模式的优点
它简化了与复合结构中对象交互的客户端代码。它使得向复合结构添加新功能变得容易。它使得表示分层数据结构变得容易。
Composite 模式的缺点
它可能会使复合对象的代码比简单对象的代码更复杂。如果复合结构包含大量的子对象它可能会降低复合结构的性能。
4. 代码实现
4.1 真实案例伪代码描述
Composite 模式的真实案例是树形数据结构例如目录树。在这种情况下抽象部分将表示一个目录具体部分将表示文件或其他目录。以下是使用组合模式的伪代码示例
# 抽象部分
class Directory:def add_file(self, file):passdef remove_file(self, file):passdef list_files(self):pass# 具体部分
class File:def __init__(self, name):self.name nameclass DirectoryNode:def __init__(self, directory):self.directory directoryself.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方法列出了目录中的所有文件。
4.2 概念示例代码
#include iostreamclass 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()函数。
通过组合模式可以将叶子节点和复合节点统一对待无论它们是单独使用还是作为其他节点的一部分。这种灵活性使得代码更加可扩展和易于维护。
4.2.1 2.1.1 概念代码实际代码
#include iostream
#include vectorclass 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::vectorGraphic* 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::vectorGraphic* 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中的原始指针时正确管理内存。如果适用可以考虑使用智能指针。
我们可以在任何支持C11或更高版本的C环境中编译和运行此代码。如果需要想查看这些方法的输出需要创建Leaf和Composite的实例调用它们的方法并将输出打印到控制台。
4.3 真实案例代码
4.3.1 geom_exmaple.h
#ifndef _GEOM_EXAMPLE_H_
#define _GEOM_EXAMPLE_H_#include vector// 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 cant have any sub-objects. Usually, its 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::vectorGraphic* 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::vectorGraphic* components);
};class GeomCompositeTest
{
public:static void GeomCompositeExample();
};#endif // _GEOM_EXAMPLE_H_4.3.2 geom_example.cpp
#include geom_example.h#include iostreamDot::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::vectorGraphic* 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::vectorGraphic* 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);
}4.4 代码分析
4.4.1 概念代码分析
4.4.1.1 4.2.1 代码分析
提供的C代码是组合模式的实现组合模式是一种设计模式用于将一组对象以与单个对象的相同方式处理。组合模式的概念允许您将对象组合成树形结构以表示部分-整体层次结构。
在此代码中我们有以下类 Component这是一个抽象基类声明了简单和复杂对象的组合的共同操作。它声明了一个纯虚函数operation()。 Leaf这个类代表组合的结束对象叶子对象。它从Component类继承并实现了operation()方法。在这个方法中它只是打印出I am a leaf.。 Composite这个类代表可能有子对象的复杂组件。它也从Component类继承并实现了operation()方法。在这个方法中它首先打印出I am a composite.然后遍历其子组件并调用它们的operation()方法。
这种结构允许您统一对待单个对象Leaf和对象的组合Composite。您可以对所有复合对象执行的操作通常具有最低公共分母关系。
请注意这段代码是不完整的。Composite类应该包含一个容器如向量或列表来保存其子组件并提供添加或删除子组件的方法。此外代码目前缺少与之交互的客户端。
4.4.1.2 4.2.2 代码分析
提供的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创建的对象以防止内存泄漏。如果适用请考虑使用智能指针。
4.4.2 真实案例代码分析
提供的代码是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.