访问者模式

  • 解耦数据结构和数据
  • 三种角色
    • 访问者IPeople:对数据结构的访问
    • 被访问者IMoney:被访问的数据结构
    • 容器BankContainer:用于装载数据结构,提供方法接受访问者访问所有的数据结构
  • UML类图
/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:23
 * @Description:抽象接口钱
 */
public interface IMoney {

    /**
     * 接受人来取钱
     *
     * @param people 中国人、美国人、等等.....
     */
    void accept(IPeople people);

    /**
     * 取钱
     *
     * @return int
     */
    int getMoney();
}
/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:30
 * @Description:美元, 实现了抽象接口 {@link IMoney} 接受美人来取美元
 */
public class DollarMoney implements IMoney {
    @Override
    public void accept(IPeople people) {
        System.out.println("DollarMoney取钱");
        people.visit(this);
    }

    @Override
    public int getMoney() {
        return 10;
    }
}
/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:26
 * @Description: 人民币, 实现了抽象接口 {@link IMoney} 接受人来取人民币
 */
public class RmbMoney implements IMoney {
    @Override
    public void accept(IPeople people) {
        System.out.println("RmbMoney取钱");
        people.visit(this);
    }

    @Override
    public int getMoney() {
        return 20;
    }
}

/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:24
 * @Description: 人, 其子类分为中国人、美国人
 */
public interface IPeople {

    /**
     * 人去取钱
     *
     * @param money 钱
     */
    void visit(IMoney money);
}

/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:34
 * @Description: 中国人, 实现接口{@link IPeople}, 完成对人民币的访问
 */
public class Chinese implements IPeople {
    @Override
    public void visit(IMoney money) {
        System.out.println("我是中国人, 我来取钱了, 取了" + money.getMoney() + "元");
    }
}

/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:34
 * @Description: 美国人, 实现接口{@link IPeople}, 完成对美元的访问
 */
public class American implements IPeople {
    @Override
    public void visit(IMoney money) {
        System.out.println("我是美国人, 我来取钱了, 取了" + money.getMoney() + "元");
    }
}

/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:44
 * @Description: 银行存储钱的容器
 */
public class BankContainer {

    private List<IMoney> list;

    public BankContainer() {
        this.init();
    }

    private void init(){
        list = new CopyOnWriteArrayList<>();
        list.add(new RmbMoney());
        list.add(new DollarMoney());
    }

    public void getMoney(IPeople people){
        for (IMoney money : this.list) {
            money.accept(people);
        }
    }
}

/**
 * @Author: lxpStu
 * @Date: 2023/02/18/10:48
 * @Description:
 */
public class ClientVisitor {

    public static void main(String[] args) {
        BankContainer container = new BankContainer();
        System.out.println("===========中国人取钱===========");
        container.getMoney(new Chinese());
        System.out.println("===========美国人取钱===========");
        container.getMoney(new American());
    }
}
  • 输出结果
  • 编译期和运行期
    • 编译期:指程序文件编译为汇编程序,再由汇编程序编译为机器语言的过程, 在Java中编译期指程序被编译为.class文件
    • 运行期:指程序真正执行的时期.
  • 分派
    • 分派是指根据对象的类型进行方法的选择, 在Java中对象的类型在编译期和运行期有可能是不同的, 所谓编译看左, 运行看右.
    • 如 Money money = new Rmb(); 变量 money在编译期类型是 Money, 在运行期实际的类型是Rmb, 从而引出了分派的两种类型.
  • 分派的分类
    • 静态分派:也叫编译期分派,根据编译期的变量定义的类型决定程序执行的方法是哪个, 比如重载就是静态分派, Java中重载方法的参数类型不同、参数个数可能也不同, 所以静态分派说Java是静态多分派的.
    • 动态分派:也叫运行期分派,根据运行期的变量实际的类型决定程序执行的方法是哪个, 比如重写就是动态态分派, Java中对象的实际类型只能对应一个重写方法, 所以说Java是动态单分派的.
  • 访问者模式的伪动态双分派
    • Java只支持动态单分派, 想要支持动态双分派必须基于代码层面的设计模式解决, 所以说访问者模式是伪动态双分派的,在ClientVisitor中第一次根据人的类型即【new BankContainer().getMoney(new Chinese())和 new BankContainer().getMoney(new American())】完成了第一次动态分派.将人的实际类型传递给了RmbMoney和DollarMoney的accept()在IMoney的子类(如RmbMoney)的accept()中又调用人的visit(this), 并将自己的this对象传入, 我们知道this对象代表本类的实例, 所以完成了第二次动态分派, 即调用了某人的visit()方法
  • 分派的code演示
public class Money {
}
class Rmb extends Money {}
class Dollar extends Money {}
class Bank{
    public void getMoney(Money money){
        System.out.println("Money");
    }
    public void getMoney(Rmb rmb){
        System.out.println("RMB");
    }
    public void getMoney(Dollar dollar){
        System.out.println("Dollar");
    }
}
class DispatchClient {
    public static void main(String[] args) {
        Money money = new Money();
        Money rmb = new Rmb();
        Money dollar = new Dollar();
        Bank bank = new Bank();
        System.out.println("=====静态分派=====");
        bank.getMoney(money);// Money
        bank.getMoney(rmb);// Money
        bank.getMoney(dollar);// Money
        System.out.println("=====动态分派=====");
        bank.getMoney(new Money());// Money
        bank.getMoney(new Rmb());//RMB
        bank.getMoney(new Dollar());//Dollar
    }
}
posted @   刘小胖同学  阅读(31)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示