Java设计模式——访问者模式

Java设计模式之访问者模式

访问者模式:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

使用到了Java双分派

角色:

  • Vistor(抽象访问者):为该对象结构中具体元素角色声明一个访问操作接口。
  • ConcreteVisitor(具体访问者):每个具体访问者都实现了Vistor中定义的操作。
  • Element(抽象元素):定义了一个accept操作,以Visitor作为参数。
  • ConcreteElement(具体元素):实现了Element中的accept()方法,调用Vistor的访问方法以便完成对一个元素的操作。
  • ObjectStructure(对象结构):可以是组合模式,也可以是集合;能够枚举它包含的元素;提供一个接口,允许Vistor访问它的元素。

使用

适用场景:

  • 假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
  • 一组对象有相似的方法,使用访问者模式减少重复代码量

场景:

运动员每天都在训练,我们需要访问运动员的一些信息,这些信息是根据内部状态获取的,比赛的成绩获取到获奖情况,身体状态获取到相应的医学指导。

现在有三种运动员:跳高运动员跳远运动员径赛运动员

我们要访问他们比赛的获奖情况和身体状况的指导信息,采用访问者模式

  • Visitor 访问者接口 定义访问者的行为
/**
 * 访问者接口,接口方法访问具体对象,违背依赖倒置原则
 */
public interface Visitor {
    public void visit(HighJumperAthlete athlete);
    public void visit(LongJumperAthlete athlete);
    public void visit(RunnerAthlete athlete);
}
  • Element 运动员元素接口
/**
 * 元素接口
 */
public interface Element {
    public void accept(Visitor visitor);
}
  • HealthState 身体健康状态枚举类
/**
 * 身体健康状态枚举类
 */
public enum HealthState {
    MORE_BETTER,//较好
    GOOD,//好
    NORMAL,//正常
    A_LITTLE_BAD,//较差
    BAD;//很差
}
  • HighJumperAthlete 跳高运动员元素类
/**
 * 跳高运动员元素类
 */
@Data
@AllArgsConstructor
public class HighJumperAthlete implements Element {
    private String name;//名字
    private String highJumpGrade;//成绩
    private HealthState healthCondition;//健康状态
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  • LongJumperAthlete 跳远运动员元素类
/**
 * 跳远运动员元素类
 */
@Data
@AllArgsConstructor
public class LongJumperAthlete implements Element{
    private String name;
    private String longJumpGrade;
    private HealthState healthCondition;

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  • RunnerAthlete 径赛运动员元素类
/**
 * 径赛运动员元素类
 */
@Data
@AllArgsConstructor
public class RunnerAthlete implements Element {
    private String name;
    private String longRunGrade;
    private String shortRunGrade;
    private HealthState healthCondition;

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  • GradeSelectionsVisitor 比赛成绩获奖情况访问类
/**
 * 访问运动员成绩获奖信息
 * 根据成绩信息获取获奖情况的实现类
 */
public class GradeSelectionsVisitor implements Visitor{
    //实现访问跳高运动员操作
    public void visit(HighJumperAthlete athlete) {
        double grade = Double.parseDouble(athlete.getHighJumpGrade());
        if(grade>=7.00){
            System.out.println(athlete.getName()+" 获得了跳高一等奖");
        }else if(grade>=6.00){
            System.out.println(athlete.getName()+" 获得了跳高二等奖");
        }else {
            System.out.println("很遗憾,"+athlete.getName()+" 在跳高比赛中没有获得奖");
        }
    }
    //实现访问跳远运动员
    public void visit(LongJumperAthlete athlete) {
        double grade = Double.parseDouble(athlete.getLongJumpGrade());
        if(grade>=12.00){
            System.out.println(athlete.getName()+" 获得了跳远一等奖");
        }else if(grade>=10.00){
            System.out.println(athlete.getName()+" 获得了跳远二等奖");
        }else {
            System.out.println("很遗憾,"+athlete.getName()+" 在跳远比赛中没有获得奖");
        }
    }
    //实现访问径赛运动员
    public void visit(RunnerAthlete athlete) {
        double longRunGrade = Double.parseDouble(athlete.getLongRunGrade());
        double shortRunGrade = Double.parseDouble(athlete.getShortRunGrade());
        if(longRunGrade<=45.00){
            System.out.println(athlete.getName()+" 获得了长跑一等奖");
        }else if(longRunGrade<=53.00){
            System.out.println(athlete.getName()+" 获得了长跑二等奖");
        }else {
            System.out.println("很遗憾,"+athlete.getName()+" 在长跑比赛中没有获得奖");
        }
        if(shortRunGrade<=11.00){
            System.out.println(athlete.getName()+" 获得了短跑一等奖");
        }else if(shortRunGrade<=12.50){
            System.out.println(athlete.getName()+" 获得了短跑二等奖");
        }else {
            System.out.println("很遗憾,"+athlete.getName()+" 在短跑比赛中没有获得奖");
        }
    }
}
  • HeathEvaluateVisitor 身体健康访问实现类
/**
 * 访问运动员身体健康状态
 * 执行相应操作提醒实现类
 */
public class HeathEvaluateVisitor implements Visitor {
    public void visit(HighJumperAthlete athlete) {
        HealthState state = athlete.getHealthCondition();
        healthEvaluate(athlete.getName(),state);
    }

    public void visit(LongJumperAthlete athlete) {
        HealthState state = athlete.getHealthCondition();
        healthEvaluate(athlete.getName(),state);
    }

