• 17 行为型模式-----迭代器模式


    模式动机(Iterator Pattern)对于聚合类的对象进行访问时,比如list,queue等,我们总希望有一个统一的访问接口,或者实现对多个聚合类对象的统一访问,或者实现对一个聚合类的多种不同访问方式,此时迭代器模式可以满足我们的这种需求。

      迭代器就是在不暴露聚合类对象内部结构的前提下,对外提供了一种访问该对象的方法。 

      一般而言,一个迭代器是和一个聚合类紧密相连的。如何实现只允许迭代器访问聚合类的内部数据而避免其他类访问呢?这里需要借助于C++中的友元类,令迭代器类为聚合类  的友元类即可实现这个目标。

     

    具体迭代器实现时有如下问题需要考虑:

    1》 迭代遍历过程由迭代器控制还是由用户控制

    若由用户控制时,这种迭代器称为外部迭代器。此时,客户必须负责向前推进遍历过程,显式地向迭代器请求下一个元素;若由迭代器控制,则称为内部迭代器。此时,迭代器会自动对聚合对象中的每个元素执行客户指定的操作。

    大多数情况下,外部迭代器比内部迭代器更加灵活,可适应多个不同类型的聚合类对象,且扩展更容易。

     

    2》 遍历算法是由迭代器定义还是由聚合类本身定义

    若迭代器负责遍历算法,那么很容易在相同的聚合类上使用不同的迭代算法,同时也易于在不同的聚合类上使用同一迭代算法;若聚合类本身定义迭代算法,那么迭代器只负责存储遍历的当前状态,相当于一个指向当前状态的指针,因此我们称这种迭代器为游标(cursor)。

    为了扩展迭代器的通用性,我们经常使用多态迭代器类型,即同时拥有一个抽象迭代器接口和具体迭代器实现类。对于不同类型的聚合对象,可以使用不同类型的迭代器实现类,这样就需要用工厂模式来分配迭代器对象。此时又有一个问题,分配的迭代器是谁来负责删除。如果由用户负责,可能造成内存泄漏,因为程序可能很复杂而忘记delete,或者在delete之前程序发生了异常。那么如何解决呢?

    方法就是使用代理模式在栈上分配一个迭代器代理,由该代理负责删除堆上分配的空间。这样当程序结束时,所有分配的空间都会得到释放。要定义这种迭代器代理,必须实现如下操作:

    1>  支持解引用操作 *

    2>  赋值操作 =

    3>  ->操作

    4>  比较操作,如!= / ==

    5>  自增操作 ++

    为了代码的简洁性,我们只重载了 -> 操作,另外需要将复制构造函数和赋值操作运算符声明为private,这样既可以防止多次delete同一对象,又可以防止编译器提供的默认实现。

     

    模式结构图:

     

    模式代码:

    bt_迭代模式.h:

     1 #ifndef IP_H
     2 #define IP_H
     3 #include <iostream>
     4 #include <string>
     5 using namespace std;
     6 
     7 /*
     8     抽象迭代器
     9 */
    10 class Iterator
    11 {
    12 public:
    13     virtual ~Iterator(){ }
    14     virtual void First() = 0;
    15     virtual void Next() = 0;
    16     virtual bool IsDone() = 0;
    17     virtual char CurrentItem() = 0;
    18 };
    19 
    20 /*
    21     抽象聚合类
    22 */
    23 class Aggregate
    24 {
    25 public:
    26     virtual ~Aggregate(){ }
    27     virtual Iterator* CreateIterator() = 0;
    28     virtual int Count() const = 0;
    29     virtual char Get(int index) const = 0;
    30 };
    31 
    32 
    33 /*
    34     具体迭代器
    35 */
    36 class ConcreteIterator : public Iterator
    37 {
    38 public:
    39     ConcreteIterator(const Aggregate* a) : aggregate(a), currentIndex(0){ }
    40     virtual void First(){ currentIndex = 0; }
    41     virtual void Next(){ currentIndex++; }
    42     virtual bool IsDone(){ return currentIndex >= aggregate->Count(); }
    43     virtual char CurrentItem()
    44     {
    45         if(IsDone())
    46         {
    47             cout << "已遍历完毕" << endl;
    48             return 0;
    49         }
    50         else
    51             return aggregate->Get(currentIndex);
    52     }
    53 
    54 private:
    55     const Aggregate* aggregate;
    56     int currentIndex;
    57 };
    58 
    59 /*
    60     具体聚合类
    61 */
    62 class ConcreteAggregate : public Aggregate
    63 {
    64 public:
    65     ConcreteAggregate(string str){ name = str; }
    66     virtual Iterator* CreateIterator()
    67     {
    68         return new ConcreteIterator(this);
    69     }
    70     virtual int Count() const{ return name.size(); }
    71     virtual char Get(int index) const{ return name.at(index); };
    72 
    73 private:
    74     string name;
    75 };
    76 
    77 #endif // IP_H

    测试用例.cpp:

     1 #include "bt_迭代器模式.h"
     2 int main()
     3 {
     4     cout << "***** 迭代器模式测试 *****" << endl;
     5     string name("benxintuzi");
     6     Aggregate* aggregate = new ConcreteAggregate(name);
     7     Iterator* iter = new ConcreteIterator(aggregate);
     8     for(iter->First(); !iter->IsDone(); iter->Next())
     9         cout << iter->CurrentItem() << endl;
    10 
    11     delete iter;
    12     delete aggregate;
    13 
    14     return 0;
    15 }
    
    

     

    模式扩展:

    将迭代器模式进行扩展,使得可以通过迭代器代理自己释放分配的内存,而不是依赖客户的手动操作。定义代理类如下:

    // ...
    
    class IteratorPtr   /* 迭代器的代理类 */
    {
    public:
        IteratorPtr(Iterator* it) : iter(it){ }
        ~IteratorPtr(){ delete iter; }                 // 删除堆上的迭代器
        Iterator* operator->(){ return iter; }
    
    private:
        IteratorPtr(const IteratorPtr&);
        IteratorPtr& operator=(const IteratorPtr&);
    
    private:
        Iterator* iter;
    };
    
    // ...
    
    int main()
    {
        cout << "***** 迭代器代理模式测试 *****" << endl;
        string name("benxintuzi");
        Aggregate* aggregate = new ConcreteAggregate(name);
        IteratorPtr iterPtr(aggregate->CreateIterator());        // 对迭代器进行包装,并且代理类指定在栈上,程序结束后代理类对象自动回收
        for(iterPtr->First(); !iterPtr->IsDone(); iterPtr->Next())
            cout << (iterPtr->CurrentItem()) << endl;
    
        return 0;
    }

    模式总结:

    :: 支持以不同的方式遍历一个聚合类,只需定义抽象迭代器的具体实现类即可更改遍历方法。

    :: 迭代器模式简化了聚合类的接口,使得聚合类本身不必再维护如何遍历的代价了。

    :: 在同一个聚合类上,通过不同的迭代器实例可以同时执行多个遍历操作,互不影响。

     

     

     

  • 相关阅读:
    图标字体IcoMoon 使用
    JS 寻找孩子并打印路径
    为什么要用on()而不直接使用click
    setTimeout 虚假的“异步”
    解决Ajax.BeginForm还是刷新页面的问题
    .net生成Excel,并下载
    C#判断文件是否正在被使用
    sql为数字添加千分位(也就是钱的格式)
    HotelIInventory项目小结
    一步一步实现FormsAuthentic验证登录
  • 原文地址:https://www.cnblogs.com/benxintuzi/p/4568865.html
Copyright © 2020-2023  润新知