设计模式总结(三)

上一篇总结了设计模式的创建型模式, 接下来总结一下设计模式的几种结构型模式。

1. 适配器模式

适配器模式允许将一个类的接口转换成客户端所期望的另一个接口。适配器模式通常用于以下情况:

  1. 当你需要使用一个已经存在的类,但是它的接口与你所需要的接口不匹配时。
  2. 当你想要创建一个可复用的类,该类与一些不相关或不可预见的类协同工作时。

适配器模式通过引入一个中间层来解决这些问题,这个中间层就是适配器。适配器将客户端的调用转换为对被适配对象的调用,从而实现了对接口的适配。

下面是一个简单的 C++ 示例,展示了如何使用适配器模式。

假设我们有一个现有的类 Adaptee,它提供了一个名为 specificRequest() 的方法,但是我们需要与一个接口为 Target 的客户端进行交互。

#include <iostream>// Adaptee类,具有特定接口
class Adaptee {
public:void specificRequest() {std::cout << "Adaptee's specific request" << std::endl;}
};// Target接口
class Target {
public:virtual void request() = 0;
};// Adapter类,将Adaptee转换为Target
class Adapter : public Target {
private:Adaptee *adaptee;public:Adapter(Adaptee *a) : adaptee(a) {}void request() override {adaptee->specificRequest();}
};// Client使用Target接口
void client(Target *target) {target->request();
}int main() {Adaptee *adaptee = new Adaptee();Target *adapter = new Adapter(adaptee);client(adapter);delete adaptee;delete adapter;return 0;
}

在这个例子中,Adaptee 类是我们需要适配的类,它提供了 specificRequest() 方法。Target 是我们需要与之交互的接口。Adapter 类实现了 Target 接口,并持有一个 Adaptee 对象,在 request() 方法中调用了 AdapteespecificRequest() 方法。最后,在 main() 函数中,我们将 Adaptee 对象传递给 Adapter 对象,然后将 Adapter 对象传递给客户端函数 client(),实现了对接口的适配。

2. 桥接模式

桥接模式将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过将继承关系转化为关联关系来实现,从而使得抽象部分和实现部分可以独立地变化而不相互影响。

桥接模式主要包含以下角色:

  1. Abstraction(抽象类):定义了抽象部分的接口,同时维护一个指向实现部分的引用。
  2. Implementor(实现类接口):定义了实现部分的接口,该接口不一定要与 Abstraction 的接口完全一致。实现类接口并不提供实现,而是声明了一些基本的操作,由具体的实现类来实现。
  3. ConcreteImplementor(具体实现类):实现了 Implementor 接口,并具体实现其定义的操作。
  4. RefinedAbstraction(扩充抽象类):扩充了 Abstraction 中定义的接口,通常通过继承 Abstraction 来完成。

以下是一个简单的 C++ 示例,演示了桥接模式的使用:

#include <iostream>// Implementor(实现类接口)
class Implementor {
public:virtual void operationImpl() = 0;
};// ConcreteImplementorA(具体实现类A)
class ConcreteImplementorA : public Implementor {
public:void operationImpl() override {std::cout << "Concrete Implementor A operation" << std::endl;}
};// ConcreteImplementorB(具体实现类B)
class ConcreteImplementorB : public Implementor {
public:void operationImpl() override {std::cout << "Concrete Implementor B operation" << std::endl;}
};// Abstraction(抽象类)
class Abstraction {
protected:Implementor *implementor;public:Abstraction(Implementor *impl) : implementor(impl) {}virtual void operation() = 0;
};// RefinedAbstraction(扩充抽象类)
class RefinedAbstraction : public Abstraction {
public:RefinedAbstraction(Implementor *impl) : Abstraction(impl) {}void operation() override {std::cout << "Refined Abstraction operation - ";implementor->operationImpl();}
};int main() {Implementor *implA = new ConcreteImplementorA();Implementor *implB = new ConcreteImplementorB();Abstraction *abstraction1 = new RefinedAbstraction(implA);Abstraction *abstraction2 = new RefinedAbstraction(implB);abstraction1->operation();abstraction2->operation();delete implA;delete implB;delete abstraction1;delete abstraction2;return 0;
}