    public void visit(RunnerAthlete athlete) {
        HealthState state = athlete.getHealthCondition();
        healthEvaluate(athlete.getName(),state);
    }

    public static void healthEvaluate(String name,HealthState state){
        if(state.equals(HealthState.MORE_BETTER)){
            System.out.println(name+" 你的身体状态非常好");
        }else if(state.equals(HealthState.GOOD)){
            System.out.println(name+" 你的身体状况挺好,继续保持");
        }else if(state.equals(HealthState.NORMAL)){
            System.out.println(name+" 你的身体状况没问题,不过要加以注意");
        }else if(state.equals(HealthState.A_LITTLE_BAD)){
            System.out.println(name+" 你的身体状况出了些问题,请作进一步检查");
        }else{
            System.out.println(name+" 你的身体状况很不好,你将不能继续训练,请立即进行检查");
        }
    }
}
  • ObjectStructure 元素结构类,控制元素的操作和访问
/**
 * 元素访问入口,元素结构容器
 */
public class ObjectStructure {
    //list存放运动员元素
    private List<Element> athletes;
    public ObjectStructure(){
        athletes = new ArrayList<>();
    }
    //添加运动员
    public void add(Element element){
        athletes.add(element);
    }
    //访问所有运动员
    public void visitAll(Visitor visitor){
        athletes.forEach((o)->o.accept(visitor));
    }
}
  • 测试
public class ClientTest {
    public static void main(String[] args) {
        ObjectStructure objectStructure = addAndGetAthlete();
        GradeSelectionsVisitor visitor = new GradeSelectionsVisitor();
        System.out.println("比赛最终结果------");
        objectStructure.visitAll(visitor);
        System.out.println("\n身体健康检查结果------");
        HeathEvaluateVisitor visitor1 = new HeathEvaluateVisitor();
        objectStructure.visitAll(visitor1);
    }
    /**
     * 添加运动员
     * @return 操作运动员的数据结构
     */
    private static ObjectStructure addAndGetAthlete(){
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(new HighJumperAthlete("张三","8.00",HealthState.A_LITTLE_BAD));
        objectStructure.add(new HighJumperAthlete("李四","6.00",HealthState.GOOD));
        objectStructure.add(new HighJumperAthlete("王五","7.00",HealthState.NORMAL));
        objectStructure.add(new LongJumperAthlete("小白","13.00",HealthState.MORE_BETTER));
        objectStructure.add(new LongJumperAthlete("小丁","10",HealthState.BAD));
        objectStructure.add(new LongJumperAthlete("小周","11.00",HealthState.NORMAL));
        objectStructure.add(new RunnerAthlete("小吴","46","11",HealthState.NORMAL));
        objectStructure.add(new RunnerAthlete("小王","44","13",HealthState.GOOD));
        objectStructure.add(new RunnerAthlete("小邹","45","10",HealthState.A_LITTLE_BAD));
        objectStructure.add(new RunnerAthlete("小赵","43","11.5",HealthState.BAD));
        return objectStructure;
    }
}
  • 输出
比赛最终结果------
张三 获得了跳高一等奖
李四 获得了跳高二等奖
王五 获得了跳高一等奖
小白 获得了跳远一等奖
小丁 获得了跳远二等奖
小周 获得了跳远二等奖
小吴 获得了长跑二等奖
小吴 获得了短跑一等奖
小王 获得了长跑一等奖
很遗憾,小王 在短跑比赛中没有获得奖
小邹 获得了长跑一等奖
小邹 获得了短跑一等奖
小赵 获得了长跑一等奖
小赵 获得了短跑二等奖

身体健康检查结果------
张三 你的身体状况出了些问题,请作进一步检查
李四 你的身体状况挺好,继续保持
王五 你的身体状况没问题,不过要加以注意
小白 你的身体状态非常好
小丁 你的身体状况很不好,你将不能继续训练,请立即进行检查
小周 你的身体状况没问题,不过要加以注意
小吴 你的身体状况没问题,不过要加以注意
小王 你的身体状况挺好,继续保持
小邹 你的身体状况出了些问题,请作进一步检查
小赵 你的身体状况很不好,你将不能继续训练,请立即进行检查

访问者模式优点

  • 可以对组合结构加入新的操作,无需改变结构
  • 便于扩展组合对象的新的操作

缺点

  • 违背了依赖倒置原则,访问者依赖了具体元素类
  • 扩展元素类不方便,需要修改访问者

代码地址:Github访问者模式


Java设计模式|策略模式

Java设计模式|观察者模式

Java设计模式|装饰者模式

Java设计模式|工厂模式

Java设计模式|命令模式

Java设计模式|适配器模式和外观模式

Java设计模式|模板方法模式

Java设计模式|迭代器模式和组合模式

Java设计模式|状态模式

Java设计模式|代理模式

Java设计模式|单例模式

Java设计模式|备忘录模式

Java设计模式|访问者模式

Java设计模式|复合模式

Java设计模式|桥接模式

Java设计模式|生成器模式

Java设计模式|享元模式/蝇量模式

Java设计模式|原型模式

Java设计模式|责任链模式

Java设计模式|中介者模式

  • 本文作者: dzou | 微信:17856530567
  • 本文链接: http://www.dzou.top/post/d88fa864.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
  • 并保留本声明和上方二维码。感谢您的阅读和支持!