zoukankan      html  css  js  c++  java
  • 设计模式学习笔记访问者模式

    概述:                                                                                                       

    访问者模式(Visitor),表示作用于某对象结构中的各元素的操作。

    它使你可以在不改变各元素的类的前提下定义作用于这些元素新的操作。

    适用场合:                                                                                                 

    1.一个对象结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。

    2.需要对一个对象中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作‘污染’这些对象的类。

       visitor使得你可以将相关的操作集中起来定义在一个类中。

       当该对象结构被很多应用共享时,使用Visitor模式让每个应用包含需要用到的操作。

    3.定义对象结构类很少改变,但经常需要在此结构上定义新的操作。

       改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。

       如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

    类图:                                                                                                       

    代码示例:                                                                                                  

    1.访问者抽象类

        /// <summary>
    /// 为该对象结构中ConcreteElement的每一个类声明一个Visit操作
    /// </summary>
    abstract class Visitor
    {
    public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);

    public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
    }

    2.实现访问者类

        /// <summary>
    /// 具体访问者,实现Visitor的操作,每个操作实现算法的一部分,该算法乃是对应
    /// 于结构中对象的类
    /// </summary>
    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);
    }
    }

    3. 定义Element,它以一个访问者为参数

        /// <summary>
    /// 定义一个Accept操作,它以一个访问者为参数
    /// </summary>
    abstract class Element
    {
    public abstract void Accept(Visitor visitor);
    }

    4.实现Accept操作

        /// <summary>
    /// 具体元素,实现Accept操作
    /// </summary>
    class ConcreteElementA:Element
    {
    /// <summary>
    /// 充分利用双分派技术,实现处理与数据结构的分离
    /// </summary>
    /// <param name="visitor"></param>
    public override void Accept(Visitor visitor)
    {
    visitor.VisitConcreteElementA(
    this);
    }
    /// <summary>
    /// 其他的相关方法
    /// </summary>
    public void OperationA()
    {
    }
    }
    class ConcreteElementB:Element
    {
    public override void Accept(Visitor visitor)
    {
    visitor.VisitConcreteElementB(
    this);
    }
    public void OperationB() { }
    }

    5.定义一个高层接口

        /// <summary>
    /// 提供一个高层接口允许访问者访问它的元素
    /// </summary>
    class ObjectStructure
    {
    private IList<Element> elements = new List<Element>();

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

    6.客户端调用

            /// <summary>
    /// 测试访问者模式
    /// </summary>
    static void TestVisitor()
    {
    ObjectStructure o
    = new ObjectStructure();
    o.Attach(
    new ConcreteElementA());
    o.Attach(
    new ConcreteElementB());

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

    Console.Read();
    }

    小结:                                                                                                       

    访问者模式有点复杂,而且应用场合很少,具体应用需要将实际情况合理抽象,需要多种设计模式配合工作。

  • 相关阅读:
    java学习之—栈
    java中的a++与++a的区别
    java学习之—数组的曾删改查
    Mybatis #{ } 和 ${ } 区别
    详解Windows不重启使环境变量修改生效(经典)
    laravel artisan常用命令
    Laravel 出现 No application encryption key has been specified.
    springboot的几种启动方式
    Angular 服务的简单使用
    Angular-1.6 路由 简单使用
  • 原文地址:https://www.cnblogs.com/jqbird/p/2171115.html
Copyright © 2011-2022 走看看