【地铁上的设计模式】--行为型模式:访问者模式

2023-05-14 09:04:54 浏览数 (1)

什么是访问者模式

访问者模式(Visitor Pattern)是一种行为型设计模式,它能够将算法与数据结构分离,使得算法可以独立于数据结构进行变化。它在不改变数据结构的前提下,定义了作用于数据结构中各个元素的新操作,即“访问者”,使得新增操作更加简单。访问者模式中,数据结构和操作是分开的,因此当需要新增一种操作时,只需增加相应的访问者即可,无需修改数据结构的代码,从而降低了系统的耦合度。 在访问者模式中,数据结构中的每个元素都有一个accept方法,它接收一个访问者作为参数,从而实现访问者对该元素的操作。访问者模式的核心思想就是“双重分派”,即先根据被访问者的类型来选择合适的访问者,再根据访问者的类型来调用合适的访问方法。 优点: 1.访问者模式能够在不改变原有数据结构的前提下,增加新的操作。 2.访问者模式将数据结构与操作分离,增加新的操作时,不会影响其他的操作。 3.访问者模式符合开闭原则。

缺点: 1.访问者模式增加了系统的复杂度,增加了新的类和接口。 2.访问者模式增加了代码量,需要实现访问者和被访问者的接口和方法。

Tip:访问者模式适用于数据结构相对稳定,但需要经常增加新的操作的场合,例如编译器、解释器、静态分析器等。

如何实现访问者模式

访问者模式的实现步骤如下:

  1. 定义抽象访问者(Visitor)接口:包含多个访问具体元素的方法,每个方法的参数都是不同的具体元素。
  2. 定义抽象元素(Element)接口:定义一个接受访问者的抽象方法,该方法接受一个访问者作为参数。
  3. 定义具体元素(ConcreteElement)类:实现抽象元素接口,并实现接受访问者方法,将自身作为参传递给访问者的方法。
  4. 定义对象结构(Object Structure)类:包含多个具体元素对象,提供遍历元素的方法。
  5. 定义具体访问者(ConcreteVisitor)类:实现抽象访问者接口中的所有方法,对不同的具体元素对象进行不同的操作。
  6. 客户端通过调用对象结构的遍历方法来启动访问者模式。遍历过程中,对每个具体元素对象都会调用它们各自的接受访问者方法,将访问者对象传入,并在具体元素对象内部调用访问者对象的方法。

Tip:上述步骤中并未包含具体实现细节,例如具体元素的属性、具体访问者对元素的操作等。具体实现应根据实际需求进行设计。

Java如何实现 以下是 Java 中访问者模式的实现示例:

首先,定义被访问的对象接口 Element,其中声明 accept() 方法用于接受访问者的访问:

代码语言:javascript复制
public interface Element {
    void accept(Visitor visitor);
}

接着,定义具体的被访问者对象 ConcreteElementAConcreteElementB,实现 Element 接口,并实现 accept() 方法:

代码语言:javascript复制
public class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitConcreteElementA(this);
    }
}

public class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitConcreteElementB(this);
    }
}

然后,定义访问者接口 Visitor,其中声明了若干个 visitConcreteElementX() 方法,用于访问具体的被访问者对象:

代码语言:javascript复制
public interface Visitor {
    void visitConcreteElementA(ConcreteElementA elementA);
    void visitConcreteElementB(ConcreteElementB elementB);
}

最后,定义具体的访问者对象 ConcreteVisitor,实现 Visitor 接口,并实现 visitConcreteElementX() 方法:

代码语言:javascript复制
public class ConcreteVisitor implements Visitor {
    @Override
    public void visitConcreteElementA(ConcreteElementA elementA) {
        System.out.println("访问者访问具体元素A:"   elementA.getClass().getSimpleName());
    }

    @Override
    public void visitConcreteElementB(ConcreteElementB elementB) {
        System.out.println("访问者访问具体元素B:"   elementB.getClass().getSimpleName());
    }
}

在使用时,需要将访问者对象传递给被访问者对象的 accept() 方法:

代码语言:javascript复制
Element element = new ConcreteElementA();
Visitor visitor = new ConcreteVisitor();
element.accept(visitor);

执行结果为:

代码语言:javascript复制
访问者访问具体元素A:ConcreteElementA

C#如何实现 以下是C#中访问者模式的示例代码:

代码语言:javascript复制
using System;
using System.Collections.Generic;

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

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

    public void OperationA()
    {
        Console.WriteLine("ConcreteElementA.OperationA() is called.");
    }
}

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

    public void OperationB()
    {
        Console.WriteLine("ConcreteElementB.OperationB() is called.");
    }
}

// 抽象访问者类
abstract class Visitor
{
    public abstract void Visit(ConcreteElementA elementA);
    public abstract void Visit(ConcreteElementB elementB);
}

// 具体访问者类 1
class ConcreteVisitor1 : Visitor
{
    public override void Visit(ConcreteElementA elementA)
    {
        Console.WriteLine("ConcreteVisitor1 is visiting ConcreteElementA.");
        elementA.OperationA();
    }

    public override void Visit(ConcreteElementB elementB)
    {
        Console.WriteLine("ConcreteVisitor1 is visiting ConcreteElementB.");
        elementB.OperationB();
    }
}

// 具体访问者类 2
class ConcreteVisitor2 : Visitor
{
    public override void Visit(ConcreteElementA elementA)
    {
        Console.WriteLine("ConcreteVisitor2 is visiting ConcreteElementA.");
        elementA.OperationA();
    }

    public override void Visit(ConcreteElementB elementB)
    {
        Console.WriteLine("ConcreteVisitor2 is visiting ConcreteElementB.");
        elementB.OperationB();
    }
}

// 对象结构类
class ObjectStructure
{
    private List<Element> elements = new List<Element>();

    public void Attach(Element element)
    {
        elements.Add(element);
    }

    public void Detach(Element element)
    {
        elements.Remove(element);
    }

    public void Accept(Visitor visitor)
    {
        foreach (var element in elements)
        {
            element.Accept(visitor);
        }
    }
}

// 测试代码
class Program
{
    static void Main(string[] args)
    {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.Attach(new ConcreteElementA());
        objectStructure.Attach(new ConcreteElementB());

        ConcreteVisitor1 visitor1 = new ConcreteVisitor1();
        ConcreteVisitor2 visitor2 = new ConcreteVisitor2();

        objectStructure.Accept(visitor1);
        objectStructure.Accept(visitor2);

        Console.ReadLine();
    }
}

代码中有一个抽象元素类和两个具体元素类,一个抽象访问者类和两个具体访问者类,还有一个对象结构类来管理元素,执行访问者的访问方法。在主函数中,我们将具体的访问者传递给对象结构,以便它可以遍历所有元素并调用访问者的方法。

总结

访问者模式是一种行为型设计模式,它允许你在不修改对象结构的情况下定义新的操作。该模式将算法与元素结构分离开来,并将这些算法封装到访问者对象中,从而使得元素可以在不同的访问者之间变化。访问者模式的优点在于可以将操作添加到对象结构中,同时保持其封装性和单一职责原则。但是,访问者模式的缺点在于会增加系统的复杂性,并且不易于添加新的元素类型。

0 人点赞