定义

  1. 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
  2. 用在 稳定的数据结构 和 易变的操作耦合问题,即 数据结构稳定 算法变化频繁
  3. 访问模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化,这使得算法操作的变化变得更容易,弱点是增加新的数据结构变得困难
  4. 所以在大多数情况下,访问者模式用到的不多也不是首选,因为访问者模式的数据结构稳定,而是只有在确定可以用到访问者模式才使用它。

使用场景

  1. 对象的类很少改变,但对对象结构定义新的操作
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类

代码实现

//访问者抽象类
abstract class Visitor
{
   public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);

   public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}

//具体访问类
class ConcreteVisitor1: Visitor
{
    public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
    }

    public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
    }

}

class ConcreteVisitor2: Visitor
{
    public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);
    }

    public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
    {
        Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);
    }

}


//抽象元素类
abstract class Element
{
    public abstract void Accept(Visitor visitor);
}

//具体元素类
class ConcreteElementA: Element
{
    public override void Accept(Visitor visitor)
    {
        visitor.VisitConcreteElementA(this);
    }
    

    //自身其他方法
    public void OperaionA() { }

}

class ConcreteElementB: Element
{
    public override void Accept(Visitor visitor)
    {
        visitor.VisitConcreteElementB(this);
    }
    

    //自身其他方法
    public void OperaionB() { }

}


//操作类
class ObjectStructure
{
    private IList<Element> elements = new List<Element>();

    public void Attach(Element element)
    {
         elements.Add(element);
    }
    
    public void Detach(Element element)
    {
        elements.Remove(element);
    }
    
    public void Accpet(Visitor visitor)
    {
        foreach (Element e in elements)
        {
            e.Accept(visitor);
        }
    }

}

void Main()
{
        ObjectStructure o = new ObjectStructure();
        o.Attach(new ConcreteElementA());
        o.Attach(new ConcreteElementB());

        ConcreteVisitor1 v1 = new ConcreteVisitor1();
        ConcreteVisitor2 v2 = new ConcreteVisitor2();
    
        o.Accpet(v1);
        o.Accpet(v2);

}

优点缺点

  1. 符合单一职责原则
  2. 优秀的扩展性(算法)
  3. 具体元素对访问者公布细节,违反了迪米特原则
  4. 具体元素变更比较困难
  5. 违反了依赖倒置原则,依赖了具体类,没有依赖抽象