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

概念

訪問者模式,是行爲模式之一,它分離對象的數據和行爲,使用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");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章