在这个示例中,Implementor 是实现类接口,定义了实现部分的接口。ConcreteImplementorAConcreteImplementorB 是具体的实现类,分别实现了 Implementor 接口。Abstraction 是抽象类,它维护了一个指向 Implementor 的引用,并定义了抽象部分的接口。RefinedAbstraction 是扩充抽象类,它继承了 Abstraction 并扩展了其接口。在 main() 函数中,我们创建了两个具体实现类对象和两个扩充抽象类对象,并调用它们的操作方法,实现了桥接模式的使用。

3. 装饰模式

装饰模式允许我们在不改变对象接口的情况下,动态地给对象添加新的功能。装饰模式通过创建一个包装对象来包裹真实对象,然后在保持真实对象接口不变的前提下,向其添加额外的功能。

装饰模式主要包含以下角色:

  1. Component(组件):定义了一个对象接口,可以为这些对象动态地添加新的功能。
  2. ConcreteComponent(具体组件):实现了 Component 接口,并定义了具体的对象。
  3. Decorator(装饰者):持有一个指向 Component 对象的引用,并且与 Component 接口一致,这样可以装饰其他组件。通常是抽象类,它可以为具体组件添加额外的功能。
  4. ConcreteDecorator(具体装饰者):扩展了 Decorator 类,实现了装饰功能。

下面是一个简单的 C++ 示例,演示了装饰模式的使用:

#include <iostream>// Component(组件)接口
class Component {
public:virtual void operation() = 0;
};// ConcreteComponent(具体组件)
class ConcreteComponent : public Component {
public:void operation() override {std::cout << "ConcreteComponent operation" << std::endl;}
};// Decorator(装饰者)抽象类
class Decorator : public Component {
protected:Component *component;public:Decorator(Component *comp) : component(comp) {}void operation() override {if (component != nullptr) {component->operation();}}
};// ConcreteDecoratorA(具体装饰者A)
class ConcreteDecoratorA : public Decorator {
public:ConcreteDecoratorA(Component *comp) : Decorator(comp) {}void operation() override {Decorator::operation();addFunctionality();}void addFunctionality() {std::cout << "Added functionality by ConcreteDecoratorA" << std::endl;}
};// ConcreteDecoratorB(具体装饰者B)
class ConcreteDecoratorB : public Decorator {
public:ConcreteDecoratorB(Component *comp) : Decorator(comp) {}void operation() override {Decorator::operation();addMoreFunctionality();}void addMoreFunctionality() {std::cout << "Added more functionality by ConcreteDecoratorB" << std::endl;}
};int main() {Component *component = new ConcreteComponent();Decorator *decoratorA = new ConcreteDecoratorA(component);Decorator *decoratorB = new ConcreteDecoratorB(decoratorA);decoratorB->operation();delete decoratorB;delete decoratorA;delete component;return 0;
}

在这个示例中,Component 是组件接口,定义了操作方法。ConcreteComponent 是具体组件类,实现了 Component 接口的方法。Decorator 是装饰者抽象类,持有一个指向 Component 对象的引用,并且与 Component 接口一致,以便可以装饰其他组件。ConcreteDecoratorAConcreteDecoratorB 是具体装饰者类,它们扩展了 Decorator 类,并实现了装饰功能。

main() 函数中,我们创建了一个具体组件对象,并使用具体装饰者类对其进行装饰,实现了装饰模式的使用。

4. 组合模式

组合模式允许我们将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户可以使用统一的方式处理单个对象和对象组合。

