【鲁班学院】设计模式—访问者(Visitor)模式

1、定义


访问者模式是一种从操做的对象结构中分离算法的方式。 它能够在不改变数据结构的前提下定义做用与这些元素的新操做。它遵循开闭原则。html

> Represent an operation to be performed on elements of an object
> structure. Visitor lets you define a new operation without changing
> the classes of the elements on which it operatesjava

.visitor: n. 访问者,参观者;视察者.算法

 

2、涉及角色


1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操做接口。该操做接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就能够经过该元素角色的特定接口直接访问它。设计模式

2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口。
3.Element 定义一个接受访问操做(accept()),它以一个访问者(Visitor)做为参数。数据结构

4.ConcreteElement具体元素,实现了抽象元素(Element)所定义的接受操做接口。
5.ObjectStructure结构对象角色,这是使用访问者模式必备的角色。它具有如下特性:能枚举它的元素;能够提供一个高层接口以容许访问者访问它的元素;若有须要,能够设计成一个复合对象或者一个汇集(如一个列表或无序集合)ide

 

3、通俗理解


1.我做为一个访客(Visitor)到朋友家(Element)拜访,朋友之间喝喝酒,聊聊天,再互相吹捧。聊天的时候,朋友告诉我他今年的表现(doSomthing),而后我就作(visit-self-method)一些对这件事的评价。学习

2.老板做为视察者,查阅(访问)手下员工的工做业绩。老板是Visitor的抽象实现,员工是Element的抽象实现。对象结构(Object Structure)为员工的业绩等信息this

3.家里有一台电脑,电脑出现了一点问题,那么我做为访问者,想去了解电脑的那个部分出了问题。我Visitor,电脑的各个部分(Element),查看有没有坏(visit method)
应该有不少相似的比喻,在开发的过程当中多去思考,作什么事情都要思考。spa

 

 4、实现细节


1.定义一个表示Element的接口.net

2.实现Element接口。建立Element的实体类ConcreteElement

3.建立一个表示访问者Visitor的接口实现

4.Visitor的接口,建立Visitor实体类ConcreteVisitor,(有时候会有多个访问者)

5.使用Visitor实体类来访问Element。

 

五 、特性


优势:1.符合单一职责原则

2.元素类能够经过接受不一样的访问者来实现对不一样操做的扩展。

缺点:1.具体元素对访问者公布细节,违背了迪米特法则。

2.违背了依赖倒置原则,访问者依赖的是具体元素,而不是抽象元素。

 

适用场景
1.对象结构中对象对应的类不多改变,但常常须要在此对象结构上定义新的操做。

2.须要对一个对象结构中的对象进行不少不一样的而且不相关的操做,而须要避免让这些操做"污染"这些对象的类,也不但愿在增长新操做时修改这些类。

注意事项:访问者能够对功能进行统一,能够作报表、UI、拦截器与过滤器。

 六 、案例


案例一


类图

咱们去检查汽车的各个部分是否能正常打印,使用Visitor根据不一样的汽车部分来分发动做。 而不是在汽车的各个部分来打印。interface 

    CarElement {
        void accept(CarElementVisitor visitor);
    }
       interface CarElementVisitor {
           void visit(Body body);
           void visit(Car car);  
           void visit(Engine engine);   
           void visit(Wheel wheel);
     }

     class Car implements CarElement { 
          CarElement[] elements;  

         public Car() {
           this.elements = new CarElement[] {       
              new Wheel("front left"), new Wheel("front right"),      
              new Wheel("back left"), new Wheel("back right"),           
              new Body(), new Engine()    
            };   
         }   

     public void accept(final CarElementVisitor visitor) {      
         for (CarElement elem : elements) {        
             elem.accept(visitor);      
          }        
          visitor.visit(this);  
        }
     }

      class Body implements CarElement {  
        public void accept(final CarElementVisitor visitor) {                                            
            visitor.visit(this);
         }
       }
       
       class Engine implements CarElement { 
          public void accept(final CarElementVisitor visitor) {                         
                    visitor.visit(this);   
           }
     }
       
        class Wheel implements CarElement {
            private String name; 

             public Wheel(final String name) { 
                    this.name = name;
              } 

             public String getName() {     
                   return name;
            }    

      public void accept(final CarElementVisitor visitor) {    
          /*     
           * accept(CarElementVisitor) in Wheel implements     
           * accept(CarElementVisitor) in CarElement, so the call        
           * to accept is bound at run time. This can be considered        
           * the *first* dispatch. However, the decision to call        
           * visit(Wheel) (as opposed to visit(Engine) etc.) can be       
           * made during compile time since 'this' is known at compile        
           * time to be a Wheel. Moreover, each implementation of        
           * CarElementVisitor implements the visit(Wheel), which is       
           * another decision that is made at run time. This can be        
           * considered the *second* dispatch.         
           */       
            visitor.visit(this);   
         }
     }

    class CarElementDoVisitor implements CarElementVisitor {           
          public void visit(final Body body) {      
               System.out.println("Moving my body");    
           }   
        public void visit(final Car car) {    
           System.out.println("Starting my car");   
         }    

        public void visit(final Wheel wheel) {     
           System.out.println("Kicking my " + wheel.getName() + " wheel");                 
       }    
       
           public void visit(final Engine engine) {                       
           System.out.println("Starting my engine");  
        }
     }

    class CarElementPrintVisitor implements CarElementVisitor {   
         public void visit(final Body body) {                    
              System.out.println("Visiting body");
          }    

     public void visit(final Car car) {                    
          System.out.println("Visiting car");
      }  
      
      public void visit(final Engine engine) {        
           System.out.println("Visiting engine"); 
         }   

      public void visit(final Wheel wheel) {        System.out.println("Visiting " + wheel.getName() + " wheel");  
        }
    }

    public class VisitorDemo { 
       public static void main(final String[] args) {        
             final Car car = new Car();   
     
     car.accept(new CarElementPrintVisitor());            
     car.accept(new CarElementDoVisitor());  
       }
    }

