• 设计模式中的访问者模式
  • 发布于 2个月前
  • 215 热度
    0 评论
  • 长青诗
  • 0 粉丝 36 篇博客
  •   
概念
封装了一些作用于某种结构中的各个元素的操作(将数据结果与元素操作进行分离),可以在不改变这个数据结构的前提下,定义作用于这些元素的新的操作

结构
抽象访问者角色
定义了对每一个元素的访问行为,它的参数就是被访问的元素对象,它的方法个数理论上与元素个数保持一致(也看出访问者模式要求元素的个数不能改变)
具体访问者角色
完成抽象访问角色定义的对每一个元素的访问行为的具体实现
抽象元素角色
定义了一个接收访问者的接口方法,使元素可以被访问者访问
具体元素角色
完成抽象元素角色定义的接收访问者的接口方法的具体实现
对象结构角色
一个容器性质的类,会含有一组元素,并且可以遍历这些元素给访问者访问

示例
目标:有宠物这一种类(元素),定义其下有狸花猫、田园犬两个品种;有铲屎官(访问者),定义其下有主人、陌生人。铲屎官可以在家中投喂家中已有宠物

抽象元素角色
package 设计模式.行为型模式.访问者模式;
import lombok.Getter;
/**
 * 宠物:抽象元素角色
 */
@Getter
public abstract class Pet {

  /** 名称 */
  protected String name;

  /**
   * 构造方法
   */
  public Pet(String name) {
    this.name = name;
  }

  /**
   * 接受投喂
   */
  abstract void accept(ShitShovelOfficer officer);

}
具体元素角色一
package 设计模式.行为型模式.访问者模式;
/**
 * 狸花猫:具体元素角色
 */
public class TabbyCat extends Pet {

  /**
   * 构造方法
   */
  public TabbyCat(String name) {
    super(name);
  }

  /**
   * 接受投喂
   */
  @Override
  public void accept(ShitShovelOfficer officer) {
    // 调用铲屎官的投喂方法
    officer.feeding(this);
    System.out.println(this.getName() + ":感谢铲屎官" + officer.getName() + "的投喂,喵~");
  }

}
具体元素角色二
package 设计模式.行为型模式.访问者模式;
/**
 * 田园犬:具体元素角色
 */
public class PastoralDog extends Pet {

  /**
   * 构造方法
   */
  public PastoralDog(String name) {
    super(name);
  }

  /**
   * 接受投喂
   */
  @Override
  public void accept(ShitShovelOfficer officer) {
    // 调用铲屎官的投喂方法
    officer.feeding(this);
    System.out.println(this.getName() + ":感谢铲屎官" + officer.getName() + "的投喂,汪~");
  }

}
抽象访问者
package 设计模式.行为型模式.访问者模式;
import lombok.Getter;

/**
 * 铲屎官:抽象访问者角色
 */
@Getter
public abstract class ShitShovelOfficer {

  /** 名称 */
  protected String name;

  /**
   * 构造方法
   */
  public ShitShovelOfficer(String name) {
    this.name = name;
  }

  /**
   * 喂食狸花猫
   */
  abstract void feeding(TabbyCat cat);

  /**
   * 喂食田园犬
   */
  abstract void feeding(PastoralDog dog);

}
具体访问者一
package 设计模式.行为型模式.访问者模式;
/**
 * 主人:具体访问者角色
 */
public class TheHost extends ShitShovelOfficer {

  /**
   * 构造方法
   */
  public TheHost(String name) {
    super(name);
  }

  /**
   * 喂食狸花猫
   */
  @Override
  public void feeding(TabbyCat cat) {
    System.out.println(this.getName() + ":开始投喂狸花猫" + cat.getName());
  }

  /**
   * 喂食田园犬
   */
  @Override
  public void feeding(PastoralDog dog) {
    System.out.println(this.getName() + ":开始投喂田园犬" + dog.getName());
  }

}
具体访问者二
package 设计模式.行为型模式.访问者模式;
/**
 * 陌生人:具体访问者角色
 */
public class Someone extends ShitShovelOfficer {

  /**
   * 构造方法
   */
  public Someone(String name) {
    super(name);
  }

  /**
   * 喂食狸花猫
   */
  @Override
  public void feeding(TabbyCat cat) {
    System.out.println(this.getName() + ":开始投喂狸花猫" + cat.getName());
  }

  /**
   * 喂食田园犬
   */
  @Override
  public void feeding(PastoralDog dog) {
    System.out.println(this.getName() + ":开始投喂田园犬" + dog.getName());
  }

}
对象结构角色
package 设计模式.行为型模式.访问者模式;
import java.util.ArrayList;
import java.util.List;

/**
 * 家:对象结构角色
 */
public class Home {

  /** 家中可有很多的宠物 */
  private List<Pet> petList = new ArrayList<>();

  /**
   * 收养宠物
   */
  public void adoption(Pet pet) {
    petList.add(pet);
  }

  /**
   * 开始投喂
   */
  public void startFeed(ShitShovelOfficer officer) {
    petList.forEach(pet -> {
      pet.accept(officer);
    });
  }

}
测试类
package 设计模式.行为型模式.访问者模式;
/**
 * 测试类
 */
public class Demo {

  public static void main(String[] args) {
    // 创建主人
    ShitShovelOfficer theHost = new TheHost("主人");
    // 创建陌生人
    ShitShovelOfficer someone = new Someone("陌生人");

    // 创建狸花猫
    Pet tabbyCat = new TabbyCat("咪咪");
    // 创建田园犬
    Pet pastoralDog = new PastoralDog("小黑");

    // 创建家
    Home home = new Home();

    // 家中收养宠物
    home.adoption(tabbyCat);
    home.adoption(pastoralDog);

    // 主人喂养宠物
    home.startFeed(theHost);

    // 陌生人喂养宠物
    home.startFeed(someone);
  }

}
优缺点
优点
1.可以在不修改对象结构中元素的前提下,为元素添加新的功能
2.通过访问者来定义整个对象结构通用的功能,提高了代码的复用性
3.将相关的行为封装到一起构成一个访问者类,使每一个访问者类的功能单一好维护

缺点
1.每增加一个新的元素类,需要在每一个访问者角色中添加对应的操作,违背了“开闭原则”
2.访问者模式依赖具体元素角色,而不是依赖抽象元素角色

应用场景
1.对象结构相对稳定,但操作算法经常变化时,可以使用访问者模式
2.对象结构中的元素需要提供多种不同且不相关的操作、且需要避免让这些操作的变化影响对象的结构时,可以使用访问者模式
用户评论