zoukankan      html  css  js  c++  java
  • 设计模式之十五:訪问者模式(Visitor Pattern)

    訪问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式。

    据《大话设计模式》中说算是最复杂也是最难以理解的一种模式了。

       定义(源于GoF《Design Pattern》):表示一个作用于某对象结构中的各元素的操作。它使你能够在
    不改变各元素类的前提下定义作用于这些元素的新操作。从定义能够看出结构对象是使用訪问者模式必备
    条件,并且这个结构对象必须存在遍历自身各个对象的方法。这便类似于Java语言其中的collection概念了。
      涉及角色 :
      1.IVisitor 抽象訪问者角色,为该对象结构中详细元素角色声明一个訪问操作接口。该操作接口的名字和
    參数标识了发送訪问请求给具休訪问者的具休元素角色,这样訪问者就能够通过该元素角色的特定接口直接訪问它。

      2.ConcreteVisitor.详细訪问者角色,实现Visitor声明的接口。
      3.Element 定义一个接受訪问操作(accept()),它以一个訪问者(Visitor)作为參数。
      4.ConcreteElement 详细元素,实现了抽象元素(Element)所定义的接受操作接口。

      5.ObjectStructure 结构对象角色,这是使用訪问者模式必备的角色。

    它具备下面特性:

    能枚举它的元素;能够提供一个高层接口以同意訪问者訪问它的元素;如有须要,能够设计成一个
    复合对象或者一个聚集(如一个列表或无序集合)。

      訪问者模式的几个特点:
      訪问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。
      訪问者模式适用于数据结构相对稳定算法又易变化的系统。

    由于訪问者模式使得算法操作添加变得easy。

    若系统数据结构对象易于变化。常常有新的数据对象添加进来,则不适合使用訪问者模式。
      訪问者模式的长处是添加操作非常easy,由于添加操作意味着添加新的訪问者。

    訪问者模式将有关行为集中

    到一个訪问者对象中,其改变不影响系统数据结构。其缺点就是添加新的数据结构非常困难。
      适用情况 :
      1) 一个对象结构包括非常多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其详细类的操作。
      2) 须要对一个对象结构中的对象进行非常多不同的而且不相关的操作。而你想避免让这些操作“污染”这些对象的类。
    Visitor模式使得你能够将相关的操作集中起来 定义在一个类中。

      3) 当该对象结构被非常多应用共享时。用Visitor模式让每一个应用仅包括须要用到的操作。
      4) 定义对象结构的类非常少改变,但常常须要在此结构上定义新的操作。

    改变对象结构类须要重定义对全部訪

    问者的接口,这可能须要非常大的代价。

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

    public class Body {  
        public void accept(IVisitor visitor) {  
            visitor.visit(this);  
        }  
    }  
    public class Engine {  
        public  void accept(IVisitor visitor) {  
                 visitor.visit(this);  
         }  
    }  
    public class Wheel {  
        private String name;  
        public Wheel(String name) {  
            this.name = name;  
        }  
        String getName() {  
            return this.name;  
        }  
        public  void accept(IVisitor visitor) {  
            visitor.visit(this);  
        }  
    }  
    public class Car {  
        private Engine  engine = new Engine();  
        private Body    body   = new Body();  
        private Wheel[] wheels   
            = { new Wheel("front left"), new Wheel("front right"),  
                new Wheel("back left") , new Wheel("back right")  };  
        public void accept(IVisitor visitor) {  
            visitor.visit(this);  
            engine.accept(visitor);  
            body.accept(visitor) ;   
            for (int i = 0; i < wheels.length; ++ i)  
                wheels[i].accept(visitor);  
        }  
    }    

    public interface IVisitor {  
        void visit(Wheel wheel);  
        void visit(Engine engine);  
        void visit(Body body);  
        void visit(Car car);  
    }    
        
    public class PrintVisitor implements IVisitor {   
        @Override  
        public void visit(Wheel wheel) {  
            System.out.println("Visiting " + wheel.getName() + " wheel");   
        }    
        @Override  
        public void visit(Engine engine) {  
            System.out.println("Visiting engine");  
        }    
        @Override  
        public void visit(Body body) {  
            System.out.println("Visiting body");  
        }    
        @Override  
        public void visit(Car car) {  
            System.out.println("Visiting car");  
        }   

    ------------------------样例2-----------------------

    Visitor模式,在不改动已有程序结构的前提下,通过加入额外的“訪问者”来完毕对已有代码功能的提升。Visitor模式的组成结构:

      1) 訪问者角色(Visitor):声明一个訪问接口。

    接口的名称和方法的參数标识了向訪问者发送请求的元素角色。这样訪问者就能够通过该元素角色的特定接口直接訪问它。

      2) 详细訪问者角色(Concrete Visitor):实现訪问者角色(Visitor)接口

      3) 元素角色(Element):定义一个Accept操作,它以一个訪问者为參数。
      4) 详细元素角色(Concrete Element):实现元素角色(Element)接口。
      5) 对象结构角色(Object Structure):这是使用Visitor模式必须的角色。它要具备下面特征:能枚举它的元素;能够提供一个高层的接口同意訪问者角色訪问它的元素;能够是一个组合(组合模式)或是一个集合,如一个列表或一个无序集合
    public abstract class Customer {
    private String customerId;
    private String name;

    public String getCustomerId() {
        return customerId;
    }
    public void setCustomerId(String customerId) {
       this.customerId = customerId;
    }
    public String getName() {
       return name;
    }
    public void setName(String name) {
       this.name = name;
    }

    //接受訪问者的訪问
    public abstract void accept(Visitor visitor);

    //企业客户
    public class EnterpriseCustomer extends Customer {
     private String linkman;
     private String linkTelephone;
     private String registerAddress;
     public String getLinkman() {
        return linkman;
     }

     public void setLinkman(String linkman) {
      this.linkman = linkman;
     }

     public String getLinkTelephone() {
     return linkTelephone;
     }

     public void setLinkTelephone(String linkTelephone) {
     this.linkTelephone = linkTelephone;
     }

     public String getRegisterAddress() {
     return registerAddress;
     }

     public void setRegisterAddress(String registerAddress) {
    this.registerAddress = registerAddress;
     }

     @Override
     public void accept(Visitor visitor) {
     //回调訪问者对象的方法
             visitor.visitEnterpriseCustomer(this);
      }
    }

    //个人客户
    public class PersonalCustomer extends Customer {
     private String telephone;
     private int age;
     public String getTelephone() {
          return telephone;
     }

     public void setTelephone(String telephone) {
             this.telephone = telephone;
     }

     public int getAge() {
           return age;
     }
     public void setAge(int age) {
              this.age = age;
     }

     @Override
     public void accept(Visitor visitor) {
         //回调訪问者对象的方法
         visitor.visitPersonalCustomer(this);
         }
    }

    /**
     * 訪问者接口
     */
    public interface Visitor {
        // 訪问企业客户。相当于给企业客户加入訪问者功能
        public void visitEnterpriseCustomer(EnterpriseCustomer ec);
        //訪问个人客户,相当于给个人客户加入訪问者的功能
        public void visitPersonalCustomer(PersonalCustomer pc);
    }

    /**
     * 详细的訪问者。实现对客户的偏好分析
     */
    public class PredilectionAnalyzeVisitor implements Visitor {
      @Override
      public void visitEnterpriseCustomer(EnterpriseCustomer ec) {
      // TODO 依据以往的购买历史、潜在购买意向,以及客户所在行业的发展趋势、客户的发展趋势等的分析
                    System.out.println("如今对企业客户" + ec.getName() + "进行产品偏好分析");
      }

      @Override
      public void visitPersonalCustomer(PersonalCustomer pc) {
                 System.out.println("如今对个人客户" + pc.getName() + "进行产品偏好分析");
      }
    }

    /**
     * 详细的訪问者,实现客户提出服务请求的功能
     */
    public class ServiceRequestVisitor implements Visitor {
      @Override
    public void visitEnterpriseCustomer(EnterpriseCustomer ec) {
            // TODO 企业客户提出的详细服务请求
             System.out.println(ec.getName() + "企业提出服务请求");
    }

    @Override
    public void visitPersonalCustomer(PersonalCustomer pc) {
           // TODO 个人客户提出的详细服务请求
          System.out.println("客户" + pc.getName() + "提出服务请求");
         }
    }

    public class ObjectStructure {
     /**
      * 要操作的客户集合
      */
     private Collection<Customer> col = new ArrayList<Customer>();
     /**
      * 提供client操作的高层接口,详细的功能由client传入的訪问者决定
      * @param visitor client须要的訪问者
      */
     public void handleRequest(Visitor visitor) {
             for(Customer cm : col) {
                  cm.accept(visitor);
            }
     }

     /**
      * 组建对象结构,想对象中加入元素
      * 不同的对象结构有不同的构建方式
      * @param ele 增加到对象的结构元素
      */
     public void addElement(Customer ele) {
              this.col.add(ele);
         }
    }

    public class Client {
     public static void main(String[] args) {
    ObjectStructure os = new ObjectStructure();
    Customer cml = new EnterpriseCustomer();
    cml.setName("钢铁侠");
    os.addElement(cml);

    Customer cm2 = new EnterpriseCustomer();
    cm2.setName("CDE公司");
    os.addElement(cm2);

    Customer cm3 = new PersonalCustomer();
    cm3.setName("美国佬");
    os.addElement(cm3);

    ServiceRequestVisitor srVisitor = new ServiceRequestVisitor();
    os.handleRequest(srVisitor);

    PredilectionAnalyzeVisitor paVisitor = new PredilectionAnalyzeVisitor();
    os.handleRequest(paVisitor);

      WorthAnalyzeVisitor waVisitor = new WorthAnalyzeVisitor();
      os.handleRequest(waVisitor);
      }
    }

  • 相关阅读:
    六大关系整理
    pthread_create多线程执行顺序诡异现象
    WinForm中 事件 委托 多线程的应用
    伪ajax上传文件
    Webx小应用的实现整理与分析
    IL反编译的实用工具
    MVC4+WebApi+Redis Session共享练习(上)
    虚拟化平台cloudstack新版本的调试
    【c++】指针参数是如何传递内存的
    NPinyin 中文转换拼音代码
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6718309.html
Copyright © 2011-2022 走看看