1. 程式人生 > >行為型模式之訪問者模式實現

行為型模式之訪問者模式實現

概念

訪問者模式,是行為模式之一,它分離物件的資料和行為,使用Visitor模式,可以不修改已有類的情況下,增加新的操作角色和職責。

角色和職責

訪問者模式
抽象訪問者(Visitor)角色:宣告一個或者多個訪問操作,形成所有的具體元素角色必須實現的介面。
具體訪問者(ConcreteVisitor)角色:實現抽象訪問者角色所宣告的介面,也就是抽象訪問者所宣告的各個訪問操作。
抽象節點(Element)角色:宣告一個接受操作,接受一個訪問者物件作為一個參量。
具體節點(ConcreteElement)角色:實現了抽象元素所規定的接受操作。
結構物件(ObiectStructure)角色:

有如下的一些責任,可以遍歷結構中的所有元素;如果需要,提供一個高層次的介面讓訪問者物件可以訪問每一個元素;如果需要,可以設計成一個複合物件或者一個聚集,如列(List)或集合(Set)。

適用於:資料結構 和 作用於資料結構上的操作 進行解耦合;適用於資料結構比較穩定的場合。

訪問者模式優點是增加新的操作很容易,因為增加新的操作就意味著增加一個新的訪問者,訪問者模式將有關的行為集中到一個訪問者物件中,訪問者模式的缺點是增加新的資料結構變得困難了。

優缺點

訪問者模式有如下的優點:

1,訪問者模式使得增加新的操作變得很容易。如果一些操作依賴於一個複雜的結構物件的話,那麼一般而言,增加新的操作會很複雜。而使用訪問者模式,增加新的操作就意味著增加一個新的訪問者類,因此,變得很容易。

2,訪問者模式將有關的行為集中到一個訪問者物件中,而不是分散到一個個的節點類中。

3,訪問者模式可以跨過幾個類的等級結構訪問屬於不同的等級結構的成員類。迭代子只能訪問屬於同一個型別等級結構的成員物件,而不能訪問屬於不同等級結構的物件。訪問者模式可以做到這一點。

4,積累狀態。每一個單獨的訪問者物件都集中了相關的行為,從而也就可以在訪問的過程中將執行操作的狀態積累在自己內部,而不是分散到很多的節點物件中。這是有益於系統維護的優點。

訪問者模式有如下的缺點:

1,增加新的節點類變得很困難。每增加一個新的節點都意味著要在抽象訪問者角色中增加一個新的抽象操作,並在每一個具體訪問者類中增加相應的具體操作。

2,破壞封裝。訪問者模式要求訪問者物件訪問並呼叫每一個節點物件的操作,這隱含了一個對所有節點物件的要求:它們必須暴露一些自己的操作和內部狀態。不然,訪問者的訪問就變得沒有意義。由於訪問者物件自己會積累訪問操作所需的狀態,從而使這些狀態不再儲存在節點物件中,這也是破壞封裝的。

案例一

案例需求:
比如有一個公園,有一到多個不同的組成部分;該公園存在多個訪問者:清潔工A負責打掃公園的A部分,清潔工B負責打掃公園的B部分,公園的管理者負責檢點各項事務是否完成,上級領導可以視察公園等等。也就是說,對於同一個公園,不同的訪問者有不同的行為操作,而且訪問者的種類也可能需要根據時間的推移而變化(行為的擴充套件性)
根據軟體設計的開閉原則(對修改關閉,對擴充套件開放),我們怎麼樣實現這種需求呢?

#include <iostream>
using namespace std;
#include "list"
#include "string"

class  ParkElement; 

//不同的訪問者 訪問公園完成不同的動作 
class Visitor
{
public:
    virtual void visit(ParkElement *park) = 0;
};

class ParkElement //每一個
{
public:
    virtual void accept(Visitor *v) = 0;
};

class ParkA : public ParkElement
{
public:
    virtual void accept(Visitor *v)
    {
        v->visit(this);
    }
};

class ParkB : public ParkElement
{
public:
    virtual void accept(Visitor *v)
    {
        v->visit(this);
    }
};

