《设计模式的艺术》笔记 - 组合模式

这篇具有很好参考价值的文章主要介绍了《设计模式的艺术》笔记 - 组合模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

介绍

        组合模式组合多个对象形成树形结构以表示具有“部分-整体”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,又可以称为“部分—整体”(Part-Whole)模式,它是一种对象结构型模式。

实现

myclass.h

//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <vector>

class Component {    // 抽象基类
public:
    virtual void operation();
    virtual void add(Component *component);
    virtual void remove(Component *component);
    virtual Component *getChild(int i);

protected:
    std::string m_name;
};

class LeafComponent : public Component {    // 叶子节点具体类
public:
    LeafComponent(const std::string &name);
    void operation() override;
};

class CompositeComponent : public Component {    // 容器节点具体类
public:
    CompositeComponent(const std::string &name);

    void operation() override;

    void add(Component *component) override;

    void remove(Component *component) override;

    Component *getChild(int i) override;

private:
    std::vector<Component *> m_components;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

void Component::operation() {
    throw std::runtime_error("operation exception");
}

void Component::add(Component *component) {
    throw std::runtime_error("add exception");
}

void Component::remove(Component *component) {
    throw std::runtime_error("remove exception");
}

Component *Component::getChild(int i) {
    throw std::runtime_error("getChild exception");
}

LeafComponent::LeafComponent(const std::string &name) {
    m_name = name;
}

void LeafComponent::operation() {
    std::cout << m_name << ": LeafComponent::operation()" << std::endl;
}

CompositeComponent::CompositeComponent(const std::string &name) {
    m_name = name;
}

void CompositeComponent::operation() {
    std::cout << m_name << ": CompositeComponent::operation()" << std::endl;
    for (auto it = m_components.begin(); it != m_components.end(); ++it) {
        (*it)->operation();
    }
}

void CompositeComponent::add(Component *component) {
    m_components.push_back(component);
}

void CompositeComponent::remove(Component *component) {
    for (auto it = m_components.begin(); it != m_components.end(); ++it) {
        if (*it == component) {
            m_components.erase(it);
            break;
        }
    }
}

Component *CompositeComponent::getChild(int i) {
    if (i < m_components.size()) {
        return m_components[i];
    } else {
        return nullptr;
    }
}

main.cpp

#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Component *leaf = new LeafComponent("leaf1");
    Component *composite = new CompositeComponent("composite1");
    Component *composite2 = new CompositeComponent("composite2");

    composite->add(new LeafComponent("leaf2"));
    composite->add(new LeafComponent("leaf3"));
    composite2->add(new LeafComponent("leaf4"));
    composite->add(composite2);
    leaf->operation();
    composite->operation();
    try {
        leaf->getChild(0);
    } catch (std::exception &e) {
        std::cout << e.what() << std::endl;
    }

    return 0;
}

组合模式形式

透明组合模式

        抽象构建Component中声明了所有用于管理成员对象的方法,这样能确保所有的构建类都有相同的接口。缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的。

组合安全模式

        安全组合模式中,在抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法。缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

总结

优点

        1. 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次。它让客户端忽略了层次的差异,方便对整个层次结构进行控制。

        2. 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。

        3. 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合开闭原则。

        4. 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案。通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

缺点

        1. 在增加新构件时很难对容器中的构件类型进行限制。

适用场景

        1. 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致性地对待它们。

        2. 在一个使用面向对象语言开发的系统中需要处理一个树形结构。

        3. 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,将来需要增加一些新的类型。

练习

myclass.h

//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <vector>

class Component {
public:
    virtual void display();
    virtual void add(Component *component);
    virtual void remove(Component *component);
    virtual Component *getChild(int i);

protected:
    std::string m_name;
};

class Button : public Component {
public:
    Button(const std::string &name);

    void display() override;
};

class Text : public Component {
public:
    Text(const std::string &name);

    void display() override;
};

class Window : public Component {
public:
    Window(const std::string &name);

    void display() override;

    void add(Component *component) override;

    void remove(Component *component) override;

    Component *getChild(int i) override;

private:
    std::vector<Component *> m_childs;
};

class Panel : public Component {
public:
    Panel(const std::string &name);

    void display() override;

    void add(Component *component) override;

    void remove(Component *component) override;

