C++設計模式 – 訪問器模式(Visitor)

行為變化模式

  • 在組件的構建過程中,組件行為的變化經常導致組件本身劇烈的變化。「行為變化」 模式將組件的行為和組件本身進行解耦,從而支持組件行為的變化,實現兩者之間的松耦合。

典型模式

Visitor

動機( Motivation )

  • 在軟件構建過程中,由於需求的改變,某些類層次結構中常常需要增加新的行為(方法) , 如果直接在基類中做這樣的更改,將會給子類帶來很繁重的變更負擔,甚至破壞原有設計。
  • 如何在不更改類層次結構的前提下,在運行時根據需要 透明地為類層次結構.上的各個類動態添加新的操作,從而避免,上述問題?

模式定義

表示一個作用於某對象結構中的各元素的操作。使得可以在不改變(穩定)各元素的類的前提下定義(擴展)作用於這些元素的新操作(變化)。

結構

在這裡插入圖片描述

要點總結

  • Visito:模式通過所謂雙重分發(double dispath )來實現在不更改,(不添加新的操作-編譯時)Elemen類層次結構的前提下在運行時透明地為類層次結構上的各個類動態添和新的操作(支持變化)。
  • 所謂雙重分發即Visitor模式中間包括了兩個多態分發(注意其中的多態機制):第一個為accept方法的多態 辨析;第二個為visitElementX方法的多態辨析
  • Visito模式最大缺點在於擴展類層次結構(增添新的Element子類)會導致Visito類的改變。因此Visito模式適用於Element類層次結構穩定,而其中的操作卻經常面臨頻繁改動。

cpp

#include<iostream>
using namespace std;

class Visitor;
class Element {
public:
	virtual void accept(Visitor& visitor) = 0;//第一次多態辨析(找accept)
	virtual ~Element() {}
};
class ElementA :public Element {
public:
	virtual void accept(Visitor& visitor) override; //第二次多態辨析(找visitElementA)
};
class ElementB :public Element {
public:
	void accept(Visitor& visitor) override;
};

class Visitor {
public:
	virtual void visitElementA(ElementA& element) = 0;
	virtual void visitElementB(ElementB& element) = 0;
	virtual ~Visitor() {}
};

void ElementA::accept(Visitor& visitor) {
	visitor.visitElementA(*this);//第二次多態辨析(找visitElementA)
}
void ElementB::accept(Visitor& visitor) {
	visitor.visitElementB(*this);
}
//=================
//對行為進行更改
class Visiter1 :public Visitor {
public:
	void visitElementA(ElementA& element) override {
		cout << "Visitor1 process ElementA" << endl;
	}
	void visitElementB(ElementB& element) override {
		cout << "Visitor1 process ElementB" << endl;
	}
};

class Visiter2 :public Visitor {
public:
	void visitElementA(ElementA& element) override {
		cout << "Visitor2 process ElementA" << endl;
	}
	void visitElementB(ElementB& element) override {
		cout << "Visitor2 process ElementB" << endl;
	}
};

int main()
{
	Visiter1 visitor;
	ElementA elementA;
	elementA.accept(visitor);//二次多態辨析

	ElementB elementB;
	elementB.accept(visitor);
	return 0;
}