Iterator

我们请了一位工程师编写了一个程序,该程序只需将图书馆A的所有书籍录入然后打印出所有书籍的信息。同时我们还请了另外一位工程师编写相同的程序,不同的是他需要将图书馆B的书籍录入然后打印出书籍的信息。对于两位工程师,我们给了一个相同的数据结构:

#define DEFAULT_SIZE 1024

typedef struct _info

{

    string _name;

    string _lib;

    int price;

}BOOKINFO, *PBOOKINFO;

Okit’s a piece of cake,工程师a的代码如下:

class CLibraryABooks

{

public:

    CLibraryABooks(int iSize = DEFAULT_SIZE);

    ~CLibraryABooks();

 

public:

    void AddBook(string& name, string& lib, int price);

 

    const PBOOKINFO GetArray() const;

 

private:

    PBOOKINFO m_pArray;

    int m_iSize;

    int m_iCurrent;

};

//        CLibraryABooks

CLibraryABooks::CLibraryABooks(int iSize /* = DEFAULT_SIZE */) : m_iSize(iSize), m_iCurrent(0)

{

    if(iSize <= 0){

        m_pArray = NULL;

    }

    else{

        m_pArray = new BOOKINFO[m_iSize];

    }

}

 

CLibraryABooks::~CLibraryABooks()

{

    delete[] m_pArray;

}

 

void CLibraryABooks::AddBook(string& name, string& lib, int price)

{

    m_pArray[m_iCurrent]._name = name;

    m_pArray[m_iCurrent]._lib  = lib;

    m_pArray[m_iCurrent].price = price;

 

    m_iCurrent ++;

}

 

const PBOOKINFO CLibraryABooks::GetArray() const

{

    return m_pArray;

}

 

工程师对于STL很熟悉,自己也比较懒,所以适用了STL中的list,代码如下:

class CLibBBooks

{

public:

    CLibBBooks(int iSize = DEFAULT_SIZE);

    ~CLibBBooks();

 

public:

    void AddBook(string& name, string& lib, int price);

 

    const list<PBOOKINFO>* GetList() const;

 

private:

    list<PBOOKINFO> m_list;

};

//        CLibBBooks

CLibBBooks::CLibBBooks(int iSize /* = DEFAULT_SIZE */) : m_list(iSize)

{

}

 

CLibBBooks::~CLibBBooks()

{

}

 

void CLibBBooks::AddBook(string& name, string& lib, int price)

{

    PBOOKINFO pInfo = new BOOKINFO;

 

    pInfo->_name = name;

    pInfo->_lib  = lib;

    pInfo->price = price;

 

    m_list.push_back(pInfo);

}

 

const list<PBOOKINFO>* CLibBBooks::GetList() const

{

    return &m_list;

}

好了,拿着两位工程师的代码,我们开始了我们的工作,打印出所有书籍的名字

class CLib

{

public:

    CLib();

    ~CLib();

 

public:

    void Display();

 

private:

    CLibraryABooks libA;

    CLibBBooks libB;

};

 

void CLib::Display()

{

    const PBOOKINFO pArray = libA.GetArray();

    int iSize = libA.GetSize();

   

    for(int i=0; i<iSize; i++){

        PBOOKINFO pInfo = pArray[i];

        string szInfo = pInfo->_lib + "" + pInfo->_name;

        cout << szString << endl;

    }

   

    const list<PBOOKINFO>* pList = libB.GetList();

   

    for(list<PBOOKINFO>::iterator iter = pList->begin(); iter != pList->end(); iter++){

        PBOOKINFO pInfo = (*iter);

        string szInfo = pInfo->_lib + "" + pInfo->_name;

        cout << szString << endl;

    }  

}

 

Ok,程序可以运行了,但是,这里似乎有些问题。

1、  我们的Display()函数的实现太过依赖前面的两个类的实现,它是面向实现编程而不是接口编程。

2、  如果那天我们的其中一个类的内部存储格式改变了,那么我们的可爱的Display()函数还得修改。

3、  在这里,要想实现Display()函数,那么我们就必须要知道类CLibraryABooksCLibBBooks的数据的具体存储格式,也就是说,我们违反了OOP编程的基本准则。

那么我们看看应该怎么改过来。我们再来看看Display中不一样的代码:

for(int i=0; i<iSize; i++){

    PBOOKINFO pInfo = pArray[i];

}

 

for(list<PBOOKINFO>::iterator iter = pList->begin(); iter != pList->end(); iter++){

    PBOOKINFO pInfo = (*iter);

}

 

还记得设计模式中经常提到的那个原则吗:对变化的概念进行封装。这里变化的就是操作数据的方式。也许我们更加希望不管是那种存储格式,我们在操作的时候都使用以下统一的格式:

Iterator iter = libA.CreateIterator();

