深入浅出Java访问者模式:定义、结构与应用实例详解

深入介绍Java的访问者模式 1.简介 对于系统中一个完整的类层次结构,我们为其提供了满足需要的接口。但面对新增加的需求我们该怎么办?如果这些是少数更改之一,并且您不需要修改整个类层次结构来适应需求,那么直接修改原始类层次结构可能是一个好主意。但我们经常遇到的是:这样的需求变化可能会不断发生;更重要的是,任何需求的改变都可能需要你把整个类层次结构颠倒修改……这种类似的操作分布在不同的类中,这可不是一个好现象。我们需要重建这个结构。那么,访客模式可能是您不错的选择。 2. 访问者模式的定义和结构。顾名思义,使用此模式后,您可以通过添加额外的“访问者”来改进现有代码的功能,而无需修改现有的程序结构。 《设计模式》一书将访问者模式定义为:表示作用于对象结构中每个元素的操作。它允许您定义作用于每个元素的新操作,而无需更改其类。从定义中可以看出,结构体对象是使用访问者模式的必要条件,并且这个结构体对象必须具有遍历其自身对象的方法。这类似于Java中的集合概念。以下是访问者模式的结构: 1)访问者角色(Visitor):为对象结构中的特定元素角色声明访问操作接口。

深入浅出Java访问者模式:定义、结构与应用实例详解

操作接口的名称和参数标识了向特定访问者发送访问请求的特定元素角色。这允许访问者通过该元素角色的特定界面直接访问它。 2)具体访问者角色(ConcreteVisitor):实现访问者角色(Visitor)声明的各个操作。 3)元素角色(Element):定义一个Accept操作,该操作以访问者为参数。 4)具体元素角色(ConcreteElement):实现元素角色提供的Accept操作。 5)对象结构角色(ObjectStructure):这是使用访问者模式所必需的角色。它必须具有以下特征:它可以枚举其元素;它可以提供高级接口以允许访问者访问其元素;它可以是复合(组合模式)或集合,例如列表或无序集合。通过类图,您可以更清楚地看到访问者模式的结构。正如简介中想象的那样。我们应该怎么做才能让访客模式发挥作用?首先我们需要将accept方法添加到原始类层次结构中。然后将这个类层次结构中的类放入一个对象结构中。然后创建访问者角色... 3. 示例 importjava.util.*;importjunit.Framework.*;//访问者角色 interfaceVisitor{voidvisit(Gladiolusg);voidvisit(Runuculusr);voidvisit(Chrysanthemumc);}//TheFlowerhierarchy 不能更改: //元素角色interfaceFlower{voidaccept(Visitorv);}//以下三个具体元素角色classGladiolusimplementsFlower{publicvoidaccept(Visitorv){v.visit(this);}} classRunuculusimplementsFlower{publicvo idaccept(Visitorv){v.visit(this);}}classChrysanthemumimplementsFlower{publicvoidaccept(Visitorv){v.visit(this);}}/ /Addtheabilityto Produceastring://实现的特定访客角色classStringValimplemen tsVisitor{Strings;publicStringtoString(){returns;}publicvoidvisit(Gladiolusg){s="Gladiolus";}publicvoidvisit(Runuculusr){s="Runuculus";}publicvoidvisit(Chrysanthemumc){s="Chrysanth emum";}} //Addtheabilitytodo"Bee"activities://另一个特定访客角色classBeeimplementsVisitor{publicvoidvisit(Gladiolusg){System.out.println("BeeandGladiolus");}publicvoidvisit(Runuculusr){Sys tem.out.println("BeeandRunuculus");}publicvoidvisit(Chrysanthemumc){System.out.println("BeeandChrysanthemum ");}}//这是一个对象Generator//这不是一个完整的对象结构,这里只是模拟对象结构中的元素classFlowerGenerator{privat estaticRandomrand=newRandom();publicstaticFlowernewFlower(){switch(rand.nextInt(3)){default:case0:returnnewGladiolus ();case1:returnnewRunuculus();case2:returnnewChrysanthemum();}}} //客户测试程序 publicclassBeeAndFlowersextendsTestCase{/*这里可以看到访问者模式执行的流程:首先获取客户端的具体访问者角色,遍历对象结构体,对每个元素调用accept方法,将具体访问者角色传入整个过程就完成了*///这里组装了对象结构体角色Listflowers=newArrayList();public BeeAndFlowers() { for(int i = 0;我<10; i++)flowers.add(FlowerGenerator.newFlower()); }访客sval; public void test() { // 这几乎就像我有一个函数来 // 生成 Flower 字符串表示形式: // 您可以修改此位置以使用另一个特定访问者角色 sval = new StringVal();迭代器 it = Flowers.iterator(); while(it.hasNext()) { ((Flower)it.next()).accept(sval); System.out.println(sval); } }public static void main(String args[]) {junit.textui .TestRunner.run(BeeAndFlowers.class); }} 4.双重调度:首先将具体的访问者模式作为参数传递给客户端程序中的具体元素角色(如高亮区域所示)。

这样就完成了一次调度。进入特定元素角色后,特定元素角色以参数的形式调用特定访问者模式下的visitor方法,并传入自身(this)作为参数。然后,特定访问者模式根据不同的参数选择要执行的方法(如突出显示的区域所示)。这样就完成了第二次分发。 5、优点、缺点和适用性首先我们看一下使用访客模式是否可以避免介绍中的痛苦。使用访问者模式后,要在原有的类层次结构中添加新的操作,只需要实现特定的访问者角色,而不需要修改整个类层次结构。这符合“开闭原则”的要求。并且每个特定的访问者角色都对应一个相关的操作,因此如果某个操作的需求发生变化,只需要修改一个特定的访问者角色,而不需要改变整个类层次结构。看来访客模式确实可以解决我们面临的一些问题。而且由于访问者模式为我们的系统提供了额外的“访问者”层,因此我们可以在访问者中的元素角色上添加一些额外的操作。然而,遵循“开闭原则”总是片面的。如果系统中的类层次结构发生变化,会对访问者模式产生什么影响?你必须修改访客角色和每个特定访客角色……看来访客角色不太适合特定元素角色频繁变化的情况。而且,为了让访问者角色执行与元素角色相关的操作,元素角色必须暴露其内部属性,这在Java中意味着其他对象也可以访问它。

这破坏了元素角色的封装。而且,在访问者模式下,元素和访问者之间可以传递的信息是有限的,这往往限制了访问者模式的使用。 《设计模式》一书给出了访问者模式适用的情况: 1)一个对象结构包含很多类对象,它们有不同的接口,并且你想对这些对象执行一些依赖于它们特定类的操作。 2)需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免这些操作“污染”这些对象的类。 Visitor 允许您将相关操作分组并在类中定义它们。 3)当对象结构被多个应用程序共享时,使用Visitor模式,让每个应用程序只包含自己需要的操作。 4)定义对象结构的类很少改变,但经常需要在这个结构上定义新的操作。更改对象结构类需要为所有访问者重新定义接口,这可能成本高昂。如果您的对象结构类经常更改,那么最好在这些类中定义这些操作。 6.总结 这是一种巧妙而复杂的模式,其使用条件也比较苛刻。当系统中存在固定的数据结构(如上面的类层次结构)且行为不同时,那么访问者模式可能是一个不错的选择。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

26阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

26阅读