一. 訪問者模式
定義:表示一個作用於某對象結構中的各元素的操作。它你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
結構如下:
二. 舉例
假設有一項科學實驗,是用來對比兩種種子在不同環境下的生長情況。
兩種種子,一種是普通的種子(Seed_A),一種是太空運回的種子(Seed_B)。
生長環境,分別是在多雨環境下(Rain_Status),陽光環境下(Sun_Status)等等。
結構如下:
代碼如下:
[cpp] //狀態
class Status
{
public:
virtual ~Status() {}
virtual void VisitSeed_A(Seed* elm) {}
virtual void VisitSeed_B(Seed* elm) {}
protected:
Status() {}
};
//下雨狀態
class Rain_Status:public Status
{
public:
Rain_Status() {}
virtual ~Rain_Status() {}
//下雨狀態下A種子生長的情況
virtual void VisitSeed_A(Seed* elm)
{
cout<<"Rain will visit Seed A..."<<endl;
}
//下雨狀態下B種子生長的情況
virtual void VisitSeed_B(Seed* elm)
{
cout<<"Rain will visit Seed B..."<<endl;
}
};
//陽光狀態
class Sun_Status:public Status
{
public:
Sun_Status() {}
virtual ~Sun_Status() {}
//陽光狀態下A種子生長的情況
virtual void VisitSeed_A(Seed* elm)
{
cout<<"Sun will visit Seed A..."<<endl;
}
//陽光狀態下B種子生長的情況
virtual void VisitSeed_B(Seed* elm)
{
cout<<"Sun will visit Seed B..."<<endl;
}
};
//種子
class Seed
{
public:
virtual ~Seed() {}
virtual void Accept(Status* vis) = 0;
protected:
Seed() {}
};
//種子A,假設為普通種子
class Seed_A:public Seed
{
public:
Seed_A() {}
~Seed_A() {}
void Accept(Status* vis)
{
vis->VisitSeed_A(this);
}
};
//種子B,假設為從太空帶回來的種子
class Seed_B:public Seed
{
public:
Seed_B() {}
~Seed_B() {}
void Accept(Status* vis)
{
vis->VisitSeed_B(this);
}
};
//對象結構類,為了對比不同種子
class ObjectStructure
{
private:
list<Seed*> lseed;
public:
//Add
void Attach(Seed* seed)
{
lseed.push_back(seed);
}
//Delete
void Detach(Seed* seed)
{
lseed.remove(seed);
}
//Show
void Display(Status* status)
{
list<Seed*>::iterator it = lseed.begin();
for (it; it != lseed.end(); ++it)
{
(*it)->Accept(status);
}
}
};
//測試代碼
int main(int argc,char* argv[])
{
ObjectStructure obj;
//加入要對比的兩個種子
obj.Attach(new Seed_A());
obj.Attach(new Seed_B());
//查看各種狀態下兩個種子的情況
obj.Display(new Rain_Status());
//Sun Satte
obj.Display(new Sun_Status());
return 0;
}
//狀態
class Status
{
public:
virtual ~Status() {}
virtual void VisitSeed_A(Seed* elm) {}
virtual void VisitSeed_B(Seed* elm) {}
protected:
Status() {}
};
//下雨狀態
class Rain_Status:public Status
{
public:
Rain_Status() {}
virtual ~Rain_Status() {}
//下雨狀態下A種子生長的情況
virtual void VisitSeed_A(Seed* elm)
{
cout<<"Rain will visit Seed A..."<<endl;
}
//下雨狀態下B種子生長的情況
virtual void VisitSeed_B(Seed* elm)
{
cout<<"Rain will visit Seed B..."<<endl;
}
};
//陽光狀態
class Sun_Status:public Status
{
public:
Sun_Status() {}
virtual ~Sun_Status() {}
//陽光狀態下A種子生長的情況
virtual void VisitSeed_A(Seed* elm)
{
cout<<"Sun will visit Seed A..."<<endl;
}
//陽光狀態下B種子生長的情況
virtual void VisitSeed_B(Seed* elm)
{
cout<<"Sun will visit Seed B..."<<endl;
}
};
//種子
class Seed
{
public:
virtual ~Seed() {}
virtual void Accept(Status* vis) = 0;
protected:
Seed() {}
};
//種子A,假設為普通種子
class Seed_A:public Seed
{
public:
Seed_A() {}
~Seed_A() {}
void Accept(Status* vis)
{
vis->VisitSeed_A(this);
}
};
//種子B,假設為從太空帶回來的種子
class Seed_B:public Seed
{
public:
Seed_B() {}
~Seed_B() {}
void Accept(Status* vis)
{
vis->VisitSeed_B(this);
}
};
//對象結構類,為了對比不同種子
class ObjectStructure
{
private:
list<Seed*> lseed;
public:
//Add
void Attach(Seed* seed)
{
lseed.push_back(seed);
}
//Delete
void Detach(Seed* seed)
{
lseed.remove(seed);
}
//Show
void Display(Status* status)
{
list<Seed*>::iterator it = lseed.begin();
for (it; it != lseed.end(); ++it)
{
(*it)->Accept(status);
}
}
};
//測試代碼
int main(int argc,char* argv[])
{
ObjectStructure obj;
//加入要對比的兩個種子
obj.Attach(new Seed_A());
obj.Attach(new Seed_B());
//查看各種狀態下兩個種子的情況
obj.Display(new Rain_Status());
//Sun Satte
obj.Display(new Sun_Status());
return 0;
}
三. 說明
1. 首先有一點要明確,就是兩種種子不會輕易改變,也就是只有普通和太空種子兩種。換句話說就是,數據結構比較穩定。
2. 可以變的是新增的狀態,比如增加一個X光下的生成情況,等等。說白了就是,操作集合可以相對自由的演化。
3. 這種結構的優點是,增加新的操作很容易;缺點是,增加新的數據結構有點困難,因為你要在每一個訪問者裡都添加相應的操作。
4. 種子生長圖相對於訪問者模式的結構圖有如下關系:
seed(種子)相當於 element(元素),這個是不怎麼變的。
status(狀態) 相當於 visitor(訪問者),這個是可變且易變的。要注意的是,每個訪問者都要對所有的元素(element)進行操作。
5. 事實上我們很少用這種模式,因為數據結構(element)不變的情況很少。
作者 lwbeyond