3.9.1 模式意圖:
當(dāng)我們已經(jīng)含有固定的數(shù)據(jù)結(jié)構(gòu),但需要頻繁的更改對(duì)數(shù)據(jù)操作的方式,如果將數(shù)據(jù)與行為放在一起,會(huì)影響數(shù)據(jù)所在對(duì)象結(jié)構(gòu)的穩(wěn)定性,增加操作的風(fēng)險(xiǎn),這時(shí)可以使用訪問(wèn)者模式,使數(shù)據(jù)與操作行為相對(duì)獨(dú)立的存在。
3.9.2 模式概念:
它屬于行為型模式,表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素類的前提下,重新定義作用于這些元素的操作。
3.9.3 模式元素:
- 元素抽象(Element)
- 元素細(xì)節(jié)(ConcreteElementA、ConcreteElementB)
- 訪問(wèn)抽象(Visitor)
- 訪問(wèn)細(xì)節(jié)(ConcreteVicitor)
- 含有元素的數(shù)據(jù)結(jié)構(gòu)(ObjectStructure)
3.9.4 代碼示例:
A. 元素相關(guān)
public abstract class Element
{
public abstract void Accept(Visitor visitor);
}
public class ConcreteElementA : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElement(this);
}
public void OperationA()
{
Debug.Log($"{nameof(ConcreteElementA)}:{nameof(OperationA)}");
}
}
public class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElement(this);
}
public void OperationB()
{
Debug.Log($"{nameof(ConcreteElementB)}:{nameof(OperationB)}");
}
}
B. 訪問(wèn)者相關(guān)
public abstract class Visitor
{
public abstract void VisitConcreteElement(ConcreteElementA element);
public abstract void VisitConcreteElement(ConcreteElementB element);
}
public class ConcreteVicitor : Visitor
{
public override void VisitConcreteElement(ConcreteElementA element)
{
element.OperationA();
}
public override void VisitConcreteElement(ConcreteElementB element)
{
element.OperationB();
}
}
C.包含元素的指定類
public class ObjectStructure
{
List<Element> context = new List<Element>();
public ObjectStructure()
{
context.Add(new ConcreteElementA());
context.Add(new ConcreteElementB());
}
public void RunVisitor(Visitor visitor)
{
for (int i = 0; i < context.Count; i++)
{
context[i].Accept(visitor);
}
}
}
調(diào)用示例代碼
void Start()
{
ObjectStructure structure = new ObjectStructure();
structure.RunVisitor(new ConcreteVicitor());
}
打印日志
3.9.5 寫法對(duì)比:
略
3.9.6 模式分析:
訪問(wèn)者模式的本質(zhì)是將對(duì)
ObjectStructure
的操作也就是對(duì)不同Element
對(duì)象的操作進(jìn)行了轉(zhuǎn)移,將具體的行為封裝進(jìn)Visitor
中,使操作細(xì)節(jié)的更改不會(huì)影響到ObjectStructure
和Element
的原始結(jié)構(gòu)。
當(dāng)更改或添加對(duì)Element
的操作行為時(shí),只需替換Element
所持有的Visitor
引用并豐富Visitor
細(xì)節(jié)(添加子類),即可保持Element
結(jié)構(gòu)穩(wěn)定。
Visitor類就像一個(gè)等待元素去訪問(wèn)的操作集合,里面含有各種對(duì)元素操作的行為,按需調(diào)用即可。對(duì)于操作數(shù)據(jù)結(jié)構(gòu)來(lái)講,訪問(wèn)者模式符合開閉原則的宗旨:對(duì)擴(kuò)展開放、修改封閉,提供了優(yōu)秀的擴(kuò)展與靈活性。但對(duì)于具體操作行為,
Visitor
含有多個(gè)Element
的操作方式,違反了迪米特原則。并且Element
中的Accept
行為可能會(huì)依賴于所傳參數(shù)的具體細(xì)節(jié),例如調(diào)用visitor.VisitElementA(this);
而非函數(shù)visitor.VisitConcreteElement(this);
。
3.9.7 應(yīng)用場(chǎng)景:
結(jié)構(gòu)中對(duì)應(yīng)元素很少改變,但需要經(jīng)常對(duì)元素定義新的操作。
3.9.8 小結(jié):
訪問(wèn)者模式適用于數(shù)據(jù)結(jié)構(gòu)相對(duì)穩(wěn)定的系統(tǒng),它把數(shù)據(jù)結(jié)構(gòu)與作用于結(jié)構(gòu)上的操作分離,使得操作元素集合可以相對(duì)自由地演化。如果
Element
易于變化,經(jīng)常有新的Element
對(duì)象增加到Visitor
中,就不適合使用訪問(wèn)者模式了。由于限制較多且收益不明顯,所以訪問(wèn)者模式在實(shí)際開發(fā)中使用的頻率也相對(duì)較低。