訪問者模式是一種將數據操作和數據結構分離的設計模式,可以說是面向數據密集型的一種設計方式,數據的結構相對穩定,有明顯的分層和分類,而對數據對象的相關操作進行分組、分析等二次加工,這些操作都是由訪問者來執行的,而不是將這些放到被訪問的數據對象中,方便了操作方法的擴展。 作用 封裝一些作用於某種數據結構 ...
訪問者模式是一種將數據操作和數據結構分離的設計模式,可以說是面向數據密集型的一種設計方式,數據的結構相對穩定,有明顯的分層和分類,而對數據對象的相關操作進行分組、分析等二次加工,這些操作都是由訪問者來執行的,而不是將這些放到被訪問的數據對象中,方便了操作方法的擴展。
作用
封裝一些作用於某種數據結構中的各元素的操作,它可以在不改變這個數據結構的前提下定義作用於這些元素的新的操作。
類視圖
實現
訪問者模式的關鍵實現是在Element中的accept函數,該函數傳入visitor,併在函數內調用visitor的針對該對象的方法,訪問者調用元素類中的方法,又回到訪問類中進行調用的方式叫做雙重分派。
class Person
// 游樂設施
class Facility
{
public:
Facility():m_ncost_money(0), m_ncost_time(0){}
virtual void accept( Person*) =0;
virtual int SpendMoney()=0;
virtual int SpendTime()=0;
protected:
int m_ncost_money;
int m_ncost_time;
};
//摩天輪
class FerrisWheel : public Facility
{
public:
FerrisWheel():m_ncost_money(10), m_ncost_time(15){}
void accept( Person* persion)
{
persion->play(this);
}
int SpendMoney(){ return m_ncost_time;}
int SpendTime(){return m_ncost_money;}
};
//碰碰車
class BumperCar : public Facility
{
public:
BumperCar():m_ncost_money(30), m_ncost_time(10){}
void accept( Person* persion)
{
persion->play(this);
}
int SpendMoney(){ return m_ncost_time;}
int SpendTime(){return m_ncost_money;}
};
//過山車
class RollerCoaster : public Facility
{
public:
RollerCoaster():m_ncost_money(100), m_ncost_time(20){}
void accept( Person* persion)
{
persion->play(this);
}
int SpendMoney(){ return m_ncost_time;}
int SpendTime(){return m_ncost_money;}
};
class Person
{
public:
Person() : m_nToTalMoney(0),m_nToTalTime(0){}
void Play(FerrisWheel*);
void Play(BumperCar*);
void Play(FerrisWheel*);
public:
int GetTotalMoney()
{
return m_nToTalMoney;
}
int GetTotalTime()
{
return m_nToTalTime;
}
protected:
int m_nToTalMoney;
int m_nToTalTime;
}
class Adult : public Person
{
public:
void Play(FerrisWheel* ferriswheel)
{
int nMoney = ferriswheel->SpendMoney();
m_ncost_money+=nMoney;
int nTime = ferriswheel->SpendTime();
m_nToTalTime += nTime;
}
void Play(BumperCar* bumpercar)
{
int nMoney = BumperCar->SpendMoney();
m_ncost_money+=nMoney;
int nTime = BumperCar->SpendTime();
m_nToTalTime += nTime;
}
void Play(RollerCoaster* rollercoaster)
{
int nMoney = RollerCoaster->SpendMoney();
m_ncost_money+=nMoney;
int nTime = RollerCoaster->SpendTime();
m_nToTalTime += nTime;
}
};
//兒童所有花費半價
class Childen : public Person
{
public:
void Play(FerrisWheel* ferriswheel)
{
int nMoney = ferriswheel->SpendMoney()/2;
m_ncost_money+=nMoney;
int nTime = ferriswheel->SpendTime();
m_nToTalTime += nTime;
}
void Play(BumperCar* bumpercar)
{
int nMoney = BumperCar->SpendMoney()/2;
m_ncost_money+=nMoney;
int nTime = BumperCar->SpendTime();
m_nToTalTime += nTime;
}
void Play(RollerCoaster* rollercoaster)
{
int nMoney = RollerCoaster->SpendMoney()/2;
m_ncost_money+=nMoney;
int nTime = RollerCoaster->SpendTime();
m_nToTalTime += nTime;
}
};
int main()
{
FerrisWheel fw;
BumperCar bc;
RollerCoaster rc;
Childen son;
Adult mather;
//兒子玩了所有項目
son.play(fw);
son.play(bc);
son.play(rc);
//可憐的媽媽只陪兒子玩了一個過山車
mother.play(rc);
int nSonCostMoney = son.GetTotalMoney();
int nSonCostTime = son.getTotalTime();
int nMotherCostMoney = mother.GetTotalMoney();
int nMotherCostTime = mother.getTotalTime();
cout<< "Son spend money :" << nSonCostMoney << " spend time: "<< nSonCostTime; << endl;
cout<< "Mother spend money :" << nMotherCostMoney << " Mother time: "<< nMotherCostTime; << endl;
}
訪問者模式的主要問題是因為每個訪問者需要有對應的方法來處理每一種可能的具體數據,,那麼一旦實現了訪問者模式,其具體類的數量和類型就不能輕易被改變。
應用場景
- 對象結構比較穩定,但經常需要在此對象結構上定義新的操作。
- 需要對一個對象結構中的對象進行很多不同的且不相關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。