大发快三_快三规则_大发快三规则 - 大发快三,快三规则,大发快三规则精选头条好文,分享实用生活小技巧,达人购物经验,包括科技、手机、数码、娱乐、美容、母婴、旅行、居家等内容,打造优质阅读体验。

《JAVA与模式》之访问者模式

  • 时间:
  • 浏览:1

在阎宏博士的《JAVA与模式》一书中开头是所以描述访问者(Visitor)模式的:

  访问者模式是对象的行为模式。访问者模式的目的是封装其他施加于有一种 数据社会形态元素之上的操作。一旦哪哪几个操作还要修改句子,接受这个操作的数据社会形态则可不不都都能否保持不变。

  变量被声明时的类型叫做变量的静态类型(Static Type),其他人又把静态类型叫做明显类型(Apparent Type);而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type)。比如:

List list = null;
list = new ArrayList();

  声明了有有有另一个变量list,它的静态类型(也叫明显类型)是List,而它的实际类型是ArrayList。

  根据对象的类型而对法律方法进行的确定,所以采集(Dispatch),采集(Dispatch)又分为有一种 ,即静态采集动态采集

  静态采集(Static Dispatch)处在在编译时期,采集根据静态类型信息处在。静态采集对于亲们儿来说何必 陌生,法律方法重载所以静态采集。

  动态采集(Dynamic Dispatch)处在在运行时期,动态采集动态地置换掉某个法律方法。

 静态采集

  Java通过法律方法重载支持静态采集。用墨子骑马的故事作为例子,墨子可不不都都能否骑白马将会黑马。墨子与白马、黑马和马的类图如下所示:

  在这个系统中,墨子由Mozi类代表

public class Mozi {
    
    public void ride(Horse h){
        System.out.println("骑马");
    }
    
    public void ride(WhiteHorse wh){
        System.out.println("骑白马");
    }
    
    public void ride(BlackHorse bh){
        System.out.println("骑黑马");
    }
    
    public static void main(String[] args) {
        Horse wh = new WhiteHorse();
        Horse bh = new BlackHorse();
        Mozi mozi = new Mozi();
        mozi.ride(wh);
        mozi.ride(bh);
    }

}

  显然,Mozi类的ride()法律方法是由有有有另一个法律方法重载而成的。这有有有另一个法律方法分别接受马(Horse)、白马(WhiteHorse)、黑马(BlackHorse)等类型的参数。

  那么在运行时,应用程序池池会打印出哪哪几个结果呢?结果是应用程序池池会打印出相同的两行“骑马”。换言之,墨子发现他所骑的有的是马。

  为哪哪几个呢?两次对ride()法律方法的调用传入的是不同的参数,也所以wh和bh。它们真是具有不同的真实类型,所以它们的静态类型有的是一样的,均是Horse类型。

  重载法律方法的采集是根据静态类型进行的,这个采集过程在编译时期就完成了。

 动态采集

  Java通过法律方法的重写支持动态采集。用马吃草的故事作为例子,代码如下所示:

public class Horse {
    
    public void eat(){
        System.out.println("马吃草");
    }
}
public class BlackHorse extends Horse {
    
    @Override
    public void eat() {
        System.out.println("黑马吃草");
    }
}
public class Client {

    public static void main(String[] args) {
        Horse h = new BlackHorse();
        h.eat();
    }

}

  变量h的静态类型是Horse,而真实类型是BlackHorse。将会中间最后一行的eat()法律方法调用的是BlackHorse类的eat()法律方法,那么中间打印的所以“黑马吃草”;相反,将会中间的eat()法律方法调用的是Horse类的eat()法律方法,那么打印的所以“马吃草”。

  所以,现象的核心所以Java编译器在编译时期何必 总是知道哪哪几个代码会被执行,将会编译器仅仅知道对象的静态类型,而别问我对象的真实类型;而法律方法的调用则是根据对象的真实类型,而有的是静态类型。所以一来,中间最后一行的eat()法律方法调用的是BlackHorse类的eat()法律方法,打印的是“黑马吃草”。

 采集的类型

  有有有另一个法律方法所属的对象叫做法律方法的接收者,法律方法的接收者与法律方法的参数统称做法律方法的宗量。比如下面例子中的Test类

