- 解耦数据结构和数据
- 三种角色
- 访问者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
}
}
标签:getMoney,Money,分派,模式,money,new,public,访问者
From: https://www.cnblogs.com/lxpStu/p/17133944.html