• [架构设计] 结构型模型


    目录

    一、代理模式

    二、装饰模式

    三、外观模式

    四、适配器模式


    一、代理模式

    通过一个代理类,来控制对这个对象的访问。

    类别描述
    适用场景
    • 为其他对象提供一种代理以控制对这个对象的访问
    优点
    • 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度
    缺点
    • 代理实现较为复杂

    无代理模式,人人可具备权限

    1. #include
    2. using namespace std;
    3. //提供一种代理来控制对其他对象的访问
    4. class AbstraactCommonInterface {
    5. public:
    6. virtual void run() = 0;
    7. };
    8. //我已经写好的系统
    9. class Mysystem {
    10. public:
    11. virtual void run() {
    12. cout << "系统启动..." << endl;
    13. }
    14. };
    15. //必须有权限验证,不是所有人都能来启动我的启动,必须提供用户名和密码
    16. int main() {
    17. //这样不行。是个人都能启动
    18. Mysystem* system = new Mysystem;
    19. system -> run();
    20. return 0;
    21. }

    增加代理模式

    1. #include
    2. using namespace std;
    3. //提供一种代理来控制对其他对象的访问
    4. class AbstraactCommonInterface {
    5. public:
    6. virtual void run() = 0;
    7. };
    8. //我已经写好的系统
    9. class Mysystem :public AbstraactCommonInterface{
    10. public:
    11. virtual void run() {
    12. cout << "系统启动..." << endl;
    13. }
    14. };
    15. //必须有权限验证,不是所有人都能来启动我的启动,必须提供用户名和密码
    16. class MysystemProxy :public AbstraactCommonInterface {
    17. public:
    18. MysystemProxy(string username,string password) {
    19. this->mUsername = username;
    20. this->mPassword = mPassword;
    21. }
    22. bool checkUsernameAndPassword() {
    23. if (mUsername == "admin"&&mPassword == "admin") {
    24. return true;
    25. }
    26. return false;
    27. }
    28. virtual void run() {
    29. if (checkUsernameAndPassword()) {
    30. cout << "用户名和密码正确,验证通过..." << endl;
    31. this->pSystem->run();
    32. }
    33. else {
    34. cout << "用户名或密码错误,权限不足...." << endl;
    35. }
    36. }
    37. ~MysystemProxy() {
    38. if (pSystem != NULL) {
    39. delete pSystem;
    40. }
    41. }
    42. public:
    43. Mysystem* pSystem;
    44. string mUsername;
    45. string mPassword;
    46. };
    47. int main() {
    48. #if 0
    49. //这样不行。是个人都能启动
    50. Mysystem* system = new Mysystem;
    51. system -> run();
    52. #endif
    53. //调用代理模式
    54. MysystemProxy* proxy = new MysystemProxy("root","admin");
    55. proxy->run();
    56. return 0;
    57. }

    二、装饰模式

    通过一种对客户端透明的方式,扩展对象功能

    具体操作是,功能放到单独的类中,客户端可以选择、排序等装饰对象。

    类别描述
    适用场景
    • 动态、透明的方式给单个对象添加职责
    • 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式
    优点
    • 装饰模式比继承更加灵活性,不会导致类的个数急剧增加
    • 通过一种动态的方式来扩展一个对象的功能,从而实现不同的行为
    • 可以对一个对象进行多次装饰
    缺点
    • 装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源,影响程序的性能
    1. #include
    2. using namespace std;
    3. //一般情况下,用继承实现类的功能拓展
    4. //装饰模式 可以动态给一个类增加功能
    5. //抽象英雄
    6. class AbstractHero {
    7. public:
    8. virtual void ShowStatus() = 0;
    9. public:
    10. int mHp;
    11. int mMp;
    12. int mAt;
    13. int mDf;
    14. };
    15. //具体英雄
    16. class HeroA :public AbstractHero {
    17. public:
    18. HeroA() {
    19. mHp = 0;
    20. mMp = 0;
    21. mAt = 0;
    22. mDf = 0;
    23. }
    24. virtual void ShowStatus() {
    25. cout << "血量:" << mHp << endl;
    26. cout << "魔法:" << mMp << endl;
    27. cout << "攻击:" << mAt << endl;
    28. cout << "防御:" << mDf << endl;
    29. }
    30. };
    31. //英雄穿上某个装饰物 那么他还是个英雄
    32. //装饰物
    33. class AbstractEquipmet : public AbstractHero {
    34. public:
    35. AbstractEquipmet(AbstractHero* hero) {
    36. this->pHero = hero;
    37. }
    38. virtual void ShowStatus() = 0;
    39. public:
    40. AbstractHero* pHero;
    41. };
    42. //狂徒
    43. class KuangtuEquipment :public AbstractEquipmet {
    44. public:
    45. KuangtuEquipment(AbstractHero* hero) :AbstractEquipmet(hero) {}
    46. //增加额外的功能
    47. void AddKuangtu() {
    48. cout << "英雄穿上狂徒之后..." << endl;
    49. this->mHp = this->pHero->mHp;
    50. this->mMp = this->pHero->mMp;
    51. this->mAt = this->pHero->mAt;
    52. this->mDf = this->pHero->mDf + 30;
    53. delete this->pHero;
    54. }
    55. virtual void ShowStatus() {
    56. AddKuangtu();
    57. cout << "血量:" << mHp << endl;
    58. cout << "魔法:" << mMp << endl;
    59. cout << "攻击:" << mAt << endl;
    60. cout << "防御:" << mDf << endl;
    61. }
    62. };
    63. //无尽
    64. class Wujing : public AbstractEquipmet {
    65. public:
    66. Wujing(AbstractHero* hero) :AbstractEquipmet(hero) {}
    67. //增加额外的功能
    68. void AddWujing() {
    69. cout << "英雄穿上无尽之后..." << endl;
    70. this->mHp = this->pHero->mHp;
    71. this->mMp = this->pHero->mMp;
    72. this->mAt = this->pHero->mAt + 80;
    73. this->mDf = this->pHero->mDf;
    74. delete this->pHero;
    75. }
    76. virtual void ShowStatus() {
    77. AddWujing();
    78. cout << "血量:" << mHp << endl;
    79. cout << "魔法:" << mMp << endl;
    80. cout << "攻击:" << mAt << endl;
    81. cout << "防御:" << mDf << endl;
    82. }
    83. };
    84. int main() {
    85. AbstractHero* hero = new HeroA;
    86. hero->ShowStatus();
    87. cout << "----------------------------" << endl;
    88. //给裸奔的英雄穿上衣服后
    89. hero = new KuangtuEquipment(hero);
    90. hero->ShowStatus();
    91. cout << "----------------------------" << endl;
    92. //装备武器
    93. hero = new Wujing(hero);
    94. hero->ShowStatus();
    95. return 0;
    96. }

    三、外观模式

    两个子系统,如果都初始化,传统需要一个一个new一下,现在提供一个类,在这个类里面做完初始化工作。

    外观模式就是将复杂的子类系统抽象到同一个的接口进行管理,外界只需要通过此接口与子类系统进行交互,而不必要直接与复杂的子类系统进行交互

    类别描述
    适用场景
    • 复杂系统需要简单入口使用
    • 客户端程序与多个子系统之间存在很大的依赖性
    • 可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度
    优点
    • 屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易
    • 子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可
    • 子系统的修改对其他子系统没有任何影响
    缺点
    • 对客户端访问子系统类做太多的限制则减少了可变性和灵活性
    • 设计不当,增加新的子系统可能需要修改外观类的源代码
    1. #include
    2. using namespace std;
    3. //电视机
    4. class Televison {
    5. public:
    6. void On() {
    7. cout << "电视机打开..." << endl;
    8. }
    9. void Off() {
    10. cout << "电视机关闭" << endl;
    11. }
    12. };
    13. //灯
    14. class Light {
    15. public:
    16. void On() {
    17. cout << "灯打开..." << endl;
    18. }
    19. void Off() {
    20. cout << "灯关闭" << endl;
    21. }
    22. };
    23. //音箱
    24. class Audio {
    25. public:
    26. void On() {
    27. cout << "音箱打开..." << endl;
    28. }
    29. void Off() {
    30. cout << "音箱关闭" << endl;
    31. }
    32. };
    33. //麦克风
    34. class Microphone {
    35. public:
    36. void On() {
    37. cout << "麦克风打开..." << endl;
    38. }
    39. void Off() {
    40. cout << "麦克风关闭" << endl;
    41. }
    42. };
    43. //DVD
    44. class DVDPlayer {
    45. public:
    46. void On() {
    47. cout << "DVD播放器打开..." << endl;
    48. }
    49. void Off() {
    50. cout << "DVD播放器关闭" << endl;
    51. }
    52. };
    53. //游戏机
    54. class Gamemachine {
    55. public:
    56. void On() {
    57. cout << "游戏机打开..." << endl;
    58. }
    59. void Off() {
    60. cout << "游戏机关闭" << endl;
    61. }
    62. };
    63. //KTV模式
    64. class KTVModel {
    65. public:
    66. KTVModel() {
    67. pTv = new Televison;
    68. pLight = new Light;
    69. pAudio = new Audio;
    70. pMicrophone = new Microphone;
    71. pDVD = new DVDPlayer;
    72. }
    73. void OnKtv() {
    74. pTv->On();
    75. pLight->Off();
    76. pAudio->On();
    77. pMicrophone->On();
    78. pDVD->On();
    79. }
    80. void OffKtv() {
    81. pTv->Off();
    82. pLight->On();
    83. pAudio->Off();
    84. pMicrophone->Off();
    85. pDVD->Off();
    86. }
    87. ~KTVModel() {
    88. delete pTv;
    89. delete pLight;
    90. delete pAudio;
    91. delete pMicrophone;
    92. delete pDVD;
    93. }
    94. public:
    95. Televison* pTv;
    96. Light* pLight;
    97. Audio* pAudio;
    98. Microphone* pMicrophone;
    99. DVDPlayer* pDVD;
    100. };
    101. int main() {
    102. KTVModel* ktv = new KTVModel;
    103. ktv->OnKtv();
    104. return 0;
    105. }

    四、适配器模式

    使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

    类别描述
    适用场景
    • 现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码
    • 创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作
    优点
    • 目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
    • 客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用
    • 可以在不修改原有代码的基础上增加新的适配器类
    缺点
    • 适配器中置换适配者类的某些方法比较麻烦
    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //适配器模式 就是将已经写好的接口,但是这个接口不符合需求
    6. //将写好的接口转换成目标接口
    7. //这函数我已经写好
    8. struct Myprint{
    9. void operator()(int v1,int v2) {
    10. cout << v1 + v2 << endl;
    11. }
    12. };
    13. //定义目标接口 我要是配偶 适配成什么样的,
    14. //要适配成只能传一个参数的,适配for_each第三个参数的适用
    15. class Target {
    16. public:
    17. virtual void operator()(int v) = 0;
    18. };
    19. //写适配器
    20. class Adapater :public Target {
    21. public:
    22. Adapater(int param) {
    23. this->param = param;
    24. }
    25. virtual void operator() (int v) {
    26. print(v,param);
    27. }
    28. public:
    29. Myprint print;
    30. int param;
    31. };
    32. //MyBind2nd,原来param固定的10,现在提供一个方法改
    33. Adapater MyBind2nd(int v) {
    34. return Adapater(v);
    35. }
    36. int main(void) {
    37. vector<int> v;
    38. for (int i = 0; i < 10; i++) {
    39. v.push_back(i);
    40. }
    41. //适配器模式的运用
    42. //for_each()的第三个参数是个带一个参数的函数,但是Myprint需要两个参数
    43. for_each(v.begin(),v.end(), MyBind2nd(10));
    44. return 0;
    45. }

  • 相关阅读:
    电提示找不到api-ms-win-crt-runtime-l1-1-0.dll怎么办,分享快速解决办法
    英特尔OneAPI介绍
    Linux系统架构----LNMP平台部署中部署wordpress
    目标检测YOLO实战应用案例100讲-水下机器人视域中小目标检测(中)
    计算机毕业设计(附源码)python在线付费课程学习平台
    Git实战技巧-如何同时撤回远程和本地分支合并操作
    被火车撞了都不能忘记的几道题(你会了吗?)
    开发技术-Java定位并打印异常信息
    DevOps | 企业内源(内部开源)适合什么样的公司
    Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (三)
  • 原文地址:https://blog.csdn.net/AgingMoon/article/details/128171978