设计模式与实例代码:Visitor模式

定义/意图:Visitor用来表示一组特定元素上的操作,通过Visitors将行为分离出来,当需要在这组元素上增加新的操作时,只需要实现新的Visitor即可。

问题:系统有一组稳定的元素,但针对其的操作在以后会扩展,若元素的类型容易扩展,则不适合用Visit模式

解决方案:把元素和元素上的操作分离,将所有操作的接口抽象出来,

参与者和协作者:Visitor基类声明了针对所有具体元素类上的操作,操作的名称和参数指明了发送给Visitors的具体元素类型,这样Visitors可以在特定的接口中完成对元素的访问处理。Concreate Visitor实现了特定的访问元素的处理操作方法。Element定义了接受Vistor的处理接口。ObjectStruct可能是实现了组合模式的一组对象,以供遍历使用。

效果:在增加操作时可以方便扩展,而不影响已有数据元素

实现:


示例代码:

一个比较理解的现实例子为:1号大院住着两户人家A和B,经常有不同的客人去两家做一些不同的事情,比如1水厂去查水表收水费,2钟点工去两家做家务。

using System;
using System.Collections.Generic;

namespace Visitor
{
    /// <summary>
    /// MainApp startup class for Structural 
    /// Visitor Design Pattern.
    /// </summary>
    class MainApp
    {
        static void Main()
        {
            // Setup structure
            ObjectStructure o = new ObjectStructure();
            o.Attach(new ConcreteElementA());
            o.Attach(new ConcreteElementB());

            // Create visitor objects
            ConcreteVisitor1 v1 = new ConcreteVisitor1();
            ConcreteVisitor2 v2 = new ConcreteVisitor2();

            // Structure accepting visitors
            o.Accept(v1);
            o.Accept(v2);

            // Wait for user
            Console.ReadKey();
        }
    }

    /// <summary>
    /// The 'Visitor' abstract class
    /// </summary>
    abstract class Visitor
    {
        public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
        public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
    }

    /// <summary>
    /// A 'ConcreteVisitor' class
    /// </summary>
    class ConcreteVisitor1 : Visitor
    {
        public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
        {
            Console.WriteLine("{0} visited by {1}",
                concreteElementA.GetType().Name, this.GetType().Name);
        }

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

    /// <summary>
    /// A 'ConcreteVisitor' class
    /// </summary>
    class ConcreteVisitor2 : Visitor
    {
        public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
        {
            Console.WriteLine("{0} visited by {1}",
                concreteElementA.GetType().Name, this.GetType().Name);
        }

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

    /// <summary>
    /// The 'Element' abstract class
    /// </summary>
    abstract class Element
    {
        public abstract void Accept(Visitor visitor);
    }

    /// <summary>
    /// A 'ConcreteElement' class
    /// </summary>
    class ConcreteElementA : Element
    {
        public override void Accept(Visitor visitor)
        {
            visitor.VisitConcreteElementA(this);
        }

        public void OperationA()
        {
        }
    }

    /// <summary>
    /// A 'ConcreteElement' class
    /// </summary>
    class ConcreteElementB : Element
    {
        public override void Accept(Visitor visitor)
        {
            visitor.VisitConcreteElementB(this);
        }

        public void OperationB()
        {
        }
    }

    /// <summary>
    /// The 'ObjectStructure' class
    /// </summary>
    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 (Element element in _elements)
            {
                element.Accept(visitor);
            }
        }
    }
}

 Visitor模式的主要问题是,Visitor中的方法都是面向实现的,当Elements扩展时,整个模式需要大量的修改。为了解决这个问题,对现有Visitor模式其进行了扩展。

  改进一

  增加一层抽象,并利用RTTI在运行时进行类型的转换,从而解决Element类型扩展难的问题。类图如下:

   

   改进二

   在改进一的基础上,采用反射的方式来获得Elements的类型,从而实现扩展。类图如下:

    



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值