结构型设计模式之装饰器模式【设计模式系列】

2023-11-03

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
设计模式系列

期待你的关注哦!!!
在这里插入图片描述

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

一、装饰器模式介绍

⚠️ 意图:
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

⚠️ 主要解决:
一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

⚠️ 何时使用:
在不想增加很多子类的情况下扩展类。

⚠️ 如何解决:
将具体功能职责划分,同时继承装饰者模式。

在这里插入图片描述

图1_1 装饰器模式类图

装饰模式的特点:

  • 装饰对象和真实对象有相同的接口。客户端对象可以使用和真实对象相同的方式和装饰对象交互。

  • 装饰对象包含一个真实对象的索引(reference)

  • 装饰对象接受所有的来自客户端的请求,并把请求转发给真实的对象。

  • 装饰对象可以在转发来自客户端的请求以前或以后增加一些附加功能。可以确保在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常通过继承来实现对给定类的功能扩展。通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但继承是静态的,用户不能控制增加行为的方式和时机。如果希望改变一个已经初始化的对象的行为,则只能在于运行时完成;如果希望继承许多类的行为,则可能会导致产生大量的不同的类。

    装饰模式提供了改变子类的灵活方案。装饰模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能,实际上时通过创建一个包装对象(装饰),来包裹真实的对象。

    当用于一组子类时,装饰模式更加有用。如果拥有一族子类(从一个父类派生而来),需要在与子类独立使用情况下添加额外的特性,可以使用装饰模式,以避免代码重复和具体子类数量的增加。

二、装饰器模式优缺点

2.1 优点

  • 比静态继承更灵活。与对象的静态继承(多重继承)相比,装饰模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。继承机制要求为每个添加的职责创建一个新的子类,会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的 Decorator类,这就使得可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性。

  • 避免在层次结构高层的类有太多的特征。装饰模式提供了一种“即用即付”的方法来添加职责,并不试图在一个复杂的可定制的类中支持所有可预见的特征。相反,可以定义一个简单的类,并且用Decorator类给简单类逐渐地添加功能,从简单的部件组合出复杂的功能。

  • 把类的装饰功能从类中搬移去除,可以简化原有的类。

  • 有效地把类的核心职责和装饰功能区分开来,而且可以去除相关类中重复的装饰逻辑。

    建造者模式要求建造的过程必须是稳定的,而装饰模式的建造过程是不稳定的,可以有各种各样的组合方式。

2.2 缺点

  • Decorator与Component不一样。Decorator是一个透明的包装。如果从对象标识的观点出发,一个被装饰的组件与组件本身是有差别的,因此,使用装饰不应该依赖对象标识。

  • 有许多小对象。采用Decorator模式进行系统设计往往会产生许多类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

三、装饰器模式使用场景

  • 在不影响其他对象的情况下,以动态,透明的方式给单个对象添加职责。

  • 处理那些可以撤销的职责

  • 当不能采用生成子类的方法扩充时。一种情况是可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

四、装饰器模式实现

Component抽象类:

#ifndef COMPONENT_H
#define COMPONENT_H
#include <iostream>
using namespace std;
 
//Component抽象类,定义类对象的接口
class Component
{
public:
    virtual ~Component(){}
    virtual void Operation() = 0;
protected:
    Component(){}
};
 
#endif // COMPONENT_H

ConcreteComponent具体对象类:

#ifndef CONCRETECOMPONENT_H
#define CONCRETECOMPONENT_H
#include "Component.h"
 
//ConcreteComponent:具体的Component对象,可以给对象动态添加职责
class ConcreteComponent : public Component
{
public:
    ConcreteComponent(){}
    ~ConcreteComponent(){}
    virtual void Operation()
    {
        cout << "Original:ConcreteComponent::Operation" << endl;
    }
};
 
#endif // CONCRETECOMPONENT_H

Decorator抽象装饰对象类:

#ifndef DECORATOR_H
#define DECORATOR_H
#include "Component.h"
 
//Decorator:装饰抽象类,继承自Component
class Decorator : public Component
{
public:
    Decorator(Component* com)
    {
        m_pCom = com;
    }
    void setComponent(Component* com)
    {
        m_pCom = com;
    }
    virtual ~Decorator(){}
    virtual void Operation() = 0;
protected:
    Component* m_pCom;
};
 
#endif // DECORATOR_H

ConcreteDecoratorA具体装饰对象类:

#ifndef CONCRETEDECORATORA_H
#define CONCRETEDECORATORA_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorA : public Decorator
{
public:
    ConcreteDecoratorA(Component* com):Decorator(com)
    {
    }
    ~ConcreteDecoratorA(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责A
        AddBehavorA();
    }
    void AddBehavorA()
    {
        cout << "Extra A:ConcreteDecoratorA::AddBehavorA" << endl;
    }
};
 
