• 设计模式的思考(四)


     看看这些模式都解决了哪些问题:

    创建模式(5个):

    // 创建一个个迷宫,某个地方将调用下面的代码

    1. ...
    2. class Maze{
    3. ...
    4. }
    5. class Room{
    6. ...
    7. }
    8. class Door{
    9. ...
    10. }
    11. ...
    12. class Game{
    13. ...
    14. //以下即为创建过程
    15. Maze CreateMaze(){
    16. Maze *aMaze=new Maze;//要修改
    17. Room *aRoom= new Room;//要修改
    18. Door *aDoor= new Door(aRoom);//要修改
    19. aMaze->AddRoom(aRoom);
    20. return aMaze;
    21. }
    22. //以上即为创建过程
    23. ...
    24. }
    25. ....
    26. int main(){
    27. ...
    28. Game *game=new Game();
    29. game->createMaze();
    30. ...
    31. }

    这段创建过程的代码的主要问题是不够灵活。如果改变了Room, Door这里的代码就要改变。比如说我们想把这个Room,改为EnchantedRoom呢?就要将第2行代码改掉,加入EnchantedRoom的定义。可能要考虑这里的实现逻辑,并添加新类。修改的地方太多。

    工厂模式:想买一辆车或开发一辆新车,你肯定是找汽车制造厂,不会找服装厂。解决接口问题。

    1. ...
    2. class Maze{
    3. ...
    4. }
    5. class Room{
    6. ...
    7. }
    8. class Door{
    9. ...
    10. }
    11. ...
    12. class Factory{
    13. ...
    14. Maze* makeMaze(){...};
    15. Room* makeRoom(){...};
    16. Door* makeDoor(){...};
    17. ...
    18. }
    19. //可以添加不同的工厂,每一个工厂可以制造不同的maze,room &door
    20. //但是有可能要定义很多的类,但是采用工厂模式可以使得建造有统一的接口
    21. clas Factory1:public Factory{
    22. ...
    23. Maze* makeMaze(){
    24. return new Maze();
    25. };
    26. ...
    27. }
    28. ...
    29. clas FactoryN:public Factory{
    30. ...
    31. Maze* makeMaze(){
    32. return new MazeN();
    33. };
    34. ...
    35. }
    36. //
    37. class Game{
    38. ...
    39. Maze CreateMaze(){
    40. Factory *factory= new FactoryN();//可以修改,但是涉及到具体逻辑,且如果工厂很多,
    41. //有不同的风格他人难以使用,需要继续演化
    42. Maze *aMaze=factory->makeMaze();
    43. Room *aRoom=factory->makeRoom;
    44. Door *aDoor=factory->makeDoor(aRoom);
    45. aMaze->AddRoom(aRoom);
    46. return aMaze;
    47. }
    48. ...
    49. }
    50. ....
    51. int main(){
    52. ...
    53. Game *game=new Game();
    54. game->createMaze();
    55. ...
    56. }

    可以定义新的方法来实现部件,而修改只有1处。

    抽象工厂模式:当同类工厂比较多,比较复杂的时候,你要将他们继续分类和组合,一类工厂创建一类产品,抽象工厂就是总公司。一家人的衣服怎么收藏?假设有一个衣帽间,衣帽间里有3个衣橱,分别存爸爸的衣服,妈妈的,孩子的。解决风格问题。

    1. ...
    2. class Maze{
    3. ...
    4. }
    5. class Room{
    6. ...
    7. }
    8. class Door{
    9. ...
    10. }
    11. ...
    12. class Factory{
    13. ...
    14. Maze* makeMaze(){...};
    15. Room* makeRoom(){...};
    16. Door* makeDoor(){...};
    17. ...
    18. }
    19. //可以添加不同的工厂,每一个工厂可以制造不同的maze,room &door
    20. //但是有可能要定义很多的类,但是采用工厂模式可以使得建造有统一的接口
    21. clas Factory1:public Factory{
    22. ...
    23. Maze* makeMaze(){
    24. return new Maze();
    25. };
    26. ...
    27. }
    28. ...
    29. clas FactoryN:public Factory{
    30. ...
    31. Maze* makeMaze(){
    32. return new MazeN();
    33. };
    34. }
    35. //抽象工厂将不同的风格进行了统一
    36. class FactoryProducer{
    37. ...
    38. Factory getMazeFactory(){//可以修改
    39. //style1
    40. return factory1;
    41. .....
    42. //styleN
    43. return factoryN;
    44. }
    45. ...
    46. }
    47. class Game{
    48. ...
    49. Maze* CreateMaze(){
    50. Factory factory=FactoryProducer.getMazeFactory();
    51. Maze *aMaze=factory.makeMaze();
    52. Room *aRoom=factory.makeRoom;
    53. Door *aDoor=factory.makeDoor(aRoom);
    54. aMaze->AddRoom(aRoom);
    55. return aMaze;
    56. }
    57. ...
    58. }
    59. .....
    60. int main(){
    61. ...
    62. Game *game=new Game();
    63. game->createMaze();
    64. ...
    65. }

    单例模式:避免一个全局使用的类频繁地创建与销毁。比如GUI的画笔。FactoryProducer就可以采用单例。

    1. class Singleton{
    2. ...
    3. static Singleton Instance(){
    4. if(_instance==0){
    5. _instance=new Singleton();
    6. }
    7. return _instance;
    8. }
    9. ...
    10. private
    11. static Singleton * _instance;
    12. }
    13. ...
    14. Singleton:: _instance=0;

    建造者模式:复杂对象的各个部分相对稳定,但是将它们组合在一起的算法却经常面临着剧烈的变化,但是又要统一管理,将稳定部分和非稳定部分分离,分别创建。建稳定部分与非稳定部分结合的是创建者。餐厅账单的项目是变化的,计算账单的总额方法是固定的。

    1. ...
    2. class Maze{
    3. ...
    4. }
    5. class Room{
    6. ...
    7. }
    8. class Door{
    9. ...
    10. }
    11. ...
    12. class Factory{
    13. ...
    14. Maze* makeMaze(){...};
    15. Room* makeRoom(){...};
    16. Door* makeDoor(){...};
    17. ...
    18. }
    19. //可以添加不同的工厂,每一个工厂可以制造不同的maze,room &door
    20. //但是有可能要定义很多的类,但是采用工厂模式可以使得建造有统一的接口
    21. clas Factory1:public Factory{
    22. ...
    23. }
    24. ...
    25. clas FactoryN:public Factory{
    26. ...
    27. }
    28. //抽象工厂将不同的风格进行了统一
    29. class FactoryProducer{
    30. ...
    31. Factory getMazeFactory(){//可以修改
    32. //style1
    33. return factory1;
    34. .....
    35. //styleN
    36. return factoryN;
    37. }
    38. ...
    39. }
    40. //新加入,可以采用统一的方式进行管理
    41. class MazeBuilder{
    42. List itemList=new List;
    43. ....
    44. BuildMaze(){...};
    45. BuildRoom(){...};
    46. BuildDoor(){...};
    47. ...
    48. GetMaze(){};
    49. ....
    50. }
    51. ...
    52. class Game{
    53. ...
    54. Maze* CreateMaze(){
    55. Builder builder= new MazeBuilder();
    56. builder.BuildMaze();
    57. builder.BuildRoom(1);
    58. builder.BuildDoor(1)
    59. return builder.GetMaze();
    60. }
    61. ...
    62. }
    63. int main(){
    64. ...
    65. Game *game=new Game();
    66. game->createMaze();
    67. ...
    68. }
    69.  原型模式:利用已有对象进行克隆,使一个系统独立于它的产品创建、构成和表示,减少类的数目。

      1. ...
      2. class Maze{
      3. ...
      4. clone(){...}//新添加
      5. ...
      6. }
      7. class Room{
      8. ...
      9. clone(){...}//新添加
      10. ...
      11. }
      12. class Door{
      13. ...
      14. clone(){...}//新添加
      15. ...
      16. }
      17. ...
      18. class Factory{
      19. Factory(Maze *m,Room*r,Door* d){
      20. __prototyMaze=m;
      21. __prototyRoom=r;
      22. __prototyDoor=d;
      23. }
      24. ...
      25. Maze* makeMaze(){return _prototyMaze->clone();}
      26. Room* makeRoom(){return _prototyRoom->clone();}
      27. Door* makeDoor({return _prototyDoor->clone();}
      28. ...
      29. Maze *_prototyMaze;//原型
      30. Room *_prototyRoom;//原型
      31. Door *_prototyDoor;//原型
      32. //初始化原型,也可以在构造函数中
      33. InitializePrototy(maze*,room*,door*){...}
      34. }
      35. //可以添加不同的工厂,每一个工厂可以制造不同的maze,room &door
      36. //但是有可能要定义很多的类,但是采用工厂模式可以使得建造有统一的接口
      37. //有太多的工厂类了,删除,用原型模式
      38. //clas Factory1:public Factory{
      39. //...
      40. // Maze* makeMaze(){
      41. // p=_prototyMaze->clone();
      42. // //下面对原型进行改造
      43. // ...
      44. // return p;
      45. // };
      46. //...
      47. //}
      48. //...
      49. //clas FactoryN:public Factory{
      50. //...
      51. // Maze* makeMaze(){
      52. // p=_prototyMaze->clone();
      53. // //下面对原型进行改造
      54. // ...
      55. // return p;
      56. // };
      57. //}
      58. //抽象工厂将不同的风格进行了统一
      59. class FactoryProducer{
      60. ...
      61. Factory getMazeFactory(){//可以修改
      62. //style1
      63. return new Factory(m1,r1,d1);
      64. .....
      65. //styleN
      66. return new Factory(mN,rN,dN);
      67. }
      68. //新加入,可以采用统一的方式进行管理
      69. class MazeBuilder{
      70. List itemList=new List;
      71. ....
      72. BuildMaze(){...};
      73. BuildRoom(){...};
      74. BuildDoor(){...};
      75. ...
      76. GetMaze(){};
      77. ....
      78. }
      79. ...
      80. class Game{
      81. ...
      82. Maze* CreateMaze(){
      83. Builder builder= new MazeBuilder();
      84. builder.BuildMaze();
      85. builder.BuildRoom(1);
      86. builder.BuildDoor(1)
      87. return builder.GetMaze();
      88. }
      89. ...
      90. }
      91. int main(){
      92. ...
      93. Game *game=new Game();
      94. game->createMaze();
      95. ...
      96. }
      97. @@

        想造汽车,太麻烦,找一家汽车厂给我造(工厂模式),轿车,卡车、公交车等等都要工厂来造,时间久了,各种车的型号、规格越来越多,汽车厂也搞不定了,汽车厂升级为汽车集团(抽象工厂模式),下设轿车、卡车、公交车等工厂。各种车的规格也不能有无限多个,典型的几种底盘、发动机、外形、内饰等进行组合,就可以生产出多种型号的汽车(建造者模式)。另外可能有时候有客户要定制汽车,其实也简单,汽车都是差不多的,先把旧车准备着,他的要求明确了(可能是查数据库等),在旧车上更改参数(原型模式)就可以了。改车时需要用到大铁锤,每个车间都要用,干嘛每次都是先写报告申请,每次都要填出库、入库单才能用?不如放到一个固定的位置,谁用谁拿,不要申请了,反正只需要一把(单例模式)!

        其他类型的对象的创建照此办理。

        @@

        结构模式(7个):

        适配器模式:主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。比如现在笔记本电脑上一般没有串口了,只有USB口,怎么办?买一个usb转232,485等转接卡。还有网关等也是适配器模式。

        桥接模式:相当于采购部。买什么由部门定,怎么买由采购部决定。买什么和怎么买分开,买和卖统合于采购部。每个人都可以买东西,但是并不需要知道如何买东西。

        组合模式:相当于单位再划分各个业务部门管理所有员工。采用树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

        外观模式:相当于打官司时的律师。律师按照你的要求帮你查资料、走流程,你把该有的资料交给他就可以了。也相当于单位的收发室。要是邮递员把每一封邮件都亲自交到收件人手里,那么邮递员要楼上楼下到处跑,把他累死了也搞不好,况且有些单位的信息你也不希望让外人知道。大家之间的关系也简单了。

        装饰器模式:相当于审批盖章部门。盖过章的文件与原来的文件是不一样的,一般动态添加功能。装饰器模式主要是为了增强功能。

        享元模式:每个领导都要配一部车,太浪费了,搞一个车队,需要时去申请,如果车不够了,再去买。

        代理模式:相当于银行(或财务处)。为了安全的原因,你不能直接到金库中去钱,必须通过银行。代理模式主要是为了控制。

        @@

        你的老板是个老外,你和他交流必须通过翻译(适配器模式)。一天他准备给所有人配个usb转接卡,但是申请流程很复杂,他就交给你(中介,外观模式)来办。你打印了一份申请表,到各个部门审批(装饰器模式),最后要大领导审批,你将申请表寄到总部,总部收发处(享元模式)收到后将申请表交到秘书处,分管设备采购的领导秘书(过滤器模式)发现这份文件就将该文件取走,并在领导审批签字同意后转交给你。收到文件后你将申请表交给后勤处(代理模式),但是库房没有,所以后勤处让采购部门(桥接模式)去采购,购买回来,入库,然后通知将你所有转接卡领出来。你领出设备后,按照部门将转接卡发给各个部门负责人,由各个部门再将转接卡发给个人(组合模式)。

        @@

        过滤器(标准)模式:相当于秘书处。每天收到那么多的公文,这些公文都要交给谁审阅,一种方式是一个秘书对应所有领导,领导换了,他要重新确定领导权限;另一种方式是一个秘书对应一位领导,领导换了,只要换一位秘书,其他秘书工作量不变。

        行为模式(11个)

        策略模式:诸葛亮发的锦囊。外表一样,但是如何处理锦囊中的内容是不一样的。锦囊太多(大于4)考虑采用混合模式。

        命令模式:领导命令下属部门办事,有两种方法:1直接找下面的职能部门;2交给秘书,让秘书通知通知相应职能部门。命令模式采用第2种方式,领导甚至不需要具体是哪个职能部门执行的命令。

        观察者模式:传达室看门老大爷老是打瞌睡,人来了也不开门,怎么办?改成感应门,接近开关(观察者)一旦检测到有人自动开门。老大爷失业了。

        中介者模式:100个人如何相互认识呢?两两相互介绍?太慢了!也太复杂了。找一个地方(中介者),每人上去自我介绍。网络状交互变为星型交互。中介把大家拉到一起(注意和外观模式区别,外观模式只对客户一方负责,中介对大家负责)。有了中介以后,大家不需要两两接触了。这也相当于单位的收发室。

        访问者模式:相当于到档案室查询资料。查询本身不改变档案信息内容。

        责任链模式:相当于工厂的流水线。工件到你面前了,你只管按螺丝,其他不管。

        备忘录模式:事情太多,记不住忘了怎么办?用个小本本。

        模板模式:写工作日志。每次都是从头写吗?可能每天都是差不多的工作,写一个模板,改改工件名称和数量,其他不变。甚至就是填一个表单。

        解释器模式:很少用到。很像命令模式。但是当领导交代的命令非常复杂,甚至可能是涉及多部门的,这是对秘书(参谋)的要求就高了,领导不需要知道涉及那些部门(我只要知道结果),秘书可要知道,并且还要协调部门间的工作。领导只是说自己的一些习惯用语(黑话,只要内部人懂,但是沟通效率高)。秘书这时候就不仅仅是上传下达了。

        迭代器模式:怎么样数部门人头?领导是不管的,也管不过来,部门太多,每个部门又太复杂,干脆专门安排一个人负责该工作。在领导面前,他希望看到的是大家都是站成一排,一个词:简单。这可苦了迭代器。

        状态模式:类似流水线(状态机)。一个产品有多道工序,每个工序又有不同的处理。早期一个人干所有的事情,现在几个人(状态)干,每人干一道工序,并且每个人都知道怎么干,自己做好了下一道工序交给谁(状态转换)。要注意与策略模式相区别,策略模式是单线条,单方向,状态模式可能是环,甚至更复杂。

        @@

        很搞笑,诸葛亮命令他的三个手下(访客,观察者,中介者),按照他给的锦囊(策略)行事:每人手里拿一个小工具,另一只手拖一台大机器。三个小工具分别是:模板,备忘录,还有一个链子。三台大机器是:解释器、迭代器、状态机。

        @@

      98. 相关阅读:
        内部类及Lambda表达式
        VSCode C++环境配置及测试运行
        【tg】6: MediaManager的主要功能
        Python 数据可视化:Seaborn 库的使用
        java小项目01:回文数的判断+剪刀石头布
        Qt——设置字体样式
        Isito 入门(四):微服务可观测性
        JavaScript 的真值与假值 | 如何判断一个对象为空
        计算机网络408考研 2021
        舵机云台实现体感姿态跟随功能
      99. 原文地址:https://blog.csdn.net/wxg_wuchujie88/article/details/125883083