访问者模式与ASM的不解之缘(一)

简介: 学习这方面的内容,主要是因为参加了集团双11技术分享的讲座

学习这方面的内容,主要是因为参加了集团双11技术分享的讲座:[http://www.atatech.org/ask/27965],

其中有一个讲座是分享共享的EOS:用于系统强弱依赖与常态下系统的提前诊段,所谓的强依赖指的是A系统必须基于B系统正常运行前提下才能正常运行,否则A则出现异常或错误导致流程不能继续,这种情况下A和B为强依赖关系。如果B系统出现异常,但不会影响A系统的正常流程,则称为A和B系统为弱依赖关系。EOS则可以用于系统强弱依赖进行判断并对弱依赖关系使用测试进行异常测试,造成B系统依赖出现异常测试A的流程。EOS的核心实现为AOP的技术,而用于AOP的实现有很多方式 。如JDK Proxy,Spring,ASM,对比如下图:

image.png

EOS采用了ASM这种形式。尝试着了解了一下ASM,对这段时间的学习做一个总结。一方面的给自己做个备忘,另一方面分享给大家,如果对大家一点点价值的地方,我就很满足了。


访问者模式

ASM的架构主要是采用了访问者模式来设计,所以我们先来了解一下访问者模式到底是个什么东东吧。。。


举个栗子

表示一个作用于某对象结构中的各元素的操作。在不改变各元素的类的前提下可以增加对这些元素的操作。

一个编译器,将源程序解析为一个抽象语法树之后,编译器会迭代每个结点并对结点进行一系列的检查操作如:类型检查,代码优化,流程分析等等。这些操作大多要求对不同的结点进行不同的处理。如对赋值语句的结点和对算术表达式的处理就不同。但在同一种编程语言范围内针对同一种类型的结点所任的操作一般不会变化。

image.png

上图所表达的意思是指:对于VariableRefNode这种类型的结点, 我们要做类型检查,生成代码或字节码,打印。对于AssignmentNode也会进行这三种处理。这种设计是将对类型的操作封装到类的本身里。这种做有几个缺点:a:操作分散到各种结点类中会导致事个系统很难理解,维护和修改,因为把打印操作与类型检查放在一块意图不明。b:如果要对Node结点增加一个操作,则需要在所有结点类里都要增加这个操作的实现,需要重新编译所有类。

如果要避免这两种缺点,只能将操作独立于结点类之外的对象(称为访问者Visitor)。当编译器遍历每个结点时,将结点交给些结点相对应的访问者进行操作处理。抽象出来则如下设计:


结构与角色

image.png

此时我们就不限于上面那个具体的示例了,我们抽象的角度来看,当我们需要对ConcreteElementA元素进行elementA的操作,并且操作封装在visitConcreteElementA(ConcreteElementA)方法里,对ConcreteElementB元素进行elementB的操作,并且操作封装在visitConcreteElementB(ConcreteElementB)方法里。整个程序运行的方法就为:当对象结构(ObjectStructure)迭代Element时,对于ConcreteElementA元素,则调用Accept方法传入相应的访问者:ConcreteVisitor1,对于ConcreteElementB素,则调用Accept方法传入相应的访问者:ConcreteVisitor2,对于不两只类型的结点分别在accept中调用相对的操作方法,如ConcreteElementA的accept中会调用ConcreteVisitor1的VisitConcreteElementA(this),如ConcreteElementB的accept中会调用ConcreteVisitor2的VisitConcreteElementB(this).此时由于入传为this(即各个元素本身的状态),所以访问者可以访问或处理当前元素的数据与操作。

他们之间的调用关系如图:

image.png


两个层次

使用Visitor模式,必须定义两个类层次:一个对应于接受操作的元素(Element层次),另一个对就于定义对元素的操作的访问者(Visitor层次)。给访问者类层次增加一个新的子类即可创建一个新的操作。只要该系统的元素处理方式(即不需要增加新的Element子类),我们就可以简单的定义新的NodeVisitor子类以增加新的功能。


适用性

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
    Visitor使得你可以将相关的操作集中起来定义在一个类中。
    当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
    改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。
    如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。


示例

Visitor

public interface Visitor {
    public void visitString(StringElement stringE);
    public void visitFloat(FloatElement floatE);
    public void visitCollection(Collection collection);
}
```
####ConreteVisitor
```
public class ConcreteVisitor implements Visitor {
    public void visitCollection(Collection collection) {
        // TODO Auto-generated method stub
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            Object o = iterator.next();
            if (o instanceof Visitable) {
                ((Visitable)o).accept(this);
            }
        }
    }
    public void visitFloat(FloatElement floatE) {
        System.out.println(floatE.getFe());
    }
    public void visitString(StringElement stringE) {
        System.out.println(stringE.getSe());
    }
}
```
####Element
```
public interface Visitable {
    public void accept(Visitor visitor);
}
```
####ConreteElement
```
public class FloatElement implements Visitable {
    private Float fe;
    public FloatElement(Float fe) {
        this.fe = fe;
    }
    public Float getFe() {
        return this.fe;
    }
    public void accept(Visitor visitor) {
        visitor.visitFloat(this);
    }
}
public class StringElement implements Visitable {
    private String se;
    public StringElement(String se) {
        this.se = se;
    }
    public String getSe() {
        return this.se;
    }
    public void accept(Visitor visitor) {
        visitor.visitString(this);
    }
}
```
####Test
```
public class Test {
    public static void main(String[] args) {
        Visitor visitor = new ConcreteVisitor();
        StringElement se = new StringElement("abc");
        se.accept(visitor);
        FloatElement fe = new FloatElement(new Float(1.5));
        fe.accept(visitor);
        System.out.println("===========");
        List result = new ArrayList();
        result.add(new StringElement("abc"));
        result.add(new StringElement("abc"));
        result.add(new StringElement("abc"));
        result.add(new FloatElement(new Float(1.5)));
        result.add(new FloatElement(new Float(1.5)));
        result.add(new FloatElement(new Float(1.5)));
        visitor.visitCollection(result);
    }
}
```
####Result
```
abc
1.5
===========
abc
abc
abc
1.5
1.5
1.5
```
##下期预告:
连copy带编,也写了很多了,本来打算把Asm的也写完,但这篇文章太长,那就下期再写吧。先休息一会。再会。
相关文章
|
3月前
|
SQL Java
访问者模式问题之在ASM中,实现一个访问者来删除指定的类属性,如何解决
访问者模式问题之在ASM中,实现一个访问者来删除指定的类属性,如何解决
|
设计模式 安全 Java
访问者模式与ASM的不解之缘(二)
上次介绍了访问者模式的适用范围与设计思路,这次接着上篇文章继续补充ASM的内容。
访问者模式与ASM的不解之缘(二)
|
6月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
328 2
|
30天前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
6月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
284 0
|
文字识别 Oracle NoSQL
oracle 11g 单机asm配置
oracle 11g 单机asm配置
658 0
|
Oracle 关系型数据库
❤️Oracle ASM加磁盘及剔盘操作❤️
❤️Oracle ASM加磁盘及剔盘操作❤️
329 0
|
存储 机器学习/深度学习 Oracle
Oracle 11gR2 ASM存储日常管理手册
Oracle 11gR2 ASM存储日常管理手册 目 录1 文档简介 31.1 编写目的 31.2 适用范围 31.3 名词解释 31.4 格式约定 42 配置多链路和LUN 42.
1137 0
|
Oracle 关系型数据库
oracle Grid 是如何找到voteidks和asm spfile.
oracle Grid 是如何找到voteidks和asm spfile.
1541 0