訪問者(Visitor)

意圖

表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作,它使你可以在不改變各元素的類的前提下,定義作用于這些元素的新操作。

結(jié)構(gòu)

訪問者結(jié)構(gòu)圖

適用性

  • 一個(gè)對(duì)象結(jié)構(gòu)包含很多類對(duì)象,它們有不同的接口,而你想對(duì)這些對(duì)象實(shí)施一些依賴于其具體類的操作;
  • 需要對(duì)一個(gè)對(duì)象結(jié)構(gòu)中的對(duì)象進(jìn)行很多不同的并且不相關(guān)的操作,而你想避免讓這些操作“污染”這些對(duì)象的類;
  • 定義對(duì)象結(jié)構(gòu)的類很少改變,但經(jīng)常需要在此結(jié)構(gòu)上定義新的操作。

優(yōu)缺點(diǎn)

  • 訪問者模式使得易于增加新的操作,僅需增加一個(gè)新的訪問者即可在一個(gè)對(duì)象結(jié)構(gòu)上定義一個(gè)新的操作;
  • 相關(guān)的行為被集中在訪問者中,無關(guān)的行為被分散到各自的訪問者子類中;
  • 每增加一個(gè)新的Element類,就需要在Visitor及其子類中添加新的操作;
  • 通過類層次進(jìn)行訪問,可以訪問具有不同父類的對(duì)象,可以對(duì)Visitor增加任意類型的對(duì)象;
  • 當(dāng)訪問者訪問對(duì)象結(jié)構(gòu)中每一個(gè)元素時(shí),它能夠積累狀態(tài);
  • 訪問者通常需要訪問每一個(gè)元素的內(nèi)部狀態(tài),因此很可能會(huì)破壞元素的封裝性。


示例

一個(gè)編譯器將源代碼轉(zhuǎn)換為抽象語法樹之后,需要對(duì)該抽象語法樹中的各個(gè)節(jié)點(diǎn)(變量節(jié)點(diǎn),賦值節(jié)點(diǎn)等)進(jìn)行類型檢查(TypeCheck)、格式打?。≒rettyPrint)及擴(kuò)展的各種操作。

實(shí)現(xiàn)(C#)

using System;

public abstract class Node
{
    public abstract void Accept(NodeVisitor visitor);
}

public class VariableRefNode : Node
{
    public override void Accept(NodeVisitor visitor)
    {
        visitor.VisitVariableRefNode(this);
    }
}

public class AssignmentNode : Node
{
    public override void Accept(NodeVisitor visitor)
    {
        visitor.VisitAssignmentNode(this);
    }
}

public abstract class NodeVisitor
{
    public abstract void VisitVariableRefNode(VariableRefNode node);
    public abstract void VisitAssignmentNode(AssignmentNode node);
}

// 1. 類型檢查
public class TypeCheckingVisitor : NodeVisitor
{
    public override void VisitVariableRefNode(VariableRefNode node)
    {
        Console.WriteLine("類型檢查「變量表達(dá)式」..");
    }

    public override void VisitAssignmentNode(AssignmentNode node)
    {
        Console.WriteLine("類型檢查「賦值表達(dá)式」..");
    }
}

// 2. 格式打印
public class PrettyPrintingVisitor : NodeVisitor
{
    public override void VisitVariableRefNode(VariableRefNode node)
    {
        Console.WriteLine("格式打印「變量表達(dá)式」..");
    }

    public override void VisitAssignmentNode(AssignmentNode node)
    {
        Console.WriteLine("格式打印「賦值表達(dá)式」..");
    }
}

public class App
{
    public static void Main(string[] args)
    {
        // 模擬一個(gè)對(duì)象結(jié)構(gòu)
        Node[] objectStructure = { new VariableRefNode(), new AssignmentNode() };

        // 1. 類型檢查
        objectStructure.Accept(new TypeCheckingVisitor());

        // 2. 格式打印
        objectStructure.Accept(new PrettyPrintingVisitor());
    }
}

public static class NodeExtensions
{
    public static void Accept(this Node[] nodes, NodeVisitor visitor)
    {
        foreach(Node node in nodes)
        {
            node.Accept(visitor);
        }
    }
}

// 控制臺(tái)輸出:
//  類型檢查「變量表達(dá)式」..
//  類型檢查「賦值表達(dá)式」..
//  格式打印「變量表達(dá)式」..
//  格式打印「賦值表達(dá)式」..
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 場(chǎng)景問題# 1.1 擴(kuò)展客戶管理的功能## 考慮這樣一個(gè)應(yīng)用:擴(kuò)展客戶管理的功能。 既然是擴(kuò)展功能,那么肯定是...
    七寸知架構(gòu)閱讀 3,052評(píng)論 1 58
  • 訪問者模式是指封裝某些作用于某種數(shù)據(jù)結(jié)構(gòu)中各元素的操作,它可以在不改變數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作...
    FlyElephant閱讀 628評(píng)論 0 0
  • 前段時(shí)間,看到一個(gè)帖子問:“真正的友誼是什么樣子?” 下面跟了很多帖子。 有的說,友誼就是陪伴。陪著我們笑,陪著我...
    講真書畫閱讀 2,229評(píng)論 3 4
  • 系列教程:玩轉(zhuǎn)微信小程序(一)怎樣將「服務(wù)號(hào)」改造成「小程序」?玩轉(zhuǎn)微信小程序(二)微信小程序項(xiàng)目結(jié)構(gòu)及配置玩轉(zhuǎn)微...
    c14328d5898b閱讀 6,087評(píng)論 1 4
  • 也許注定有緣無分,這段感情之路到此終止,仿佛從一開始就注定了這樣的結(jié)局。但是如果再給我一次選擇的機(jī)會(huì),我也會(huì)選擇對(duì)...
    花文子Flyao閱讀 502評(píng)論 0 2

友情鏈接更多精彩內(nèi)容