访问者模式
解释
在结构不变的情况下动态改变对于内部元素的动作
举例
组装电脑,不同的顾客打不同的折扣
可以使用visitor模式,不同的visitor实现各自的对应折扣问题
public class Computer {
ComputerPart cpu = new CPU();
ComputerPart memory = new Memory();
ComputerPart board = new Board();
public void acccept(Visitor v) {
this.cpu.accept(v);
this.memory.accept(v);
this.board.accept(v);
}
public static void main(String[] args) {
PersonelVisitor p = new PersonelVisitor();
new Computer().acccept(p);
System.out.println(p.totalPrice);
}
}
abstract class ComputerPart {
abstract void accept(Visitor v);
//some other operations eg:getName getBrand
abstract double getPrice();
}
class CPU extends ComputerPart {
@Override
void accept(Visitor v) {
v.visitCpu(this);
}
@Override
double getPrice() {
return 500;
}
}
class Memory extends ComputerPart {
@Override
void accept(Visitor v) {
v.visitMemory(this);
}
@Override
double getPrice() {
return 300;
}
}
class Board extends ComputerPart {
@Override
void accept(Visitor v) {
v.visitBoard(this);
}
@Override
double getPrice() {
return 200;
}
}
interface Visitor {
void visitCpu(CPU cpu);
void visitMemory(Memory memory);
void visitBoard(Board board);
}
class PersonelVisitor implements Visitor {
double totalPrice = 0.0;
@Override
public void visitCpu(CPU cpu) {
totalPrice += cpu.getPrice()*0.9;
}
@Override
public void visitMemory(Memory memory) {
totalPrice += memory.getPrice()*0.85;
}
@Override
public void visitBoard(Board board) {
totalPrice += board.getPrice()*0.95;
}
}
class CorpVisitor implements Visitor {
double totalPrice = 0.0;
@Override
public void visitCpu(CPU cpu) {
totalPrice += cpu.getPrice()*0.6;
}
@Override
public void visitMemory(Memory memory) {
totalPrice += memory.getPrice()*0.75;
}
@Override
public void visitBoard(Board board) {
totalPrice += board.getPrice()*0.75;
}
}
类图
代码
知识点
visitor模式更适合结构不变的情况下
如果结构发生变更,则所有的visitor都需要对应变更代码。
最开始的visitor模式是使用在编译器中,编译器需要做类型检查、中间处理等等…
抽象语法树中多个节点,如果不实用visitor模式需要每个节点做处理。
如果使用visitor模式则可以所有节点共通处理,每个类型的visitor实现各自的逻辑检查…
visitor模式的经典应用 — asm
动态读取
public class ClassPrinter extends ClassVisitor {
public ClassPrinter() {
super(ASM4);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
System.out.println(name + " extends " + superName + "{" );
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
System.out.println(" " + name);
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
System.out.println(" " + name + "()");
return null;
}
@Override
public void visitEnd() {
System.out.println("}");
}
public static void main(String[] args) throws IOException {
ClassPrinter cp = new ClassPrinter();
//ClassReader cr = new ClassReader("java.lang.Runnable");
ClassReader cr = new ClassReader(
ClassPrinter.class.getClassLoader().getResourceAsStream("com/mashibing/dp/ASM/T1.class"));
cr.accept(cp, 0);
}
}
动态写入
public class ClassWriteTest {
public static void main(String[] args) {
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
"pkg/Comparable", null, "java/lang/Object",
null);
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I",
null, -1).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I",
null, 0).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I",
null, 1).visitEnd();
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo",
"(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
byte[] b = cw.toByteArray();
MyClassLoader myClassLoader = new MyClassLoader();
Class c = myClassLoader.defineClass("pkg.Comparable", b);
System.out.println(c.getMethods()[0].getName());
}
}
使用ASM进行动态代理
public class ClassTransformerTest {
public static void main(String[] args) throws Exception {
ClassReader cr = new ClassReader(
ClassPrinter.class.getClassLoader().getResourceAsStream("com/mashibing/dp/ASM/Tank.class"));
ClassWriter cw = new ClassWriter(0);
ClassVisitor cv = new ClassVisitor(ASM4, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
//return mv;
return new MethodVisitor(ASM4, mv) {
@Override
public void visitCode() {
visitMethodInsn(INVOKESTATIC, "com/mashibing/dp/ASM/TimeProxy","before", "()V", false);
super.visitCode();
}
};
}
};
cr.accept(cv, 0);
byte[] b2 = cw.toByteArray();
MyClassLoader cl = new MyClassLoader();
//Class c = cl.loadClass("com.mashibing.dp.ASM.Tank");
cl.loadClass("com.mashibing.dp.ASM.TimeProxy");
Class c2 = cl.defineClass("com.mashibing.dp.ASM.Tank", b2);
c2.getConstructor().newInstance();
String path = (String)System.getProperties().get("user.dir");
File f = new File(path + "/com/mashibing/dp/ASM/");
f.mkdirs();
FileOutputStream fos = new FileOutputStream(new File(path + "/com/mashibing/dp/ASM/Tank_0.class"));
fos.write(b2);
fos.flush();
fos.close();
}
}
生成的代码
public class Tank {
public Tank() {
TimeProxy.before();
super();
}
public void move() {
TimeProxy.before();
System.out.println("Tank Moving ClaClaCla ...");
}
}