• 设计模式-适配器模式(结构型)、迭代器模式(行为型)、组合模式(结构型)


    0 迭代器模式和适配器模式组合模式

    这几个模式放在一起讲的原因在于:都在向外界提供统一的借口

    适配器模式是在项目已经开始,新加入的对象需要和原有对象有一致的接口。

    而迭代器模式应用则比较狭隘,只是为了遍历容器中的对象,向外提供统一的接口。

    组合模式在于不同种类的某种事物向外提供统一的接口。

    1 适配器模式

    1.0 需求

    通常都是某个类A已经在系统中使用了很长时间,使用该类的代码也很多。后来突然来了一个类B,类B具有和类A同样的功能,但是实现不同,而且向外提供的接口不同。也就是说类A和类B不派生自同一个类。

    因此适配器模式解决的问题是,如何处理两个功能相同,但是提供接口的类,让其向外提供统一的接口。

    方法很简单,新增一个类C,让类C关联(组合)类B,同时继承类A的基类。类C中的接口通过关联的类B实例实现一样的功能。

    适配器模式的最终目标:已有的代码能够复用

    要注意:之前的类A一定是一个派生类,也就是有一个基类。如果没有基类,这个模式行不通。如果之前的类没有一个基类。那么后面的类智能使用相同的方法调用。但是之前的代码不能够复用,因为需要的参数不能够转换。重载类型转换也是不可以的。

    1.1 实现

    class ABCompiler 
    {
    public:
       virtual void do()=0; 
    };


    // 已有的使用很久的类,不能够变更 class Gnu :public ABCompiler { public: void do(Path,Op);//选项和 do 方法结合在一起 }; // 新来了一个能够提供一样功能的类 class Clang { public: void compile(); void add_op(); // 编译选项需要额外添加 private: Op op; }; class CompilerClang :public ABCompiler { public: //内部实现和 gnu 相同的功能 virtual void do(Path path,Op op) { clang.add_op(op); clang.compile(Path); } private: Clang clang; //组合的方式,在 CompilerClang 创建的时候创建,销毁的时候销毁。 };

      

    1.2 缺点

    之前的类,一定要存在继承体系,不然已有的使用类的代码不能够工作。

    也就是说要符号依赖倒置和里氏替换原则,才能够使用适配器模式。

    2 迭代器模式

    2.0 需求

    存在不同的容器,vector和map,两者之间遍历元素的方式不同。一种是数组,一种是树。

    而迭代器模式,就是封装两者遍历元素的行为,向外提供统一的接口:

    1. ++下一个元素
    2. --上一个元素

    因此迭代器模式可以理解为重载容器的++和--运算符,但是直接重载容器类的++和--肯定不行,因为不能做到代码复用,也就是说使用vector的代码不能用在map上。

    因此,新增一个Iterator的虚基类,有next、end和begin三个接口。然后为不同的容器新增一个具体的迭代器类,继承Iterator虚基类。

    然后不同容器关联(组合)这个迭代器类的实例。

    2.1 现状

    迭代器模式,现在已经很少自己实现了。一般是有语言或是标准库提供。因为迭代器一般使用在容器上的。而容器又是标准库提供的。

    c++标准库的迭代器也不是使用迭代器模式实现的。

    而是使用模板+函数重载实现的。

     

    3 组合模式

    3.0 需求

    在某些情况下,用到分支和节点。也就是子节点和叶节点,操作不同种类的节点之间出现的情况不同。

    例如,linux下各种文件类型,打开普通文件和目录文件的结果是不同的。

    因此需要一种设计模式,能够统一的访问这些资源。也就是说以统一的接口访问节点。

    并且节点之间存在包含的关系。

    这其实和适配器模式类似,都是需要提供统一的接口

    3.1 实现

    既然有统一的接口,那就需要一个基类提供接口,然后节点继承基类,覆写方法,实现多态。

    节点之间存在包含的关系,类内关联一个容器,存储其子节点

    //提供统一的方式
    class Node
    {
    public:
      virtual void add(Node*)=0;
      virtual void remove(Node*)=0;
      virtual Node* show(int index)=0;
    };
    
    class left:public Node
    {
    //。。。。
    private:
      vector<Node*> _list;
    };
    
    class Branch:public Node
    {
    //。。。
    private:
      vector<Node*> _list;
    };
    

      

    如果基类提供节点所有可能的操作,而一个节点不应该包含某个操作,在编译的时候会报错,因为纯虚函数没有定义。

    如果基类只提供各个节点都有的功能,不同类型的节点类自行添加方法,那么也是在编译期报错。

  • 相关阅读:
    边框
    文本样式
    框架
    表格
    列表
    标签
    常用类--包装类
    常见类 --Object
    日志
    异常
  • 原文地址:https://www.cnblogs.com/perfy576/p/8549910.html
Copyright © 2020-2023  润新知