概念
通路者模式(Visitor模式)是行為模式之一,它分離對象的資料和行為,使用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 ;
}
關注公衆号:《碼之有道》,一起聊遊戲全棧開發!
1、公衆号回複:【教程】擷取零基礎遊戲開發用戶端+服務端全套教程。
2、公衆号回複:【實戰】擷取企業級實戰項目。
3、公衆号回複:【資料】擷取大學四年整理的所有自學資料。