3.9設(shè)計(jì)模式之訪問(wèn)者模式(Visitor)

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ì)影響到ObjectStructureElement的原始結(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ì)較低。


更多設(shè)計(jì)模式詳見:設(shè)計(jì)模式全家桶

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容