#endif // CONCRETEDECORATORA_H

ConcreteDecoratorB具体装饰对象类:

#ifndef CONCRETEDECORATORB_H
#define CONCRETEDECORATORB_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorB : public Decorator
{
public:
    ConcreteDecoratorB(Component* com):Decorator(com)
    {}
    ~ConcreteDecoratorB(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责B
        AddBehavorB();
    }
    void AddBehavorB()
    {
        cout << "Extra B:ConcreteDecoratorB::AddBehavorB" << endl;
    }
};
 
#endif // CONCRETEDECORATORB_H

ConcreteDecoratorC具体装饰对象类:

#ifndef CONCRETEDECORATORC_H
#define CONCRETEDECORATORC_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorC : public Decorator
{
public:
    ConcreteDecoratorC(Component* com):Decorator(com)
    {}
    ~ConcreteDecoratorC(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责C
        AddBehavorC();
    }
    void AddBehavorC()
    {
        cout << "Extra C:ConcreteDecoratorC::AddBehavorC" << endl;
    }
};
 
#endif // CONCRETEDECORATORC_H

ConcreteDecoratorD具体装饰对象类:

#ifndef CONCRETEDECORATORD_H
#define CONCRETEDECORATORD_H
#include "Decorator.h"
 
//ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能
class ConcreteDecoratorD : public Decorator
{
public:
    ConcreteDecoratorD(Component* com):Decorator(com)
    {}
    ~ConcreteDecoratorD(){}
    virtual void Operation()
    {
        m_pCom->Operation();
        //附加职责D
        AddBehavorD();
    }
    void AddBehavorD()
    {
        cout << "Extra D:ConcreteDecoratorD::AddBehavorD" << endl;
    }
};
 
#endif // CONCRETEDECORATORD_H

客户调用程序:

#include "ConcreteComponent.h"
#include "ConcreteDecoratorA.h"
#include "ConcreteDecoratorB.h"
#include "ConcreteDecoratorC.h"
#include "ConcreteDecoratorD.h"
 
int main()
{
    //要装饰的对象
    Component* pCom = new ConcreteComponent();
    Decorator* pDec = NULL;
     //给装饰对象附加职责A
    pDec = new ConcreteDecoratorA(pCom);
     //给装饰对象附加职责B
    pDec = new ConcreteDecoratorB(pDec);
     //给装饰对象附加职责C
    pDec = new ConcreteDecoratorC(pDec);
     //给装饰对象附加职责D
    pDec = new ConcreteDecoratorD(pDec);
    pDec->Operation();
 
    delete pCom,pDec;
    return 0;
}

五、装饰器模式应用案例

手机装饰实例:

Phone抽象类:

#ifndef PHONE_H
#define PHONE_H
#include <iostream>
#include <string>
using namespace std;
 
//抽象类
class Phone
{
public:
    Phone(){}
    virtual ~Phone(){}
    virtual void showDecorator() = 0;
};
 
#endif // PHONE_H

iPhone具体对象类:

#ifndef IPHONE_H
#define IPHONE_H
#include "Phone.h"
 
//具体手机类
class iPhone : public Phone
{
public:
    iPhone(string name):m_name(name){}
    ~iPhone(){}
    void showDecorator()
    {
        cout << m_name << " 's Decorator" << endl;
    }
private:
    string m_name;
};
 
#endif // IPHONE_H

MiPhone具体对象类:

#ifndef MIPHONE_H
#define MIPHONE_H
#include "Phone.h"
 
//具体手机类
class MiPhone : public Phone
{
public:
    MiPhone(string name):m_name(name){}
    ~MiPhone(){}
    void showDecorator()
    {
        cout << m_name << " 's Decorator" << endl;
    }
private:
    string m_name;
};
 
#endif // MIPHONE_H

DecoratorPhone装饰基类:

#ifndef DECORATORPHONE_H
#define DECORATORPHONE_H
#include "Phone.h"
 
//装饰基类
class DecoratorPhone : public Phone
{
public:
    DecoratorPhone(Phone* phone):m_phone(phone){}
    ~DecoratorPhone(){}
    virtual void showDecorator() = 0;
protected:
    Phone* m_phone;//要装饰的对象
};
 
#endif // DECORATORPHONE_H

DecoratorPhoneA具体装饰对象类:

#ifndef DECORATORPHONEA_H
#define DECORATORPHONEA_H
#include "DecoratorPhone.h"
 