/* 输出内容
Visiting front left wheel
Visiting front right wheel
Visiting back left wheel
Visiting back right wheel
Visiting bodyVisiting engine
Visiting carKicking my front left wheel
Kicking my front right wheel
Kicking my back left whee
lKicking my back right wheel
Moving my body
Starting my engine
Starting my car
*/

案例二

类图

本质上和案例一没什么差异

    // ComputerPart.java
    public interface ComputerPart {
      public void accept(ComputerPartVisitor computerPartVisitor);
     }
    
    // Keyboard.java
    public class Keyboard  implements ComputerPart { 
    
       @Override   
       public void accept(ComputerPartVisitor computerPartVisitor) {                   
            computerPartVisitor.visit(this); 
         }
     }
    
    // Monitor.java
    public class Monitor  implements ComputerPart {       
         
         @Override  
        public void accept(ComputerPartVisitor computerPartVisitor) {                 
           computerPartVisitor.visit(this);  
          }
       }
      
      // Mouse.java
      public class Mouse  implements ComputerPart {  
          @Override   
          public void accept(ComputerPartVisitor computerPartVisitor) {                
              computerPartVisitor.visit(this); 
            }
        }
    
    // Computer.java
    public class Computer implementsComputerPart {  
    
         ComputerPart[] parts;  
    
         public Computer(){   
            parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};     
             }   
    
    
     @Override
      public void accept(ComputerPartVisitor computerPartVisitor) { 
           for (int i = 0; i < parts.length; i++) {          
                parts[i].accept(computerPartVisitor);  
               }   
               computerPartVisitor.visit(this); 
            }
         }
    
    // ComputerPartVisitor
    public interface ComputerPartVisitor {   
         public void visit(Computer computer);
         public void visit(Mouse mouse); 
         public void visit(Keyboard keyboard);
         public void visit(Monitor monitor);
      }
    
    // ComputerPartDisplayVisitor.java
    public class ComputerPartDisplayVisitor implements ComputerPartVisitor {  
    
        @Override 
       public void visit(Computer computer) {          
            System.out.println("Displaying Computer."); 
         }   
    
        @Override
        public void visit(Mouse mouse) {                      
           System.out.println("Displaying Mouse.");
           }  
    
       @Override 
       public void visit(Keyboard keyboard) {          
             System.out.println("Displaying Keyboard."); 
         }  
    
        @Override   
        public void visit(Monitor monitor) {      
            System.out.println("Displaying Monitor."); 
         }
      }
    
    // demo
    public class VisitorPatternDemo {
       public static void main(String[] args) {      
    
        ComputerPart computer = new Computer();          
        computer.accept(newComputerPartDisplayVisitor());   
      }
    }

/* 输出
Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.
*/

 小结

主要记录了在学习设计模式时的一些资料,对资料进行了整理。想要深刻理解设计模式,还要多读优秀的代码,在开发的时候多去思考相关的应用场景。 附录 访问者模式—百度百科:https://0x9.me/HXKTA(短网址) 访问者模式—维基百科:https://en.wikipedia.org/wiki/Visitor_pattern 访问者模式—菜鸟教程:http://www.runoob.com/design-pattern/visitor-pattern.html

相关文章
相关标签/搜索