public class Test {

    public void print(String str){
        System.out.println(str);
    }
}

  在中间的类中,print()法律方法属于Test对象,所以它的接收者也所以Test对象了。print()法律方法有有有有另一个参数是str,它的类型是String。

  根据采集可不不都都能否基于哪几个种宗量,可不不都都能否将面向对象的语言划分为单采集语言(Uni-Dispatch)和多采集语言(Multi-Dispatch)。单采集语言根据有有有另一个宗量的类型进行对法律方法的确定,多采集语言根据多于有有有另一个的宗量的类型对法律方法进行确定。

  C++和Java均是单采集语言,多采集语言的例子包括CLOS和Cecil。按照所以的区分,Java所以动态的单采集语言,将会这个语言的动态采集仅仅会考虑到法律方法的接收者的类型,一齐又是静态的多采集语言,将会这个语言对重载法律方法的采集会考虑到法律方法的接收者的类型以及法律方法的所有参数的类型。

  在有有有另一个支持动态单采集的语言中间,有有有有另一个条件决定了有有有另一个请求会调用哪有有有另一个操作:一是请求的名字,所以接收者的真实类型。单采集限制了法律方法的确定过程,使得只能有有有另一个宗量可不不都都能否被考虑到,这个宗量通常所以法律方法的接收者。在Java语言中间,将会有有有另一个操作是作用于某个类型不明的对象中间,那么对这个对象的真实类型测试仅会处在一次,这所以动态的单采集的社会形态。

 双重采集

  有有有另一个法律方法根据有有有另一个宗量的类型来决定执行不同的代码,这所以“双重采集”。Java语言不支持动态的多采集,也就由于着着Java不支持动态的双采集。所以通过使用设计模式,也可不不都都能否在Java语言里实现动态的双重采集。

  在Java中可不不都都能否通过两次法律方法调用来达到两次采集的目的。类图如下所示:

  在图带有有有有另一个对象,左边的叫做West,右边的叫做East。现在West对象首先调用East对象的goEast()法律方法,并将它当事人传入。在East对象被调用时,立即根据传入的参数知道了调用者是谁,于是反过来调用“调用者”对象的goWest()法律方法。通过两次调用将应用程序池池控制权轮番交给有有有另一个对象,其时序图如下所示:

  所以就冒出了两次法律方法调用,应用程序池池控制权被有有有另一个对象像传球一样,首先由West对象传给了East对象,所以又被返传给了West对象。

  所以仅仅返传了一下球,何必 能补救双重采集的现象。关键是怎样才能利用这两次调用,以及Java语言的动态单采集功能,使得在这个传球的过程中,不不都都能否触发两次单采集。

  动态单采集在Java语言中是在子类重写父类的法律方法时处在的。换言之,West和East都还要分别置身于当事人的类型等级社会形态中,如下图所示:

  源代码

  West类

public abstract class West {
    
    public abstract void goWest1(SubEast1 east);
    
    public abstract void goWest2(SubEast2 east);
}

  SubWest1类

public class SubWest1 extends West{
    
    @Override
    public void goWest1(SubEast1 east) {
        
        System.out.println("SubWest1 + " + east.myName1());
    }
    
    @Override
    public void goWest2(SubEast2 east) {
        
        System.out.println("SubWest1 + " + east.myName2());
    }
}

  SubWest2类

public class SubWest2 extends West{
    @Override
    public void goWest1(SubEast1 east) {
        
        System.out.println("SubWest2 + " + east.myName1());
    }
    