class Park  : public ParkElement
{
public:
    Park()
    {
        m_list.clear();
    }
    void setPart(ParkElement *e)
    {
        m_list.push_back(e);
    }
public:
    //結構物件角色:提供一個高層次的介面讓訪問者物件可以訪問每一個元素;
    void accept(Visitor *v)
    {
        for ( list<ParkElement *>::iterator it=m_list.begin(); it != m_list.end(); it++)
        {
            (*it)->accept(v);
        }
    }

private:
    list<ParkElement *> m_list;
};

class VisitorA : public Visitor
{
public:
    virtual void visit(ParkElement *park)
    {
        cout << "清潔工A訪問公園A部分,打掃衛生完畢" << endl;
    }
};

class VisitorB : public Visitor
{
public:
    virtual void visit(ParkElement *park)
    {
        cout << "清潔工B 訪問 公園B 部分,打掃衛生完畢" << endl;    
    }
};

class VisitorManager : public Visitor
{
public:
    virtual void visit(ParkElement *park)
    {
        cout << "管理員 檢查整個公園衛生打掃情況" << endl;
    }
};

void main()
{
    VisitorA *visitorA = new VisitorA;
    VisitorB *visitorB = new VisitorB;

    ParkA *partA = new ParkA;
    ParkB *partB = new ParkB;

    //公園接受訪問者a訪問
    partA->accept(visitorA);
    partB->accept(visitorB);

    VisitorManager *visitorManager = new VisitorManager;
    Park * park = new Park;
    park->setPart(partA);
    park->setPart(partB);
    park->accept(visitorManager);

    cout<<"hello..."<<endl;
    system("pause");
    return ;
}

案例二


#include <iostream>
using namespace std;
#include "string"
#include "list"

//客戶去銀行辦理業務
//m個客戶
//n個櫃員 

//將要 物件和要處理的操作分開,不同的櫃員可以辦理不同來訪者的業務

class Element;

//訪問者訪問櫃員 
class Visitor
{
public:
    virtual void visit(Element *element) = 0;
};


//櫃員接受客戶訪問
class Element
{
public:
    virtual void accept(Visitor *v) = 0;
    virtual string getName() = 0;
};

//櫃員A 員工
class EmployeeA : public Element
{
public:
    EmployeeA(string name)
    {
        m_name = name;
    }
    virtual void accept(Visitor *v)
    {
        v->visit(this); 
    }
    virtual string getName()
    {
        return m_name;
    }
private:
    string m_name;
};

//櫃員B 員工
class EmployeeB : public Element
{
public:
    EmployeeB(string name)
    {
        m_name = name;
    }
    virtual void accept(Visitor *v)
    {
        v->visit(this);
    }
    string getName()
    {
        return m_name;
    }
private:
    string m_name;
};

class VisitorA : public Visitor
{
public:
    virtual void visit(Element *element)
    {
        cout << "通過" << element->getName() << "做A業務" << endl;
    }
};

class VisitorB : public Visitor
{
public:
    virtual void visit(Element *element)
    {
        cout << "通過" << element->getName() << "做B業務" << endl;
    }
};

void main26_01()
{
    EmployeeA *eA = new EmployeeA("櫃員A");

    VisitorA *vA = new VisitorA;
    VisitorB *vB = new VisitorB;

    eA->accept(vA);
    eA->accept(vB);

    delete eA;
    delete vA;
    delete vB;
    return ;
}

//櫃員B 員工
class Employees : public Element
{
public:
    Employees()
    {
        m_list = new list<Element *>;
    }
    virtual void accept(Visitor *v)
    {
        for (list<Element *>::iterator it = m_list->begin(); it != m_list->end(); it++  )
        {
            (*it)->accept(v);
        }
    }
    string getName()
    {
        return m_name;
    }
public:
    void addElement(Element *e)
    {
        m_list->push_back(e);
    }
    void removeElement(Element *e)
    {
        m_list->remove(e);
    }
private:
    list<Element *> *m_list;
    string m_name;

};

void main26_02()
{
    EmployeeA *eA = new EmployeeA("櫃員A");
    EmployeeA *eB= new EmployeeA("櫃員B");

    Employees *es = new Employees;
    es->addElement(eA);
    es->addElement(eB);
    VisitorA *vA = new VisitorA;
    VisitorB *vB = new VisitorB;

    es->accept(vA);
    cout << "-------------" << endl;
    es->accept(vB);

    delete eA;
    delete eB;
    delete vA;
    delete vB;

    return ;
}

void main()
{
    //main26_01();
    main26_02();
    system("pause");
}