访问者模式和ASM详解
本文链接:https://blog.csdn.net/feather_wch/article/details/131756394
文章目录
1、访问者模式(Visitor Pattern)属于行为型模式
2、定义:在类的内部结构不变的情况下,不同的访问者访问这个对象都会呈现出不同的处理方式。
为了解决类结构不变但操作处理逻辑易变的问题,把对数据的操作都封装到访问者类中,我们只需要调用不同的访问者,而无需改变改变结构类。
3、违背了开闭原则
- 要新增元素,需要修改Visitor和每一个ConcreateVisitor
结构
访问者模式的基本结构包括以下几个角色:
- 抽象元素(Element):定义了一个接受访问者的方法,通常是
accept(Visitor visitor)
。 ==> 比如是饮品 - 具体元素(ConcreteElement):实现了抽象元素的接受方法,通常是
visitor.visit(this)
。==> 比如是奶茶、果茶 - 抽象访问者(Visitor):定义了对每个具体元素的访问操作,通常是
visit(ConcreteElement element)
。==> 会员 - 具体访问者(ConcreteVisitor):实现了抽象访问者的访问操作,根据具体元素的类型执行相应的逻辑。=> 白银会员、铂金会员、钻石会员
- 对象结构(ObjectStructure):维护了一个元素的集合,提供了遍历元素的方法,可以让访问者对每个元素进行访问。==> 奶茶店
奶茶店维护不同的奶茶、果茶,对于同一种产品,不同的会员会拥有不同的折扣。
抽象元素:饮品
public interface Beverage {
void accept(Visitor visitor); // 访问
int getPrice(); // 获得价格
}
具体元素:声声乌龙、幽兰拿铁
实现饮料接口,accept还是交给visitor自己去处理
public class ShengShengWuLong implements Beverage {
int price;
public ShengShengWuLong(int price) {
this.price = price;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public int getPrice() {
return price;
}
}
public class YoulanLatte implements Beverage {
int price;
public YoulanLatte(int price) {
this.price = price;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public int getPrice() {
return price;
}
}
抽象访问者:Visitor
根据具体元素的数量,定义visit方法
public abstract class Visitor {
abstract void visit(ShengShengWuLong wulong);
abstract void visit(YoulanLatte latte);
}
具体访问者
白银会员、黄金会员、钻石会员
实现visit方法,自定义处理逻辑。
public class SilverClient extends Visitor {
@Override
void visit(ShengShengWuLong wulong) {
System.out.println("白银客户 喝到:"+wulong.getClass().getSimpleName() + " 9折:" + (0.9 * wulong.getPrice()));
}
@Override
void visit(YoulanLatte latte) {
System.out.println("白银客户 喝到:"+latte.getClass().getSimpleName() + " 9折:" + (0.9 * latte.getPrice()));
}
}
public class GoldClient extends Visitor {
@Override
void visit(ShengShengWuLong wulong) {
System.out.println("黄金客户 喝到:"+wulong.getClass().getSimpleName() + " 8折:" + (0.8 * wulong.getPrice()));
}
@Override
void visit(YoulanLatte latte) {
System.out.println("黄金客户 喝到:"+latte.getClass().getSimpleName() + " 8折:" + (0.8 * latte.getPrice()));
}
}
public class DiamondClient extends Visitor {
@Override
void visit(ShengShengWuLong wulong) {
System.out.println("钻石客户 喝到:"+wulong.getClass().getSimpleName() + " 7折:" + (0.7 * wulong.getPrice()));
}
@Override
void visit(YoulanLatte latte) {
System.out.println("钻石客户 喝到:"+latte.getClass().getSimpleName() + " 7折:" + (0.7 * latte.getPrice()));
}
}
对象结构:茶颜悦色商店
- 存储各种饮品
- 提供给访问者的服务接口
public class Store {
List<Beverage> drinks = new ArrayList<>();
public void addBeverage(Beverage beverage){
drinks.add(beverage);
}
public void accept(Visitor visitor){
for (Beverage beverage : drinks) {
beverage.accept(visitor);
}
}
}
测试类
public class Main {
public static void main(String[] args) {
Store store = new Store();
store.addBeverage(new ShengShengWuLong(32));
store.addBeverage(new YoulanLatte(26));
store.accept(new SilverClient());
store.accept(new GoldClient());
store.accept(new DiamondClient());
}
}
ASM中的访问者模式
1、ASM是什么?=>ASM框架通过改写或直接写出字节码(class文件)去生成新的类
相对于JDK动态代理(Proxy.newProxyInstance)性能更高,因为后者是利用了反射,而前者直接生成想要的类行为。
2、为什么ASM要使用访问者模式?
- JVM规范中class文件拥有固定结构
3、ASM是如何实现的?
- 通过找到固定方法区,修改方法区代码。
- 需要如何变换,定义访问者去决定操作逻辑
4、ASM组成部分和访问者对照表
1、抽象元素(Element)
2、具体元素(ConcreteElement)
- 抽象元素和具体元素是指字节码中的各种组成部分,比如类、字段、方法、指令、注解等。
3、抽象访问者(Visitor) => ClassVisitor、MethodVisitor、FieldVisitor、SignatureVisitor
4、具体访问者(ConcreteVisitor) => ClassWriter、AdviceAdapter(MethodVisitor)
- 实现了对类、字段、方法等元素的访问操作。
5、对象结构(ObjectStructure)=> ClassReader
- 负责读取类文件,并将其转换为一系列的事件,然后传递给ClassVisitor进行处理
- 提供了一个accept方法,接受一个ClassVisitor作为参数
MethodVisitor也是一个抽象访问者,它定义了对方法中的指令、变量、标签、异常等元素的访问操作,通常也是visit(ConcreteElement element)。MethodVisitor也可以有多个具体的子类,比如AdviceAdapter、GeneratorAdapter等,它们都实现了对方法中的元素的访问操作。AdviceAdapter负责在方法的开始和结束处插入代码,GeneratorAdapter负责生成常用的指令。
ClassReader读取流程
ClassReader
->读取到一个类
->ClassVisitor.visit 传递一些类的信息
->读取到一个字段
->ClassVisitor.visitField 传递一些字段的信息
->读取到一个方法
->ClassVisitor.visitMethod方法 传递一些方法的信息
->返回MethodVisitor对象:定义了对方法中的指令、变量、标签、异常等元素的访问操作
->继续读取这个方法中的元素
->MethodVisitor.visit方法 传递一些元素的信息