2021年9月27日-设计模式之访问者模式

第十六章:访问者模式

一、基本介绍

现在我们有这么几个类:足球类、篮球类、排球类。现在需要实现获取各个球重量的功能。那么直接在各个球类中加一个获取重量的方法就行了。那么问题来了,现在又需要获取各个球的颜色。那我们还是修改各个类增加个新方法?那如果以后有更多的新需求还是这么做?这显然违反了 OCP 原则。

所以我们使用访问者模式解决这个问题。

访问者模式基本类图:

在这里插入图片描述

  • Visitor 里面的 operation 的数量往往对应着具体 Element 的种类数
  • 每新增一个需求只需新建一个 ConcreteVisitor 类
  • Element 具体的子类数应该是不轻易改变的,因为这会影响到所有访问者类

二、案例解决

在这里插入图片描述

抽象元素类 Ball

@Data
public abstract class Ball {
    private int id;
    private int diameter;
    private int weight;
    private String color;

    abstract public void accept(Visitor visitor);
}

具体元素子类

Basketball

public class Basketball extends Ball {
    @Override
    public void accept(Visitor visitor) {
        visitor.operateBasketball(this);
    }
}

Football

public class Football extends Ball{
    @Override
    public void accept(Visitor visitor) {
        visitor.operateFootball(this);
    }
}

Volleyball

public class Volleyball extends Ball{
    @Override
    public void accept(Visitor visitor) {
        visitor.operateVolleyball(this);
    }
}

抽象访问者类 Visitor

public abstract class Visitor {
    // 根据操作的元素类第二次分派
    abstract public void operateBasketball(Basketball ball);
    abstract public void operateFootball(Football ball);
    abstract public void operateVolleyball(Volleyball ball);
}

具体子类访问者

WeightVisitor

public class WeightVisitor extends Visitor {
    @Override
    public void operateBasketball(Basketball ball) {
        // 为什么不直接调用 ball.getWeight(),搞这么麻烦
        // 实际情况下可能有很多输出格式,比如 xml 形式什么的
        // 所以直接调用 ball.getWeight() 往往是不满足需求的
        System.out.println("篮球重量:" + ball.getWeight());
    }

    @Override
    public void operateFootball(Football ball) {
        System.out.println("足球重量:" + ball.getWeight());
    }

    @Override
    public void operateVolleyball(Volleyball ball) {
        System.out.println("排球重量:" + ball.getWeight());
    }
}

测试类

public class VisitorTest {
    public static void main(String[] args) {
        Football football = new Football();
        football.setWeight(200);
        WeightVisitor weightVisitor = new WeightVisitor();
        // 第一次分派
        football.accept(weightVisitor);
    }
}

现在如果我们新增一个打印颜色的需求是不是只需添加一个打印颜色功能的访问者就行了呢!

上面的案例使用到了双分派,element.accept(visitor) 根据访问者第一次分派,visitor 里根据操作的元素类第二次分派。这样就能实现特定元素特定功能

三、模式总结

1)适合有稳定的数据结构,如上述案例 Ball 的子类就那么多不怎么新增

2)有经常变化的功能需求,只需新增一个 Visitor 实现类就行了

3)可以做报表、UI、拦截器、过滤器

4)但是我们的元素类对访问者类可以说开诚布公,违反迪米特法则

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值