访问者模式和ASM详解

访问者模式和ASM详解

本文链接:https://blog.csdn.net/feather_wch/article/details/131756394

文章目录

  • 访问者模式和ASM详解
    • 结构
      • 抽象元素:饮品
      • 具体元素:声声乌龙、幽兰拿铁
      • 抽象访问者:Visitor
      • 具体访问者
      • 对象结构:茶颜悦色商店
    • ASM中的访问者模式
      • ClassReader读取流程


1、访问者模式(Visitor Pattern)属于行为型模式

2、定义:在类的内部结构不变的情况下,不同的访问者访问这个对象都会呈现出不同的处理方式。

为了解决类结构不变但操作处理逻辑易变的问题,把对数据的操作都封装到访问者类中,我们只需要调用不同的访问者,而无需改变改变结构类。

【设计模式】访问者模式,不愧是最复杂的设计模式之一!

3、违背了开闭原则

  1. 要新增元素,需要修改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()));
    }
}

对象结构:茶颜悦色商店

  1. 存储各种饮品
  2. 提供给访问者的服务接口
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要使用访问者模式?

  1. JVM规范中class文件拥有固定结构

3、ASM是如何实现的?

  1. 通过找到固定方法区,修改方法区代码。
  2. 需要如何变换,定义访问者去决定操作逻辑

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方法 传递一些元素的信息

你可能感兴趣的:(设计模式,访问者模式)