访问者模式

意图和简介

意图
使一个高层级的类方便地添加新的方法/操作/接口

  • 扩展性/表达式问题:对于任何一门编程语言而言,添加新子类与添加新方法之间是一个两难的选择(即若选择使一个类易于添加新的操作那么这个类就难以去扩展新的子类,而若这个类容易扩展新的子类,那么就难以去添加新的操作)

何时使用
对于面向对象编程,我们的依赖于抽象原则让我们常常去扩展一个抽象类的子类,而非它的方法。而有时我们会遇到这样一种情况,它的子类是已经确定的了。而它的方法/操作却并非确定的(有很多)。
那么这个时候,我们可以使用访问者模式将其转换为易于扩展新方法而非易于扩展新子类的一个模式。
注:访问者模式并没有解决表达式问题,只是将问题的呈现变换了一种形式

使用的具体思路
    如果一个较高层级的类,它的子类是已知且确定的而操作是未知的,那么我们可以将其操作的具体实现从子类中抽取出来放到访问者类中去实现。而它本身则通过accept方法调用访问者类中相应的visit()方法来实现将表达式问题从易于扩展新的子类难添加新操作转移为易于添加新操作而难以去扩展新子类

可以拿生活中的事情做类比。
这个不知道操作有哪些种类的较高层次的类Receiver,某家的主人,这主人的种类是确定的,同时他们所拥有的房子也是确定的。有天客人Visitor去他家做客,visitor的种类并非是确定的,所以这些客人去某个主人家去说什么话做什么事也就是不知道的。而具体的客人说的具体的话和做的具体的事(即方法/操作)是根据不同的主人,该主人所拥有的房子以及这个visitor具体是谁来确定的(双分派,即具体的操作由主客双方来确定)。



具体示例

这里计算机对普通用户开放的部件ComputerPart作为被访问者(计算机对普通用户开放的部件是确定和已知的)
具体的用户操作作为访问者,操作的种类这里实现了两种,一种display,一种close,(展示和关闭)


1.被访问者,抽象类ComputerPart

public interface ComputerPart
{
   public void accept(ComputerPartVisitor computerPartVisitor);
}



2.被访问者ComputerPart的几个具体子类

public class Keyboard implements ComputerPart
{
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor){
        computerPartVisitor.visit(this);
    }
}


public class Monitor implements ComputerPart
{
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor){
        computerPartVisitor.visit(this);
    }
}


public class Mouse  implements ComputerPart {
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}

public class Computer implements ComputerPart
{
   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);
   }
   
}

3.访问者抽象类

public interface ComputerPartVisitor
{
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
}

4.两种访问者的具体实现类(分别封装了display操作和close操作)

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.");
   }
}

public class ComputerPartCloseVisitor implements ComputerPartVisitor {
 
   @Override
   public void visit(Computer computer) {
      System.out.println("closing Computer.");
   }
 
   @Override
   public void visit(Mouse mouse) {
      System.out.println("closing Mouse.");
   }
 
   @Override
   public void visit(Keyboard keyboard) {
      System.out.println("closing Keyboard.");
   }
 
   @Override
   public void visit(Monitor monitor) {
      System.out.println("closing Monitor.");
   }
}

5.测试类

public class VisitorPatternDemo
{
   public static void main(String[] args) {
 
      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartDisplayVisitor());
      ComputerPart monitor = new Monitor();
      monitor.accept(new ComputerPartDisplayVisitor());
      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartCloseVisitor());
   }
}

综上:操作对具体的计算机部件和操作的种类(display/close)的依赖构成了访问者模式中的职责双分派。这样就得到使用访问者模式的一个场景:在遇到需要对一个类中操作的职责进行双分派的时候,我们可以考虑访问者模式。

你可能感兴趣的:(访问者模式)