• 设计模式迭代器模式


    迭代器模式Iterator):

        提供一种方法顺序访问一个聚合对象中各个元素,而不暴漏该对象的内部表示。


        当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式。你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。
    为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。
    作者已经考虑废除这个模式了,因为现在很多语言已经支持迭代了,但是这个模式还是有实现的价值的,就是实现价值大于使用价值,接下来简单实现一下。

    迭代器模式

    .H

    #pragma once
    #include <list>
    using namespace std;
    
    //Iterator 迭代器抽象类
    class CIterator
    {
    public:
    	virtual void* First() = 0;
    	virtual void* Next() = 0;
    	virtual bool IsDone() = 0;
    	virtual void* CurrentItem() = 0;
    };
    
    //Aggregate 聚集抽象类
    class CAggregate
    {
    public:
    	virtual CIterator * CreateIterator() = 0;
    	virtual void Insert(void *const pNode) = 0;
    	virtual void Remove(void *const pNode) = 0;
    };
    
    //ConcreteAggregate 具体聚集类 继承Aggregate
    class CConcreteAggregate : public CAggregate
    {
    public:
    	list <void*> m_pItems;
    	CConcreteAggregate();
    	void Clear();
    	CIterator * CreateIterator();
    	void Insert(void *const pNode);
    	void Remove(void *const  pNode);
    };
    
    //ConcreteIterator具体迭代器类,继承Iterator
    class CConcreteIterator : public CIterator
    {
    private:
    	CConcreteAggregate *m_pAggregate;
    	int m_nCurrent;
    public:
    	CConcreteIterator(CConcreteAggregate * pAggregate);
        void* First();
    	void* Next();
    	bool IsDone();
    	void* CurrentItem();
    };

    .CPP

    #include "stdafx.h"
    #include "IteratorMode.h"
    
    CConcreteAggregate::CConcreteAggregate()
    {
    	m_pItems.clear();
    }
    void CConcreteAggregate::Clear()
    {
    	for each(auto i in m_pItems)
    	{
    		delete i;
    	}
    }
    
    CIterator * CConcreteAggregate::CreateIterator()
    {
    	return new CConcreteIterator(this);
    }
    
    void CConcreteAggregate::Insert(void *const pNode)
    {
    	m_pItems.push_back(pNode);
    }
    
    void CConcreteAggregate::Remove(void *const pNode)
    {
    	m_pItems.remove(pNode);
    }
    
    
    CConcreteIterator::CConcreteIterator(CConcreteAggregate * pAggregate)
    {
    	m_pAggregate = pAggregate;
    	m_nCurrent = 0;
    }
    
    void* CConcreteIterator::First()
    {
    	return m_pAggregate->m_pItems.size() == 0 ? NULL : *(m_pAggregate->m_pItems.begin());
    }
    
    void* CConcreteIterator::Next()
    {
    	if(IsDone()) return NULL;
    	int nSubscript = 0;
    	m_nCurrent ++;
        for each(auto i in m_pAggregate->m_pItems)
    	{
    		if(nSubscript ++ == m_nCurrent + 1)
    		{
    			return i;
    		}
    	}
    }
    
    bool CConcreteIterator::IsDone()
    {
    	return m_nCurrent >= m_pAggregate->m_pItems.size();
    }
    
    void* CConcreteIterator::CurrentItem()
    {
    	int nSubscript = 0;
    	for each(auto i in m_pAggregate->m_pItems)
    	{
    		if(nSubscript++ == m_nCurrent)
    		{
    			return i;
    		}
    	}
    	return NULL;
    }
    
    客户端调用:

    
    #include "stdafx.h"
    #include "IteratorMode.h"
    #include <iostream>
    #include <string>
    #include <windows.h>
    using namespace std;
    
    int main()
    {
    	CConcreteAggregate *pA = new CConcreteAggregate();
    	pA->Insert(new string("node-1"));
    	pA->Insert(new string("node-2"));
    	string * pstr = new string("node-3");
    	pA->Insert(pstr);
    
    	CIterator *pIteratorA = new CConcreteIterator(pA);
    	while(!pIteratorA->IsDone())
    	{
    		cout<<*((string*)pIteratorA->CurrentItem())<<endl;
    	    pIteratorA->Next();
    	}
    
    	pA->Remove(pstr);
    	CIterator *pIteratorB = new CConcreteIterator(pA);
    	while(!pIteratorB->IsDone())
    	{
    		cout<<*((string*)pIteratorB->CurrentItem())<<endl;
    		pIteratorB->Next();
    	}
    	pA->Clear();
    	delete pIteratorA;
    	delete pIteratorB;
    	delete pstr;//*自己移除的对象该迭代器不会再clear里面进行清理内存,
    	            //哎!内存谁来释放这个问题一直是一个经典的蛋疼问题,
    	            //合作开发的时候一定要注意这个问题,轻则内存泄露,重则系统崩溃。
    	return 0;
    }

    运行结果:


    总结:
        在写上面代码的时候,我一直在纠结,实现迭代器为什么非要拆成两大部分,聚集抽象类和迭代抽象类,这么想的原因就是我觉得迭代本身一个简单的类就完事了,原因是我觉得核心就是这几个接口而已:

    直接定义一个类,然后有一个离散化的连续存储,然后再把上面的那几个接口实现下就可以了,为什么还要多出来一个聚集类,然后自己想了一阵子,发现确实需要这个类,原因是如下几个:
    1.首先迭代类本身只是为了迭代,单独成一个类封装好之后通常不会去修改,也不用关心迭代的对象的其他独有特征什么的,而聚集类是把整个存储单元进行整理在一起,同时方便内存释放等,逻辑上看着也比较清晰。
    2.如果我们要扩展这个迭代器,比如增加功能A(.find功能),比如增加一个功能B(把所有元素都进行+1操作),比如增加功能C(在指定元素上进行+1)操作。其实这个时候我们也可以把A和B集成到聚集类里,然后再把C继承在迭代类里,这样相对合理,整体的操作的东西我们就放在整体管理的类,单独操作的就放在独立的类里(但是不得不说,把C加在迭代类里也不是很合适,毕竟那个类的初始目的是为了迭代)。如果这个时候我们只有一个类,把所有的东西都写在一起,内容多到一定程度的时候,就难以维护和扩展了,同时逻辑会比较乱。
  • 相关阅读:
    Server.MapPath()
    如何系统学习网络攻击技术
    查询数据库中有多少表、视图、存储过程
    测试种类
    linq使用Distinct()
    ASPxPivotGrid隐藏列
    Jenkins:Linux下安装部署步骤
    Jenkins:【测试设计】使用jenkins 插件Allure生成漂亮的自动化测试报告
    Python:Python 自动化测试框架 unittest 和 pytest 对比
    Jenkins:插件安装方式及插件下载地址
  • 原文地址:https://www.cnblogs.com/csnd/p/12062333.html
Copyright © 2020-2023  润新知