组合模式主要包含以下角色:

  1. Component(组件):定义了组合中的对象的共有接口,可以是抽象类或接口,它提供了一个统一的方法来访问组合中的所有对象。
  2. Leaf(叶子):表示组合中的叶子节点对象,叶子节点没有子节点,它实现了 Component 接口中的方法。
  3. Composite(复合):表示组合中的容器对象,可以包含其他子节点,它实现了 Component 接口中的方法,并且可以添加、删除、获取子节点等操作。

下面是一个简单的 C++ 示例,演示了组合模式的使用:

#include <iostream>
#include <vector>// Component(组件)接口
class Component {
public:virtual void operation() = 0;
};// Leaf(叶子)类
class Leaf : public Component {
public:void operation() override {std::cout << "Leaf operation" << std::endl;}
};// Composite(复合)类
class Composite : public Component {
private:std::vector<Component*> children;public:void add(Component *component) {children.push_back(component);}void remove(Component *component) {// 在实际应用中,通常需要在这里实现查找并删除子节点的逻辑// 这里简化为直接删除对应指针children.erase(std::remove(children.begin(), children.end(), component), children.end());}Component* getChild(int index) {if (index >= 0 && index < children.size()) {return children[index];}return nullptr;}void operation() override {std::cout << "Composite operation" << std::endl;for (Component *child : children) {child->operation();}}
};int main() {Component *leaf1 = new Leaf();Component *leaf2 = new Leaf();Component *leaf3 = new Leaf();Composite *composite1 = new Composite();composite1->add(leaf1);composite1->add(leaf2);Composite *composite2 = new Composite();composite2->add(leaf3);Composite *composite = new Composite();composite->add(composite1);composite->add(composite2);composite->operation();delete composite;delete composite2;delete composite1;delete leaf3;delete leaf2;delete leaf1;return 0;
}

在这个示例中,Component 是组件接口,定义了操作方法。Leaf 类是叶子类,它实现了 Component 接口的方法。Composite 类是复合类,它实现了 Component 接口,并且可以包含其他子节点。在 main() 函数中,我们创建了多个叶子对象和复合对象,将它们组合成了树形结构,并调用了根节点的 operation() 方法,实现了组合模式的使用。

5. 外观模式

外观模式提供了一个统一的接口,用于访问子系统中的一群接口。外观模式定义了一个高层接口,这个接口使得子系统更容易使用。

外观模式的核心思想是将复杂系统的内部逻辑隐藏在一个简单的接口背后,让客户端只需要通过这个简单的接口与系统交互,而不需要了解系统内部的复杂逻辑。

外观模式主要包含以下角色:

  1. Facade(外观):提供了一个简单的接口,用于与客户端交互。外观对象将客户端的请求委派给相应的子系统对象来完成具体的工作。
  2. Subsystem(子系统):实现了系统的功能,是外观对象的组成部分。客户端可以直接访问子系统,但通常通过外观对象来间接访问。

下面是一个简单的 C++ 示例,演示了外观模式的使用:

#include <iostream>// 子系统A
class SubsystemA {
public:void operationA() {std::cout << "SubsystemA operation" << std::endl;}
};// 子系统B
class SubsystemB {
public:void operationB() {std::cout << "SubsystemB operation" << std::endl;}
};// 外观类
class Facade {
private:SubsystemA subsystemA;SubsystemB subsystemB;public:void operation() {subsystemA.operationA();subsystemB.operationB();}
};int main() {Facade facade;facade.operation();return 0;
}

在这个示例中,SubsystemASubsystemB 分别是两个子系统,它们分别实现了系统的一部分功能。Facade 是外观类,它提供了一个简单的接口 operation(),内部调用了 SubsystemASubsystemB 的方法来完成工作。

main() 函数中,我们创建了一个外观对象 facade,并调用了其 operation() 方法,实现了对子系统的访问。通过外观模式,客户端可以直接调用外观对象的方法,而不需要了解系统内部的复杂逻辑,从而简化了客户端的使用方式。

6. 享元模式

享元模式旨在通过共享尽可能多的对象来有效支持大量细粒度的对象。

享元模式的核心思想是尽量减少系统中相似对象的数量,通过共享相似对象的状态来减少内存消耗。在享元模式中,通常将对象的状态分成内部状态(Intrinsic State)和外部状态(Extrinsic State),内部状态是可以共享的,而外部状态则是每个对象单独拥有的。通过这种方式,可以将大量相似对象中的内部状态共享,从而节省内存空间。

享元模式主要包含以下角色:

