访问者模式

简介: 访问者模式

假设有男人和女人两种元素,要分别打印出他们在不同状态时的不同表现。



用OO的思想把表现(行为)提取出来作为一个抽象方法,代码如下:



用if-else对状态进行判断

Person接口



public interface Person {

     public void action(String state);

}


Man实现类





Java代码  

public class Man implements Person{

public void action(String state) {

 if(state == "success"){

  System.out.println("当男人成功时,背后多半有一个伟大的女人");

 }

 else if(state == "love"){

  System.out.println("当男人恋爱时,凡事不懂也装懂");

 }

}  

}

Woman实现类



Java代码  


public class Woman implements Person{

public void action(String state) {

 if(state == "success"){

  System.out.println("当女人成功时,背后大多有一个不成功的男人");

 }

 else if(state == "love"){

  System.out.println("当女人恋爱时,遇事懂也装不懂");

 }

}

}

客户端测试代码




Java代码  



public class Client {

    public static void main(String[] args) {

 Person man = new Man();

 Person woman = new Woman();

 man.action("success");

 woman.action("success");

 

 man.action("love");

 woman.action("love");

}

}

结果显示:

当男人成功时,背后多半有一个伟大的女人

当女人成功时,背后大多有一个不成功的男人

当男人恋爱时,凡事不懂也装懂

当女人恋爱时,遇事懂也装不懂



当需求发生变化时,要增加一种失败状态时,增加男人女人的不同表现,这时就要修改Man类与Woman类的if else,违反了ocp原则(对增加开放-对修改封闭)。而且随着需求的增加,Man类与Woman类的if,else越来越臃肿,需要取消时,又要去修改if,else,既不方便,又容易出错。

这时候访问者模式可以派上用场了。

请看下面经修改后的类图:

2.png




使用访问者模式


把状态抽象出来成为一个接口(访问者),不同的状态就作为状态的不同实现类(不同的访问者)。

状态的接口(访问者接口)



public interface Visitor {

     public void visit(Man man);

     public void visit(Woman woman);

}

具体访问者实现类(分别代表不同的状态)





Java代码  

//成功时Man与Woman的不同表现

public class Success implements Visitor{

public void visit(Man man) {

 System.out.println("当男人成功时,背后多半有一个伟大的女人");

}

public void visit(Woman woman) {

 System.out.println("当女人成功时,背后大多有一个不成功的男人");

}

}

public class Love implements Visitor{

public void visit(Man man) {

 System.out.println("当男人恋爱时,凡事不懂也装懂");

}

public void visit(Woman woman) {

 System.out.println("当女人恋爱时,遇事懂也装不懂");

}

}

按照类图改造一下人的接口与实现类


Java代码  

public interface Person {

     void accept(Visitor visitor);

}

public class Man implements Person{

public void accept(Visitor visitor) {

 visitor.visit(this);

}

}

public class Woman implements Person{

public void accept(Visitor visitor) {

         visitor.visit(this);

}

}


这时Man与Woman变得轻盈多了,不再需要写一大段的if,else,只需要按不同的状态,传入不同的访问者,执行访问者的方法就OK了。



为了更好地实现客户类与具体元素的解耦,加入一个ObjectStructure类。有了ObjectStructure能更方便地执行一些任何,其具体细节对于客户端来说是透明的。




import java.util.*;

public class ObjectStructure {

   private List<Person> elements = new ArrayList<Person>();

   public void attach(Person element){

    elements.add(element);

   }

 

   public void detach(Person element){

    elements.remove(elements);

   }

 

   //遍历各种具体元素并执行他们的accept方法

   public void display(Visitor visitor){

    for(Person p:elements){

     p.accept(visitor);

    }

   }

}


客户端测试代码:





Java代码  

public class Client {

     public static void main(String[] args) {

 ObjectStructure o = new ObjectStructure();  //依赖于ObjectStructure

 //实例化具体元素

 o.attach(new Man());  

 o.attach(new Woman());

 

 //当成功时不同元素的不同反映

 Visitor success = new Success();           //依赖于抽象的Visitor接口

 o.display(success);

 

 //当恋爱时的不同反映

 Visitor amativeness = new Love();          //依赖于抽象的Visitor接口

 o.display(amativeness);

}

}

这时客户端只依赖于ObjectStructure类与Visitor接口,实现了高度的解耦,具体Visitor实现类的实例化与具体元素(Man,Woman)的创建可以通过工厂模式甚至配合properties/xml配置文件创建,无需客户端关注。而Man与Gril的创建的代码也可以放在其他地方,客户端无需知道,如可以放到ObjectStructure的构造函数中完成