    @Override
    public void goWest2(SubEast2 east) {
        
        System.out.println("SubWest2 + " + east.myName2());
    }
}

  East类

public abstract class East {

    public abstract void goEast(West west);
}

  SubEast1类

public class SubEast1 extends East{
    @Override
    public void goEast(West west) {
        west.goWest1(this);
    }
    
    public String myName1(){
        return "SubEast1";
    }
}

  SubEast2类

public class SubEast2 extends East{
    @Override
    public void goEast(West west) {
        west.goWest2(this);
    }
    
    public String myName2(){
        return "SubEast2";
    }
}

  客户端类

public class Client {

    public static void main(String[] args) {
        //组合1
        East east = new SubEast1();
        West west = new SubWest1();
        east.goEast(west);
        //组合2
        east = new SubEast1();
        west = new SubWest2();
        east.goEast(west);
    }

}

  运行结果如下


SubWest1 + SubEast1

SubWest2 + SubEast1


  系统运行时,会首先创建SubWest1和SubEast1对象,所以客户端调用SubEast1的goEast()法律方法,并将SubWest1对象传入。将会SubEast1对象重写了其超类East的goEast()法律方法,所以,这个然后就处在了一次动态的单采集。当SubEast1对象接到调用时,会从参数中得到SubWest1对象,所以它就立即调用这个对象的goWest1()法律方法,并将当事人传入。将会SubEast1对象有权确定调用哪有有有另一个对象,所以,在此时又进行一次动态的法律方法采集。

  这个然后SubWest1对象就得到了SubEast1对象。通过调用这个对象myName1()法律方法,就可不不都都能否打印出当事人的名字和SubEast对象的名字,其时序图如下所示:

  将会这有有有另一个名字有有有另一个来自East等级社会形态,所以来自West等级社会形态中,所以,它们的组合式是动态决定的。这所以动态双重采集的实现机制。

  访问者模式适用于数据社会形态相对未定的系统,它把数据社会形态和作用于社会形态上的操作之间的耦合解脱开,使得操作集合可不不都都能否相对自由地演化。访问者模式的简略图如下所示:

  数据社会形态的每有有有另一个节点都可不不都都能否接受有有有另一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。所以的过程叫做“双重采集”。节点调用访问者,将它当事人传入,访问者则将某算法针对此节点执行。访问者模式的示意性类图如下所示:

  

  访问者模式涉及到的角色如下:

  ●  抽象访问者(Visitor)角色:声明了有有有另一个将会多个法律方法操作,形成所有的具体访问者角色还要实现的接口。

  ●  具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也所以抽象访问者所声明的各个访问操作。

  ●  抽象节点(Node)角色:声明有有有另一个接受操作,接受有有有另一个访问者对象作为有有有另一个参数。

  ●  具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。

  ●  社会形态对象(ObjectStructure)角色:有如下的责任,可不不都都能否遍历社会形态中的所有元素;将会还要,提供有有有另一个高层次的接口让访问者对象可不不都都能否访问每有有有另一个元素;将会还要,可不不都都能否设计成有有有另一个复合对象将会有有有另一个聚集,如List或Set。

  源代码

  可不不都都能否看一遍,抽象访问者角色为每有有有另一个具体节点都准备了有有有另一个访问操作。将会有有有有另一个节点,所以,对应有的是有有有另一个访问操作。

public interface Visitor {
    /**
     * 对应于NodeA的访问操作
     */
    public void visit(NodeA node);
    /**
     * 对应于NodeB的访问操作
     */
    public void visit(NodeB node);
}

  具体访问者VisitorA类

public class VisitorA implements Visitor {
    /**
     * 对应于NodeA的访问操作
     */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
     * 对应于NodeB的访问操作
     */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }

}

  具体访问者VisitorB类

public class VisitorB implements Visitor {
    /**
     * 对应于NodeA的访问操作
     */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
     * 对应于NodeB的访问操作
     */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }

}

  抽象节点类

