在数据基础类里面有一个方法接受访问者,将自身引用传入访问者
利用“双重分派”分派到实例内部,弥补Java多态中的方法重载时静态的,这一问题
Java的方法重载是静态的:
方法重载时,若参数有父类的,也有子类的,则按声明的类型调用,而不是实例的真正类型。
eg. 对于重载的方法test(Father f)和test(Son s),若Father f = new Son();,调用test(f)则会以Father的类型传入。
所以,用父类的引用无法代表子类的实例。但是this指针的类型是本类。
事例
需求:对苹果、桔子、香蕉进行清仓甩卖
数据结构如图:
接口及其实现类代码如下:
public interface Fruit {
void accept(Visit visit);
}
public class Apple implements Fruit {
int price = 100;
@Override
public void accept(Visit visit) {
visit.sell(this);
}
}
public class Orange implements Fruit {
int price = 80;
@Override
public void accept(Visit visit) {
visit.sell(this);
}
}
public class Banana implements Fruit {
int price = 20;
@Override
public void accept(Visit visit) {
visit.sell(this);
}
}
访问者类。通过方法重载,根据参数类型不同而执行不同的逻辑
public class Visit {
/*
方法的重载
*/
public void sell(Apple apple) {
// 卖苹果
}
public void sell(Orange orange) {
// 卖桔子
}
public void sell(Banana banana) {
// 卖香蕉
}
public void sell(Fruit fruit) {
// 其他水果。缺省情况
}
}
测试:客户持有数据集合和访问类。
public class VisitClient {
private List<Fruit> mList = new ArrayList<>();
private Visit mVisit = new Visit();
// 添加要甩卖的水果
{
mList.add(new Apple());
mList.add(new Orange());
mList.add(new Banana());
}
// 清仓甩卖
private void clearOut() {
for (Fruit fruit : mList) {
fruit.accept(mVisit);
}
}
}
总结
适用场景
- 集合中有不同类型的对象,要识别它们真实类型
- 数据结构对应的类固定不变时
- 对数据类增加新操作,又不想修改数据类
优点
- 避免污染数据类。由访问类判断真实类型并转发业务
- 符合单一职责
- 扩展性高
- 灵活性高
缺点
- 对访问者公布细节,违反了迪米特原则
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象