while(iter.HasNext()){

    PBOOKINFO pInfo = iter.Next();

    // ....

}

 

恩,这种方式看上去比刚才我们使用的方式简单多了。既然如此,我们就回头去修改那两个存储数据的类,让他们提供一个统一的接口吧。好想法,但是,有那么多代码需要修改,难道就没有简单一点的方法?让我们进入正题吧。

首先我们声明一个统一的接口:

class Iterator

{

public:

virtual BOOL HasNext() = 0;

virtual PBOOKINFO Next() = 0;

};

 

然后我们继承一个类下来专门处理

class CArrayIterator : public Iterator

{

public:

CArrayIterator(PBOOKINFO pArray, int iSize);

 

public:

BOOL HasNext();

PBOOKINFO Next();

 

private:

PBOOKINFO m_pArray;

int m_iSize;

int m_iIndex;

};

//        CArrayIterator

CArrayIterator::CArrayIterator(PBOOKINFO  pArray, int iSize)

: m_pArray(pArray), m_iSize(iSize)

{

m_iIndex = 0;

}

 

BOOL CArrayIterator::HasNext()

{

    return m_iIndex <= m_iSize;

}

 

PBOOKINFO CArrayIterator::Next()

{

    PBOOKINFO pInfo = m_pArray[m_iIndex];

m_iIndex ++;

 

    return pInfo;

}

 

对于List的类,我们同样有处理它的Iterator

class CListIterator : public Iterator

{

public:

    CListIterator(list<PBOOKINFO>* pList);

 

public:

    bool HasNext();

    PBOOKINFO Next();

 

private:

    list<PBOOKINFO>* m_pList;

    list<PBOOKINFO>::iterator _iter;

};

//        CListIterator

CListIterator::CListIterator(list<PBOOKINFO>* pList) : m_pList(pList)

{

    _iter = m_pList->begin();

}

 

bool CListIterator::HasNext()

{

    return _iter != m_pList->end();

}

 

PBOOKINFO CListIterator::Next()

{

    PBOOKINFO pInfo = (*_iter);

    _iter++;

    return pInfo;

}

 

我们需要改写一下CLibraryABooksCLibBBooks

class CLibraryABooks

{

public:

    const PBOOKINFO GetArray() const;

        const int GetSize() const;

const Iterator* GetIterator()

{

return new CArrayIterator(m_pArray, m_iSize);

}

 

};

 

class CLibBBooks

{

public:

const list<PBOOKINFO>* GetList() const;

         const Iterator* GetIterator()

{

return new CListIterator(m_pList);

}

};

 

在来看看我们的Display函数该怎么编写:

class CLib

{

public:

    CLib();

    ~CLib();

 

public:

    void Display();

 

private:

    void Print(Iterator* _iter);

 

private:

    CLibraryABooks libA;

    CLibBBooks libB;

};

 

void Display()

{

    Iterator* _iter = NULL;

 

_iter = libA.GetIterator();

    Print(_iter);

 

    _iter = libB.GetIterator();

    Print(_iter);  

}

 

void Print(Iterator* _iter)

{

    PBOOKINFO pInfo;

    string szMsg;

 

    while(_iter->HasNext()){

        pInfo = _iter->Next();

        szMsg = pInfo->_lib + ":" + pInfo->_name;

        cout << szMsg << endl;

    }

}

 

呵呵,很清晰,看看UML结构:

恩,结构已经很清晰了,至少在Iterator这边是很清晰了,但是,我们继续让它更清晰一些。

class CContainer

{

public:

    virtual const Iterator* GetIterator() = 0;

};

 

class CLibraryABooks : public CContainer

{

public:

    const Iterator* GetIterator();

    // some other action else

};

 

class CLibBBooks : public CContainer

{

public:

    const Iterator* GetIterator();

    // some other action else

};

 

再来看看这次设计的UML结构:

 

仔细体会一下我们的Iterator是怎么和CContainer协同工作的。也许你会说,为什么需要这么麻烦?在最开始我们直接在类CLibraryABooksCLibBBooks里面添加HasNext()Next()接口不就可以了?也就是说,我们在上面这种UML中的CContainer中添加这两个接口,去掉GetIterator()接口,这样右边的Iterator就直接可以去掉了。没错,那样的话程序的确可以运行,那么它有什么不好呢?记住:一个类最好只有一个功能。即如果类需要修改时,那么引起它修改的原则只可能是一个。这样做的好处是:可以减少类将来改变的机会,降低出错的几率。

好了,说了这么多,来看看Iterator模式正式的UML框架结构吧。

 

图中,Aggregate提供了一个公共的接口GetIterator(),然后通过Iterator进行实际的数据遍历或者其他操作,这样就把存储数据的具体实现方法和Client隔离开来,实现了松耦合。注意Iterator模式里,对存储的数据操作时,并不关心数据是否已排序,它只是从头到尾遍历而已。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值