//具体装饰类
class DecoratorPhoneA : public DecoratorPhone
{
public:
    DecoratorPhoneA(Phone* phone):DecoratorPhone(phone){}
    void showDecorator()
    {
        m_phone->showDecorator();
        addDecorator();//增加装饰
    }
private:
    void addDecorator()
    {
        cout << "add a DecoratorPhoneA Decorator" << endl;
    }
};
 
#endif // DECORATORPHONEA_H

DecoratorPhoneB具体装饰对象类:

#ifndef DECORATORPHONEB_H
#define DECORATORPHONEB_H
#include "DecoratorPhone.h"
 
//具体装饰类
class DecoratorPhoneB : public DecoratorPhone
{
public:
    DecoratorPhoneB(Phone* phone):DecoratorPhone(phone){}
    void showDecorator()
    {
        m_phone->showDecorator();
        addDecorator();//增加装饰
    }
private:
    void addDecorator()
    {
        cout << "add a DecoratorPhoneB Decorator" << endl;
    }
};
 
#endif // DECORATORPHONEB_H

客户调用程序:

#include "Phone.h"
#include "MiPhone.h"
#include "iPhone.h"
#include "DecoratorPhoneA.h"
#include "DecoratorPhoneB.h"
 
int main()
{
    Phone *iphone = new iPhone("iPhone X");
    Phone* decorator1 = NULL;
    decorator1 = new DecoratorPhoneA(iphone); //增加装饰
    decorator1 = new DecoratorPhoneB(decorator1);    //增加装饰
    decorator1->showDecorator();//显示装饰
 
    Phone *mi = new MiPhone("Mi 6");
    Phone* decorator2 = NULL;
    decorator2 = new DecoratorPhoneA(mi); //增加装饰
    decorator2 = new DecoratorPhoneB(decorator2);//增加装饰
    decorator2->showDecorator();//显示装饰
    delete decorator2,decorator2;
    delete iphone,mi;
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

结构型设计模式之装饰器模式【设计模式系列】 的相关文章

  • 语音识别编程问题入门

    所以 你们可能都看过 钢铁侠 其中托尼与一个名为贾维斯的人工智能系统进行交互 演示剪辑here http www youtube com watch v Go8zsh1Ev6Y 抱歉 这是广告 我非常熟悉 C C 和 Visual Basi
  • 如何在 C# Designer.cs 代码中使用常量字符串?

    如何在 designer cs 文件中引用常量字符串 一个直接的答案是在我的 cs 文件中创建一个私有字符串变量 然后编辑 Designer cs 文件以使用此变量 而不是对字符串进行硬编码 但设计者不喜欢这样抛出错误 我明白为什么这行不通
  • 即使没有异步,CallContext.LogicalGetData 也会恢复。为什么?

    我注意到CallContext LogicalSetData LogicalGetData不按照我期望的方式工作 内部设置的值async方法得到恢复即使没有异步或任何类型的线程切换 无论如何 这是一个简单的例子 using System u
  • 在 C# 中检查 PowerShell 执行策略的最佳方法是什么?

    当你跑步时Get ExecutionPolicy在 PowerShell 中 它得到有效的执行政策 https learn microsoft com en us powershell module microsoft powershell
  • 在 VS 中运行时如何查看 C# 控制台程序的输出?

    我刚刚编写了一个名为 helloworld 的聪明程序 它是一个 C NET 4 5 控制台应用程序 在扭曲的嵌套逻辑迷宫深处 使用了 Console WriteLine 当我在命令行运行它时 它会运行并且我会看到输出 我可以执行其他命令并
  • 如何使用 x64 运行 cl?

    我遇到了和这里同样的问题致命错误 C1034 windows h 未设置包含路径 https stackoverflow com questions 931652 fatal error c1034 windows h no include
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 开发者环境-如何调用/消费其他微服务

    背景 我的环境 Java Play2 MySql 我在 Play2 gt S1 S2 S3 上编写了 3 个无状态 Restful 微服务 S1 消耗来自 S2 和 S3 的数据 因此 当用户点击 S1 时 该服务会异步调用 S2 S3 合
  • Spring - 如何在不匹配列名的情况下使用 BeanPropertyRowMapper

    我正在开发一个应用程序 该应用程序已使用行映射器从纯 JDBC 转换为 Spring 模板 我遇到的问题是数据库中的列与属性名称不匹配 这阻止我使用BeanPropertyRowMapper容易地 我看到一些关于在查询中使用别名的帖子 这会
  • 从 C# 使用 Odbc 调用 Oracle 包函数

    我在 Oracle 包中定义了一个函数 CREATE OR REPLACE PACKAGE BODY TESTUSER TESTPKG as FUNCTION testfunc n IN NUMBER RETURN NUMBER as be
  • 模板外部链接?谁能解释一下吗?

    模板名称具有链接 3 5 非成员函数模板可以有内部链接 任何其他模板名称应具有外部链接 从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同 我知道使用关键字的外部链接 extern C EX extern C templat
  • 在 C 中使用枚举而不是 #defines 作为编译时常量是否合理?

    在 C 工作了一段时间后 我将回到 C 开发领域 我已经意识到 在不必要的时候应该避免使用宏 以便让编译器在编译时为您做更多的工作 因此 对于常量值 在 C 中我将使用静态 const 变量或 C 11 枚举类来实现良好的作用域 在 C 中
  • 将二变量 std::function 转换为单变量 std::function

    我有一个函数 它获取两个值 x 和 y 并返回结果 std function lt double double double gt mult double x double y return x y 现在我想得到一个常量 y 的单变量函数
  • C++ 对象用 new 创建,用 free() 销毁;这有多糟糕?

    我正在修改一个相对较大的 C 程序 不幸的是 并不总是清楚我之前的人使用的是 C 还是 C 语法 这是在一所大学的电气工程系 我们 EE 总是想用 C 来做所有事情 不幸的是 在这种情况下 人们实际上可以逃脱惩罚 但是 如果有人创建一个对象
  • Java时区混乱

    我正在运行 Tomcat 应用程序 并且需要显示一些时间值 不幸的是 时间快到了 还有一个小时的休息时间 我调查了一下 发现我的默认时区被设置为 sun util calendar ZoneInfo id GMT 08 00 offset
  • Unicode(希腊语)字符存储在数据库中,例如“??????”

    数据库中的希腊字符就像问号 我找不到解决办法 我使用 Java Swing 开发了一个应用程序 但是当我在 MySQL 中插入希腊字母时 就像问号一样 我将数据库排序规则更改为 utf8 并将列也更改为 utf8 我的项目编码设置为UTF
  • 是否允许全局静态标识符以单个 _ 开头?

    换句话说 可能static 文件范围 全局变量恰好以一个下划线开头 而不会产生与 C 实现发生名称冲突的可能性 https www gnu org software libc manual html node Reserved Names
  • MySqlConnectionStringBuilder - 使用证书连接

    我正在尝试连接到 Google Cloud Sql 这是一个 MySql 解决方案 我能够使用 MySql Workbench 进行连接 我如何使用 C 连接MySqlConnectionStringBuilder 我找不到提供这三个证书的
  • 当用户更改 Windows 中的语言键盘布局时如何通知?

    I want to show a message to user when the user changes the language keyboard layout of Windows for example from EN to FR
  • 如何在 C 中将 char 连接到 char* ?

    我怎样才能前置char c to char myChar 我有c值为 A and myChar值为 LL 我怎样才能前置c to myChar使 ALL 这应该有效 include

随机推荐

  • 不平衡数据分类方法

    仅个人学习时 阅读相关资料总结 可能有部分不准确 概述 定义 数据不平衡分类是对各类别间样本的数目相差较大的数据集进行分类 例如 二分类问题中 一个样本总数为100 80个样本被标为类别1 剩下的20个样本被标为类别2 类别1比类别2的样本
  • python高性能调用js

    转载于 微信公众号 爬虫黑科技 做js逆向 一般是将js的加解密的源码抽出来然后用python的pyexecjs包来调用 但这样的话会有一部分性能丢失 这里推荐一种http调用方式 1 将js的加解密入口封装成一个函数 例如 functio
  • Linux Ubuntu 虚拟机不能连网、Linux Ubuntu 虚拟机怎么连网

    主机与虚拟机文件传递移步 https blog csdn net qq 38786209 article details 79984879 notice 虚拟机不能上网 可能会有很多原因 但是如果没有特殊要求 只是想尽快连上网使用的话 推荐
  • 二叉树的优点和缺点

    二叉树的优点和缺点 二叉排序树是一种比较有用的折衷方案 数组的搜索比较方便 可以直接用下标 但删除或者插入某些元素就比较麻烦 链表与之相反 删除和插入元素很快 但查找很慢 二叉排序树就既有链表的好处 也有数组的好处 在处理大批量的动态的数据
  • CCF-CSP 202209-1 如此编码

    该题主要理解题意 首先a数组已经给你了 c数组是可以自己求出的 再按照提示所给的公式就可以很容易地求出每个b了 include
  • 地图地址转经纬度,js没加载完进行调用了高德地图的api报错处理

    传给后端需要转化成经纬度 版本问题下面代码v 1 3 使用外链加载地图js
  • python中添加进度条----trange的使用

    今天抓取某个平台数据时有个参数需要生成 因此加了个trange 对抓取添加进度条能更加直观的看到生成了多少 如图所示 添加了进度条以后看到进度就更直观了 那么这个操作是如何实现的呢 这就要提到python中的trange函数了 很简单 1
  • Redis研发实践

    author skate time 2018 12 22 1 设计规范的key名 1 建议 可读性和可管理性 以业务名 或数据库名 为前缀 防止key冲突 用冒号分隔 比如业务名 表名 id 一般redis Key需要能明显的看出该类型存储
  • 【GPU高性能编程 CUDA实战】学习笔记

    CUDA By Example an Introduction to General Purpose GPU Programming 第1章 为什么需要CUDA 第2章 入门 第3章 CUDA C 第4章 CUDA C并行编程 第5章 线程
  • Windows运行python

    windows运行py文件的方法 1 通过powershell打开 当前文件夹空白的地方 shift 右键 选择powershell选项 python 按tab选择你要运行的文件 2 通过地址栏打开 在当前文件夹地址栏上方 输入cmd 回车
  • 那些年在Opencv遇到过的Mat坑

    本文记录一些遇到过的Mat坑 以及易淆的知识点 1 热身 Mat成员之易淆 a Mat depth depth 得到的是一个0 6的数字 分别代表单个图不同的深度 对应关系如下 C1 C2 C3 C4 C 5 C 6 C 7 C 8 CV
  • 使用pd.io.sql.to_sql 将数据导入到mysql数据库

    首先导入需要的包 导入需要的包 import pandas as pd import sqlalchemy import create engine 初始化数据库 导入数据 db info user root password 123456
  • 【fly-iot飞凡物联】(12):EMQX 5.1使用docker 本地部署,接入到Actorcloud的数据库中,成功连接创建的设备,可以控制设备访问状态

    目录 前言 1 关于 2 使用docker 进行部署 3 配置API key 可以使用接口访问的 4 设置客户端认证 连接PostgreSQL 数据连接 5 使用客户端进行连接 6 EMQX的API 接口地址 7 总结 前言 本文的原文连接
  • 华为OD机试真题 Java 实现【跳格子2】【2023 B卷 100分】,附详细解题思路

    一 题目描述 小明和朋友玩跳格子游戏 有n个连续格子组成的圆圈 每个格子有不同的分数 小朋友可以选择从任意格子起跳 但是不能跳连续的格子 不能回头跳 也不能超过一圈 给定一代表每个格子得分的非负整数数组 计算能够得到的最高分数 二 输入描述
  • MATLAB2016b 下载,破解,安装

    MATLAB2016下载地址 包含安装教程 链接 https pan baidu com s 1gvYOii0Db5tHMV3blSb w 密码 zq6i 解压破解文件夹密码 rjzkgzh MATLAB C盘的安装路径 C Program
  • C语言-快速排序算法-原理-详解(完整代码)

    目录 原理 思想 代码 快排代码详解 执行结果 原理 先选择一个数作为 基准值 这里用的是 第一个数 进行一次排序 然后将所有比 基准值小的数 放在基准值的 左边 将所有比 基准值大的数 放在基准值的 右边 然后再对两边的 各自 再取一个数
  • Git基本概念及常用命令

    一 基本概念 1 1 概念 Git是一个开源的分布式版本控制系统 在项目开发过程中 我们可以用它记录我们对项目的操作记录以及项目迭代过程 git有两种类型的仓库 分别是本地仓库和远程仓库 本地仓库 是在开发人员自己电脑上的Git仓库 远程仓
  • 搭建zimg内网图片服务器+springboot+Java对接

    简述 zimg是图像存储和处理服务器 您可以使用URL参数从zimg获取压缩和缩放的图像 zimg的并发I O 分布式存储和时间处理能力非常出色 您不再需要在图像服务器中使用nginx 在基准测试中 zimg可以在高并发级别上处理每秒300
  • 对话框拦截控件消息

    BOOL CQuickMosaicDlg PreTranslateMessage MSG pMsg if pMsg gt message WM KEYDOWN 键盘按下 if pMsg gt hwnd GetDlgItem IDC DATA
  • 结构型设计模式之装饰器模式【设计模式系列】

    系列文章目录 C 技能系列 Linux通信架构系列 C 高性能优化编程系列 深入理解软件架构设计系列 高级C 并发线程编程 设计模式系列 期待你的关注哦 现在的一切都是为将来的梦想编织翅膀 让梦想在现实中展翅高飞 Now everythin