public ObjectStructure(){

 attach(new Man());  

 attach(new Woman());

}


在实例块{ }中完成实例化也可以。这时如果要增加一种状态的不同操作,只需要增加一个具体访问者,无需要修改具体元素类Man与Woman。代码如下,





Java代码  

public class Fail implements Visitor{

public void visit(Man man) {

 System.out.println("当男人失败时,闷头喝酒,谁也不用劝");

}

public void visit(Woman woman) {

 System.out.println("当女人失败时,眼泪汪汪,谁也劝不了");

}

}

修改一下客户端测试代码就OK:



Java代码  


public class Client {
      public static void main(String[] args) {
  ObjectStructure o = new ObjectStructure();  //依赖于ObjectStructure
  //实例化具体元素
  o.attach(new Man());  
  o.attach(new Woman());
  //当成功时不同元素的不同反映
  Visitor success = new Success();           //依赖于抽象的Visitor接口
  o.display(success);
  //当恋爱时的不同反映
  Visitor amativeness = new Love();          //依赖于抽象的Visitor接口
  o.display(amativeness);
  //当失败时的不同反映
  Visitor fail = new Fail();
  o.display(fail);
  }
}


结果显示:

当男人成功时,背后多半有一个伟大的女人

当女人成功时,背后大多有一个不成功的男人

当男人恋爱时,凡事不懂也装懂

当女人恋爱时,遇事懂也装不懂

当男人失败时,闷头喝酒,谁也不用劝

当女人失败时,眼泪汪汪,谁也劝不了




现在来让我们看看访问者模式的定义与类图:

访问者模式定义:表示一个作用于某个对象结构中的各元素的操作。它使可以在不改变各元素的类的前提下定义作用于这些元素的新操作。


访问者模式的特点:

1)优点:使用了访问者模式以后,对于原来的类层次增加新的操作,仅仅需要实现一个具体访问者角色就可以了,而不必修改整个类层次,使得类层次结构的代码臃肿难以维护。而且这样符合“开闭原则”的要求。而且每个具体的访问者角色都对应于一个相关操作,因此如果一个操作的需求有变,那么仅仅修改一个具体访问者角色,而不用改动整个类层次。


2)访问者模式的双重分派技术

(1)将具体访问者作为参数传递给具体元素角色

(2)进入具体元素角色后,具体元素角色调用者作为参数的具体访问者的visit方法,同时将自己(this)作为参数传递进行。具体访问者再根据参数的不同来执行相应的方法


3)前提:开闭原则”的遵循总是片面的。如果系统中的类层次发生了变化,会对访问者模式产生什么样的影响呢?你必须修改访问者接口和每一个具体访问者。因此4人组曾经提出,访问者模式适用于数据结构相对稳定的系统。


4)适用情况:访问者模式的目的是要把处理从数据结构分离出来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式是比较合适的,因为访问者模式似得算法操作的增加变得容易。反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据对象增加进来,就不适合使用访问者模式。  

details/49408873

目录
打赏
0
0
0
0
2
分享
相关文章
访问者模式
访问者模式是一种行为型设计模式,用于将数据结构与其操作解耦。通过在不改变数据结构的前提下增加新的操作,访问者模式提供了一种灵活的方式来实现功能扩展。其关键特性包括分离操作、支持扩展和双分派机制。适用于需要对对象结构中的元素执行多种操作、频繁扩展操作以及不希望操作逻辑和数据结构耦合的场景。常见的使用案例包括编译器中的语法树、文件系统和游戏场景。优点是增加操作时无需修改数据结构,符合开闭原则;缺点是添加新的数据结构类型时需要修改所有访问者类,维护成本较高。
62 3
访问者模式问题之在不使用访问者模式的情况下,怎么在一个 SelectNode 类中实现 extractFunctions 方法
访问者模式问题之在不使用访问者模式的情况下,怎么在一个 SelectNode 类中实现 extractFunctions 方法
聊聊Java设计模式-访问者模式
访问者模式(Visitor Pattern)指将作用域某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作。
75 3
聊聊Java设计模式-访问者模式
|
10月前
|
行为型 访问者模式
行为型 访问者模式
72 0
深入Java设计模式之访问者模式
深入Java设计模式之访问者模式
84 0
今天说说你不知道的访问者模式
今天说说你不知道的访问者模式
95 0
java设计模式之访问者模式
写这篇文章之前,我也看了十几篇网络大牛写的访问者设计模式的文章,都说这个访问者模式是最复杂的一个,但是我觉得跟其他的设计模式并没有太多的不同,因此自己整理了一下,相信大多数人都能看懂。
202 0
java设计模式之访问者模式
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等