public abstract class Node {
    /**
     * 接受操作
     */
    public abstract void accept(Visitor visitor);
}

  具体节点类NodeA

public class NodeA extends Node{
    /**
     * 接受操作
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
     * NodeA特有的法律方法
     */
    public String operationA(){
        return "NodeA";
    }

}

  具体节点类NodeB

public class NodeB extends Node{
    /**
     * 接受法律方法
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
     * NodeB特有的法律方法
     */
    public String operationB(){
        return "NodeB";
    }
}

  社会形态对象角色类,这个社会形态对象角色持有有有有另一个聚集,并向外界提供add()法律方法作为对聚集的管理操作。通过调用这个法律方法,可不不都都能否动态地增加有有有另一个新的节点。

public class ObjectStructure {
    
    private List<Node> nodes = new ArrayList<Node>();
    
    /**
     * 执行法律方法操作
     */
    public void action(Visitor visitor){
        
        for(Node node : nodes)
        {
            node.accept(visitor);
        }
        
    }
    /**
     * 添加有有有另一个新元素
     */
    public void add(Node node){
        nodes.add(node);
    }
}

  客户端类

public class Client {

    public static void main(String[] args) {
        //创建有有有另一个社会形态对象
        ObjectStructure os = new ObjectStructure();
        //给社会形态增加有有有另一个节点
        os.add(new NodeA());
        //给社会形态增加有有有另一个节点
        os.add(new NodeB());
        //创建有有有另一个访问者
        Visitor visitor = new VisitorA();
        os.action(visitor);
    }

}

  真是在这个示意性的实现里并那么冒出有有有另一个繁杂的具有多个树枝节点的对象树社会形态,所以,在实际系统中访问者模式通常是用来补救繁杂的对象树社会形态的,所以访问者模式可不不都都能否用来补救跨太满个等级社会形态的树社会形态现象。这正是访问者模式的功能强大之处。

  准备过程时序图

  首先,这个示意性的客户端创建了有有有另一个社会形态对象,所以将有有有另一个新的NodeA对象和有有有另一个新的NodeB对象传入。

  其次,客户端创建了有有有另一个VisitorA对象,并将此对象传给社会形态对象。

  所以,客户端调用社会形态对象聚集管理法律方法,将NodeA和NodeB节点加入到社会形态对象中去。

  最后,客户端调用社会形态对象的行动法律方法action(),启动访问过程。

  

  访问过程时序图

  

  社会形态对象会遍历它当事人所保存的聚集中的所有节点,在本系统中所以节点NodeA和NodeB。首先NodeA会被访问到,这个访问是由以下的操作组成的:

  (1)NodeA对象的接受法律方法accept()被调用,并将VisitorA对象有一种 传入;

  (2)NodeA对象反过来调用VisitorA对象的访问法律方法,并将NodeA对象有一种 传入;

  (3)VisitorA对象调用NodeA对象的特有法律方法operationA()。

  从而就完成了双重采集过程,接着,NodeB会被访问,这个访问的过程和NodeA被访问的过程是一样的,这里不再叙述。

  ●  好的扩展性

  不不都都能否在不修改对象社会形态中的元素的情况汇报下,为对象社会形态中的元素添加新的功能。

  ●  好的复用性

  可不不都都能否通过访问者来定义整个对象社会形态通用的功能,从而提高复用程度。

  ●  分离无关行为

  可不不都都能否通过访问者来分离无关的行为,把相关的行为封装入 一齐,构成有有有另一个访问者,所以每有有有另一个访问者的功能都比较单一。

  ●  对象社会形态变化很困难

  不适用于对象社会形态中的类总是变化的情况汇报,将会对象社会形态处在了改变,访问者的接口和访问者的实现有的是处在相应的改变,代价太高。

  ●  破坏封装

  访问者模式通常还要对象社会形态开放内部人员数据给访问者和ObjectStructrue,这破坏了对象的封装性。