  1. Flyweight(享元):定义了一个接口,用于设置和获取外部状态。
  2. ConcreteFlyweight(具体享元):实现了 Flyweight 接口,并包含内部状态。
  3. FlyweightFactory(享元工厂):负责创建和管理享元对象,确保可以正确地共享享元对象。

下面是一个简单的 C++ 示例,演示了享元模式的使用:

#include <iostream>
#include <map>// Flyweight(享元)接口
class Flyweight {
public:virtual void operation(int extrinsicState) = 0;
};// ConcreteFlyweight(具体享元)类
class ConcreteFlyweight : public Flyweight {
private:int intrinsicState; // 内部状态,可以共享public:ConcreteFlyweight(int state) : intrinsicState(state) {}void operation(int extrinsicState) override {std::cout << "ConcreteFlyweight with intrinsic state " << intrinsicState<< " and extrinsic state " << extrinsicState << std::endl;}
};// FlyweightFactory(享元工厂)类
class FlyweightFactory {
private:std::map<int, Flyweight*> flyweights;public:Flyweight* getFlyweight(int key) {if (flyweights.find(key) == flyweights.end()) {flyweights[key] = new ConcreteFlyweight(key);}return flyweights[key];}~FlyweightFactory() {for (auto& pair : flyweights) {delete pair.second;}flyweights.clear();}
};int main() {FlyweightFactory factory;Flyweight* flyweight1 = factory.getFlyweight(1);flyweight1->operation(100);Flyweight* flyweight2 = factory.getFlyweight(2);flyweight2->operation(200);Flyweight* flyweight3 = factory.getFlyweight(1);flyweight3->operation(300);return 0;
}

在这个示例中,Flyweight 是享元接口,定义了操作方法。ConcreteFlyweight 是具体享元类,实现了 Flyweight 接口,并包含内部状态。FlyweightFactory 是享元工厂类,负责创建和管理享元对象。

main() 函数中,我们创建了一个享元工厂对象 factory,然后通过工厂获取了几个具体享元对象,并分别调用它们的 operation() 方法。可以看到,当获取相同内部状态的享元对象时,工厂会返回同一个对象,从而实现了对相似对象内部状态的共享。

7. 代理模式

代理模式允许通过一个代理对象来控制对另一个对象的访问。代理模式常用于需要在访问对象时增加额外操作的情况,例如延迟加载、权限控制、日志记录等。

代理模式主要包含以下角色:

  1. Subject(主题):定义了真实对象和代理对象共同的接口,客户端通过这个接口访问真实对象。
  2. RealSubject(真实主题):定义了真实对象的具体实现。
  3. Proxy(代理):代理对象,包含了对真实对象的引用,并且与真实对象实现了相同的接口。在客户端请求时,代理对象会执行额外的操作,然后将请求委派给真实对象。

代理模式通常可以分为静态代理和动态代理两种方式。静态代理是在编译时就确定代理对象和真实对象的关系,而动态代理是在运行时动态生成代理对象。

下面是一个简单的 C++ 示例,演示了静态代理模式的使用:

#include <iostream>// Subject(主题)接口
class Subject {
public:virtual void request() = 0;
};// RealSubject(真实主题)类
class RealSubject : public Subject {
public:void request() override {std::cout << "RealSubject handles request." << std::endl;}
};// Proxy(代理)类
class Proxy : public Subject {
private:RealSubject realSubject;public:void request() override {// 在真实主题处理请求前可以执行额外的操作std::cout << "Proxy handles request." << std::endl;// 委派给真实主题处理请求realSubject.request();}
};int main() {Proxy proxy;proxy.request();return 0;
}

在这个示例中,Subject 是主题接口,定义了操作方法。RealSubject 是真实主题类,实现了 Subject 接口的方法。Proxy 是代理类,包含了对真实主题对象的引用,并且实现了与真实主题相同的接口。在 request() 方法中,代理对象执行了额外的操作,然后将请求委派给真实主题处理。

main() 函数中,我们创建了一个代理对象 proxy,并调用了其 request() 方法,代理对象处理了客户端的请求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/719461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不愧是华为出来的,太厉害了...

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 实习去了博彦科技&#xff08;外包&#xff09;&#xff0c;做的…

设计模式笔记——建造者模式

设计模式&#xff08;创建型&#xff09;—— 建造者模式 这是一个学生类&#xff0c;它有四个属性&#xff0c;通过构造方法创建它的对象&#xff0c;我们需要填入四个参数&#xff0c;这就导致创建对象的代码有点长&#xff08;如果他有更多属性时&#xff0c;那会更加恐怖&…

赋能中国制造,大道云行发布智能制造分布式存储解决方案

《中国制造2025》指出&#xff0c;“制造业是国民经济的主体&#xff0c;是立国之本、兴国之器、强国之基。” 智能制造引领产业提质增效 智能制造是一种利用先进的信息技术、自动化技术和智能技术来优化和升级制造业生产过程的方法。它将人工智能、大数据、物联网、机器学习等…

算法竞赛STL:map的使用方法

算法竞赛STL&#xff1a;map的使用方法 map 容器描述&#xff1a; map是一种关联容器&#xff0c;它存储的元素是键值对&#xff0c;键和值可以是任意类型。map内部的元素按照键的顺序进行排序&#xff0c;排序的规则由比较函数决定。 使用方法&#xff1a; 首先&#xff0c…

【扩散模型系列2】DiT 《Scalable Diffusion Models with Transformers》论文阅读

文章目录 摘要1. 前言2. 相关工作TransformersDDPMs架构复杂度 3. 扩散Transformer3.1 准备知识扩散公式Classifier-free GuidanceLDMs 3.2. Diffusion Transformer Design SpacePatch化DiT模块设计模型大小Transformer Decoder 4. 实验设置训练扩散评估指标计算 5. 实验DiT bl…

【前端】登陆页面:记住密码、设置cookie、加密

将保存在cookie中的密码自动填入表单&#xff1a;库js-cookie // login.vue getCookie() {const username Cookies.get("username");const password Cookies.get("password");const rememberMe Cookies.get(rememberMe)this.loginForm {username: use…

Material UI 5 学习01-按钮组件

Material UI 5 学习01-按钮组件 一、安装Material UI二、 组件1、Button组件1、基础按钮2、variant属性3、禁用按钮4、可跳转的按钮5、disableElevation属性6、按钮的点击事件onClick 2、Button按钮的颜色和尺寸1、Button按钮的颜色2、按钮自定义颜色3、Button按钮的尺寸 3、图…

MacOS包管理工具homebrew使用教程

MacOS包管理工具homebrew使用教程 1.概述与安装2.基本使用3.其他常用命令 1.概述与安装 homebrew是Mac OS X上的强大的包管理工具&#xff0c;可以高效管理各种软件包 安装&#xff1a; 1、安装xcode&#xff1a; xcode-select --install2、一行命令下载&#xff1a; /bin…

DreamTalk:单张图像即可生成逼真人物说话头像动画,助力AI数字人落地

“DreamTalk: When Expressive Talking Head Generation Meets Diffusion Probabilistic Models” DreamTalk是一个基于扩散的音频驱动的富有表现力的说话头生成框架&#xff0c;可以生成不同说话风格的高质量的说话头视频。DreamTalk对各种输入表现出强大的性能&#xff0c;包…

Thingsboard本地源码部署教程

本章将介绍ThingsBoard的本地环境搭建&#xff0c;以及源码的编译安装。本机环境&#xff1a;jdk11、maven 3.6.2、node v12.18.2、idea 2023.1、redis 6.2 环境安装 开发环境要求&#xff1a; Jdk 11 版本 &#xff1b;Postgresql 9 以上&#xff1b;Maven 3.6 以上&#xf…

vue实现循环滚动列表

本文章使用 vue-seamless-scroll 为大家分享了vue实现循环滚动列表的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下&#xff1a; vue实现循环滚动列表 1.安装插件 vue-seamless-scroll vue-seamless-scroll 实例文档 npm install vue-seamless-scroll --save 2.HTM…

代码随想录算法训练营Day50 | 123.买卖股票的最佳时机 III、188.买卖股票的最佳时机 IV

123.买卖股票的最佳时机 III 思路与 121.买卖股票I 一脉相承&#xff0c;一次买卖有2种状态&#xff08;持有/不持有&#xff09;&#xff0c;那么两次买卖就有4种状态&#xff08;第一次持有/不持有、第二次持有/不持有&#xff09; 1、DP数组定义&#xff1a; dp[i][j]为当前…

【Java】Base理论的核心思想和理论三要素

目录 简介 BASE 理论的核心思想 BASE 理论三要素 1. 基本可用 2. 软状态 3. 最终一致性 总结 简介 BASE 是 Basically Available&#xff08;基本可用&#xff09; 、Soft-state&#xff08;软状态&#xff09; 和 Eventually Consistent&#xff08;最终一致性&#xf…

深度强化学习系列【2】- 贝尔曼方程和马尔可夫决策过程

引言: 一直想做点强化学习相关的内容,但是对于其原理一直不是太明了,相比于编程实现,懂得算法部分的机理与理论也是至关重要的。网上找的一些资料都在强调贝尔曼方程和马尔可夫决策过程在强化学习中的作用,但是介绍都不够充分。 另外,在知乎【1】上看到一个说法,说 强化学…

财报解读:基本盘稳定后,联想如何进一步抢占AI时代?

从2021年下半年开始&#xff0c;受诸多因素影响&#xff0c;消费电子行业始终处在承压状态&#xff0c;“不景气”这一关键词屡次被市场提及。 但寒气没有持续&#xff0c;可以看到&#xff0c;消费电子行业正在逐渐回暖。国金证券在今年1月的研报中就指出&#xff0c;从多方面…

【简单模拟】第十一届蓝桥杯省赛第二场C++ B组 / C组《成绩统计》(c++)

1.题目说明 小蓝给学生们组织了一场考试&#xff0c;卷面总分为100 分&#xff0c;每个学生的得分都是一个 0 到 100 的整数。 如果得分至少是 60 分&#xff0c;则称为及格。 如果得分至少为 85 分&#xff0c;则称为优秀。 请计算及格率和优秀率&#xff0c;用百分数表示…

#WEB前端(CCS常用属性,补充span、div)

1.实验&#xff1a; 复合元素、行内元素、块内元素、行内块元素 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; span为行内元素&#xff1a;不可设置宽高&#xff0c;实际占用控件决定分布空间。 div为块内元素&#xff1a;占满整行&#xff0c;可以设置宽高 img为行内块元…

Unity(第二十三部)导航

你可以使用 unity官方提供的 unity导航组件或第三方 unity导航组件&#xff0c;以实现游戏中角色或其他物体的导航。 unity导航组件通常具有多种导航模式&#xff0c;如飞行模式、步行模式、车辆模式等&#xff0c;可以根据不同的需求选择合适的模式。同时&#xff0c;unity导…

2023年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中,敬请期待…

2023年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中&#xff0c;敬请期待… 武汉唯众智创科技有限公司 2024 年 2 月 联系人&#xff1a;辜渝傧13037102709 题号&#xff1a;试题01 模块二&#xff1a;数据获取与处理 &#xff08;一&#xff09;…

Ainx的全局配置

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于Ainx系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列…