    Component *getChild(int i) override;

private:
    std::vector<Component *> m_childs;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp文章来源地址https://www.toymoban.com/news/detail-806134.html

//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

void Component::display() {
    throw std::runtime_error("operation exception");
}

void Component::add(Component *component) {
    throw std::runtime_error("add exception");
}

void Component::remove(Component *component) {
    throw std::runtime_error("remove exception");
}

Component *Component::getChild(int i) {
    throw std::runtime_error("getChild exception");
}


Button::Button(const std::string &name) {
    m_name = name;
}

void Button::display() {
    std::cout << "Button: " << m_name << std::endl;
}

Text::Text(const std::string &name) {
    m_name = name;
}

void Text::display() {
    std::cout << "Text: " << m_name << std::endl;
}

Window::Window(const std::string &name) {
    m_name = name;
}

void Window::display() {
    std::cout << "Window: " << m_name << "包含: " << std::endl;
    for (auto it = m_childs.begin(); it != m_childs.end(); ++it) {
        (*it)->display();
    }
}

void Window::add(Component *component) {
    m_childs.push_back(component);
}

void Window::remove(Component *component) {
    for (auto it = m_childs.begin(); it != m_childs.end(); ++it) {
        if (*it == component) {
            m_childs.erase(it);
            break;
        }
    }
}

Component *Window::getChild(int i) {
    if (i < m_childs.size()) {
        return m_childs[i];
    } else {
        return nullptr;
    }
}

Panel::Panel(const std::string &name) {
    m_name = name;
}

void Panel::display() {
    std::cout << "Panel: " << m_name << "包含: " << std::endl;
    for (auto it = m_childs.begin(); it != m_childs.end(); ++it) {
        (*it)->display();
    }
}

void Panel::add(Component *component) {
    m_childs.push_back(component);
}

void Panel::remove(Component *component) {
    for (auto it = m_childs.begin(); it != m_childs.end(); ++it) {
        if (*it == component) {
            m_childs.erase(it);
            break;
        }
    }
}

Component *Panel::getChild(int i) {
    if (i < m_childs.size()) {
        return m_childs[i];
    } else {
        return nullptr;
    }
}

到了这里,关于《设计模式的艺术》笔记 - 组合模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《设计模式的艺术》笔记 - 状态模式

            状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象,状态模式是一种对象行为模式。 myclass.h myclass.cpp main.cpp         1. 封装了状态的转换规则。在状态模式中可以将状态的转换代码封装在环境类或者具体状

    2024年01月25日
    浏览(46)
  • 《设计模式的艺术》笔记 - 代理模式

            代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式是一种对象结构型模式。 myclass.h myclass.cpp main.cpp         1. 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度,满足迪米特法则。         2. 客户端可以

    2024年01月19日
    浏览(46)
  • 《设计模式的艺术》笔记 - 桥接模式

            桥接模式将抽象部分与其实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式 myclass.h myclass.cpp main.cpp         1. 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,

    2024年01月18日
    浏览(45)
  • 《设计模式的艺术》笔记 - 命令模式

            命令模式将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为模式,其别名为动作模式或事务模式。 myclass.h myclass.cpp main.cpp         只需要增加一个CommandQueue类即可

    2024年01月20日
    浏览(43)
  • 《设计模式的艺术》笔记 - 享元模式

            享元模式运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,是一种对象结构型模式。 myclass.

    2024年01月19日
    浏览(32)
  • 《设计模式的艺术》笔记 - 迭代器模式

            迭代器模式提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。 myclass.h myclass.cpp main.cpp         1. 支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代

    2024年01月24日
    浏览(38)
  • 《设计模式的艺术》笔记 - 单例模式

            单例模式优点是可以确保系统中只存在单个对象实例,缺点是不便扩展,一定程度上违背单一原则,既提供业务方法,又提供创建对象方法         在类加载的时候就创建好对象,获取对象时直接返回即可         在类加载的时候没有创建对象,第一次获取对象

    2024年02月02日
    浏览(32)
  • 《设计模式的艺术》笔记 - 工厂方法模式

            在简单工厂模式中,当系统中需要引入新的产品时,由于静态工厂方法通过所传入的参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背开闭原则。因此,工厂方法模式应运而生。工厂方法模式是定义一个用于创建对象的接口,让子类决定将哪一个

    2024年01月23日
    浏览(37)
  • 《设计模式的艺术》笔记 - 抽象工厂模式

            提供了一个创建一系列相关或相互依赖的对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。         在抽象工厂模式中,每个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族。

    2024年01月16日
    浏览(29)
  • 《设计模式的艺术》笔记 - 建造者模式

            建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造这模式是一种对象创建型模式。 myclass.h myclass.cpp main.cpp         优点:         1. 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建

    2024年01月16日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包