电子说
访问者设计模式是一种行为型设计模式,用于将算法与对象结构分离。它允许你在不改变对象结构的前提下定义新的操作。
访问者模式的作用是在不改变对象结构的前提下定义新的操作。它允许你定义一个新的操作,而无需修改现有的对象结构。在访问者模式中,我们将操作封装在访问者对象中,并在元素对象上调用访问者对象的方法,从而实现对元素对象的操作。
访问者模式适用于以下场景:
•对象结构稳定,但是经常需要在此结构上定义新的操作;•需要对复杂对象结构中的对象进行操作,而且这些对象可能具有不同的类型;•需要在不改变对象结构的前提下,为对象结构中的元素对象动态添加新的操作。
抽象访问者(Visitor)定义了访问者可以访问的元素对象的接口。它包含了多个 visit() 方法,每个方法对应一个具体元素对象。
publicinterfaceVisitor{
void visit(ConcreteElementA elementA);
void visit(ConcreteElementB elementB);
}
在上述代码中,我们定义了一个抽象访问者接口 Visitor,它包含了两个 visit() 方法,分别对应具体元素对象 ConcreteElementA 和 ConcreteElementB。
具体访问者(ConcreteVisitor)实现了抽象访问者接口,对不同类型的元素对象进行具体的操作。
publicclassConcreteVisitorAimplementsVisitor{
@Override
publicvoid visit(ConcreteElementA elementA){
System.out.println("ConcreteVisitorA visit ConcreteElementA");
}
@Override
publicvoid visit(ConcreteElementB elementB){
System.out.println("ConcreteVisitorA visit ConcreteElementB");
}
}
publicclassConcreteVisitorBimplementsVisitor{
@Override
publicvoid visit(ConcreteElementA elementA){
System.out.println("ConcreteVisitorB visit ConcreteElementA");
}
@Overridepublicvoid visit(ConcreteElementB elementB){
System.out.println("ConcreteVisitorB visit ConcreteElementB");
}
}
在上述代码中,我们定义了两个具体访问者类 ConcreteVisitorA 和 ConcreteVisitorB,它们分别实现了抽象访问者接口 Visitor,并对不同类型的元素对象进行具体的操作。
抽象元素(Element)定义了元素对象的接口,让访问者对象可以访问自己的元素对象。
publicinterfaceElement{
void accept(Visitor visitor);
}
在上述代码中,我们定义了一个抽象元素接口 Element,它包含了一个 accept() 方法,该方法接收一个访问者对象作为参数。
具体元素(ConcreteElement)实现了抽象元素接口,定义了自己的 accept() 方法,该方法调用访问者对象的 visit() 方法,并将自身作为参数传入。
publicclassConcreteElementAimplementsElement{
@Override
publicvoid accept(Visitor visitor){
visitor.visit(this);
}
}
publicclassConcreteElementBimplementsElement{
@Override
publicvoid accept(Visitor visitor){
visitor.visit(this);
}
}
在上述代码中,我们定义了两个具体元素类 ConcreteElementA 和 ConcreteElementB,它们分别实现了抽象元素接口 Element,并在 accept() 方法中调用访问者对象的 visit() 方法,并将自身作为参数传入。
对象结构(Object Structure)是元素对象的集合,它提供了一个接口,让访问者对象可以访问集合中的元素对象。
publicclassObjectStructure{
privateList< Element > elements =newArrayList< >();
publicvoid attach(Element element){
elements.add(element);
}
publicvoid detach(Element element){
elements.remove(element);
}
publicvoid accept(Visitor visitor){
for(Element element : elements){
element.accept(visitor);
}
}
}
在上述代码中,我们定义了一个对象结构类 ObjectStructure,它包含了一个元素对象的集合 elements,提供了 attach() 和 detach() 方法,用于添加和删除元素对象。它还提供了一个 accept() 方法,该方法遍历元素对象集合,并调用每个元素对象的accept() 方法,将访问者对象作为参数传入。
publicinterfaceElement{
void accept(Visitor visitor);
}
publicclassConcreteElementAimplementsElement{
@Override
publicvoid accept(Visitor visitor){
visitor.visit(this);
}
}
publicclassConcreteElementBimplementsElement{
@Override
publicvoid accept(Visitor visitor){
visitor.visit(this);
}
}
publicinterfaceVisitor{
void visit(ConcreteElementA elementA);
void visit(ConcreteElementB elementB);
}
publicclassConcreteVisitorAimplementsVisitor{
@Override
publicvoid visit(ConcreteElementA elementA){
System.out.println("ConcreteVisitorA visit ConcreteElementA");
}
@Override
publicvoid visit(ConcreteElementB elementB){
System.out.println("ConcreteVisitorA visit ConcreteElementB");
}
}
publicclassConcreteVisitorBimplementsVisitor{
@Override
publicvoid visit(ConcreteElementA elementA){
System.out.println("ConcreteVisitorB visit ConcreteElementA");
}
@Override
publicvoid visit(ConcreteElementB elementB){
System.out.println("ConcreteVisitorB visit ConcreteElementB");
}
}
publicclassObjectStructure{
privateList< Element > elements =newArrayList< >();
publicvoid attach(Element element){
elements.add(element);
}
publicvoid detach(Element element){
elements.remove(element);
}
publicvoid accept(Visitor visitor){
for(Element element : elements){
element.accept(visitor);
}
}
}
publicclassClient{
publicstaticvoid main(String[] args){
ObjectStructure objectStructure =newObjectStructure();
objectStructure.attach(newConcreteElementA());
objectStructure.attach(newConcreteElementB());
Visitor visitorA =newConcreteVisitorA();
Visitor visitorB =newConcreteVisitorB();
objectStructure.accept(visitorA);
objectStructure.accept(visitorB);
}
}
在上述代码中,我们创建了一个对象结构 objectStructure,并向其中添加了两个元素对象 ConcreteElementA 和 ConcreteElementB。然后,我们创建了两个具体访问者对象 visitorA 和 visitorB,并调用 objectStructure 的 accept() 方法,将这两个访问者对象作为参数传入。在 accept() 方法中,我们遍历元素对象集合 elements,并依次调用每个元素对象的 accept() 方法,将访问者对象作为参数传入。
访问者设计模式的优点包括:
•可以在不改变对象结构的前提下定义新的操作;•可以将代码的稳定性和易于扩展性相结合;•可以使得增加新的操作变得简单。
访问者设计模式的缺点包括:
•增加新的元素对象比较困难;•元素对象的访问者接口必须稳定,否则会导致所有访问者对象都需要进行修改;•具体元素对象对访问者对象的访问是单向的,访问者对象无法访问元素对象的其他方法。
在访问者设计模式中,我们可以通过双重分派来实现不同的操作。双重分派是指在访问者对象中定义了多个具体的 visit() 方法,每个方法对应一个具体元素对象,然后在元素对象中调用访问者对象的 visit() 方法,并将自身作为参数传入。
双重分派的实现方式是通过重载 accept() 方法来实现的。具体来说,我们在抽象元素接口 Element 中定义多个 accept() 方法,每个方法对应一个具体访问者对象,并在具体元素对象中重载这些 accept() 方法,将具体访问者对象作为参数传入。
下面是一个双重分派的示例代码:
publicinterfaceElement{
void accept(Visitor visitor);
void accept(Visitor visitor,String param);
}
publicclassConcreteElementAimplementsElement{
@Override
publicvoid accept(Visitor visitor){
visitor.visit(this);
}
@Override
publicvoid accept(Visitor visitor,String param){
visitor.visit(this, param);
}
}
publicinterfaceVisitor{
void visit(ConcreteElementA elementA);
void visit(ConcreteElementB elementB);
void visit(ConcreteElementA elementA,String param);
}
publicclassConcreteVisitorAimplementsVisitor{
@Override
publicvoid visit(ConcreteElementA elementA){
System.out.println("ConcreteVisitorA visit ConcreteElementA");
}
@Override
publicvoid visit(ConcreteElementB elementB){
System.out.println("ConcreteVisitorA visit ConcreteElementB");
}
@Override
publicvoid visit(ConcreteElementA elementA,String param){
System.out.println("ConcreteVisitorA visit ConcreteElementA with param "+ param);
}
}
publicclassConcreteVisitorBimplementsVisitor{
@Override
publicvoid visit(ConcreteElementA elementA){
System.out.println("ConcreteVisitorB visit ConcreteElementA");
}
@Override
publicvoid visit(ConcreteElementB elementB){
System.out.println("ConcreteVisitorB visit ConcreteElementB");
}
@Override
publicvoid visit(ConcreteElementA elementA,String param){
System.out.println("ConcreteVisitorB visit ConcreteElementA with param "+ param);
}
}
publicclassObjectStructure{
privateList< Element > elements =newArrayList< >();
publicvoid attach(Element element){
elements.add(element);
}
publicvoid detach(Element element){
elements.remove(element);
}
publicvoid accept(Visitor visitor){
for(Element element : elements){
element.accept(visitor);
}
}
publicvoid accept(Visitor visitor,String param){
for(Element element : elements){
element.accept(visitor, param);
}
}
}
publicclassClient{
publicstaticvoid main(String[] args){
ObjectStructure objectStructure =newObjectStructure();
objectStructure.attach(newConcreteElementA());
objectStructure.attach(newConcreteElementB());
Visitor visitorA =newConcreteVisitorA();
Visitor visitorB =newConcreteVisitorB();
objectStructure.accept(visitorA);
objectStructure.accept(visitorB);
objectStructure.accept(visitorA,"paramA");
objectStructure.accept(visitorB,"paramB");
}
}