访问者模式(Visitor Pattern)

本文介绍访问者模式的应用场景及其实现方式,适用于需要为对象结构定义新操作而不修改原有类的情况。文中详细解释了访问者模式的角色分工,并通过示例代码展示了如何实现这一设计模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        我们需要扩展生成的行为与现有的对象模型并不一致,或者不修改层次结构中的类,就无法扩展层次结构的行为,这时可以使用访问者模式为对这个层次结构进行扩展提供支持。访问者模式的目的在于不改变一个层次结构中的类的情况下,我们可以为一个层次结构定义定义一个新的操作,扩展过程中无需访问原有的代码。

        目的为了表示一个作用于某个对象结构中的各元素的操作,可以在不改变各元素的类的前提下定义作用于这些元素的新操作.(GOF)

        使用访问者模式,必须定义两个类层次结构,一个对应于接受操作的元素类,另一个对应于定义对元素的操作的访问者类。给访问者类层次增加一个新的子类即可以创建一个新的操作。为所有类都增加一个Accept操作;创建一个接口,所有操作均被该接口定义。访问者模式不要求层次结构的所有类都实现一个Accept()方法,但是如果某个类实现了Accept()方法,那么这个为会作为Visitor()方法的一个参数,而Accept()方法由访问者的接口定义。

        适用性:

        1 .一个对象结构内部包含很多实现了不同接口的类对象,你想对这些对象执行依赖于其具体类的操作。

        2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。访问者模式使得你可以将相关的操作集中起来定义在一个类中,当该对象结构被很多应用共享时,用访问者模式让每个应用仅包含需要用到的操作。

        3.定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

        参与者:

        1. 抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体访问者角色必须实现的接口。 具体为该对象结构中的ConcreteElement的每一个类声明一个Visit操作,该操作的名字和特征标示了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问这就可以通过该元素的特定接口直接访问它。

        2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。 具体为实现每个由Visitor声明的操作,每个操作实现本算法的一部分,而该算法片断乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储他的局部状态。这一个状态常常在遍历该结构的过程中累积信息。

         3.抽象元素(Element)角色: 声明一个Accept操作,该操作接受一个访问者对象作为参数。

        4. 具体元素(ConcreteElement)角色:实现抽象元素角色所规定的Accept操作。

        5. 结构对象(ObiectStructure)角色:提供一个方法可以遍历结构中的所有元素,或者可以设计成一个复合对象或者一个聚集。 

        访问者模式是一个有争议的模式,因为可能在设计过程中陷入过程流中的无限循环,也可能为层次结构中加入危险的依赖关系,当层次关系结构发生变化时,会导致这种依赖无效.与其他设计模式一样,该模式也不是一种必须使用的模式,通常可以找到一种更可靠的模式作为其替代方案,除非别无选择.

        示例代码:

using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  VisitorPattern
{
    
public abstract class AbstractVisitor
    
{
        
public abstract void Visit(AbstractElement abstractElement);
    }


    
public abstract class AbstractElement
    
{
        
public abstract void Accept(AbstractVisitor abstractVisitor);
    }


    
public class ConcreteElement : AbstractElement
    
{

        
public override void Accept(AbstractVisitor abstractVisitor)
        
{
            abstractVisitor.Visit(
this);
        }

    }


    
public class ConcreteVisitor : AbstractVisitor
    
{
        
public override void Visit(AbstractElement abstractElement)
        
{
            Console.WriteLine(
"访问操作!");
        }

    }


    
public class ObjectStructure
    
{
        
private IList<AbstractElement> elements = new List<AbstractElement>();

        
/// <summary>
        
/// 添加一个对象
        
/// </summary>
        
/// <param name="abstractElement"></param>

        public void Attach(AbstractElement abstractElement)
        
{
            elements.Add(abstractElement);
        }


        
/// <summary>
        
/// 移除一个对象
        
/// </summary>
        
/// <param name="abstractElement"></param>

        public void Detach(AbstractElement abstractElement)
        
{
            elements.Remove(abstractElement);
        }


        
/// <summary>
        
/// 行集合内所有对象的Accept()方法
        
/// </summary>
        
/// <param name="abstractVisitor"></param>

        public void Accept(AbstractVisitor abstractVisitor)
        
{
            
foreach (AbstractElement abstractElement in elements)
            
{
                abstractElement.Accept(abstractVisitor);
            }

        }

    }


    
class Program
    
{
        
static void Main(string[] args)
        
{
            ObjectStructure o 
= new ObjectStructure();
            o.Attach(
new ConcreteElement());
            ConcreteVisitor v 
= new ConcreteVisitor();
            o.Accept(v);

            Console.ReadLine();
        }

    }

}

 


[1] http://tianli.blog.51cto.com/190322/45702
[2] http://www.cnblogs.com/singlepine/archive/2005/10/30/265025.html 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值