5

初识设计模式 - 访问者模式 - 程序员翔仔

 1 year ago
source link: https://www.cnblogs.com/fatedeity/p/16875853.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

初识设计模式 - 访问者模式

访问者设计模式(Visitor Design Pattern)的定义是,允许一个或多个操作应用到一组对象上,解耦操作和对象本身。

在使用访问者模式的时候,被访问的元素通常不是单独存在的,它们存储在一个集合中,这个集合称为“对象结构”,访问者通过遍历对象结构实现对其存储的元素进行逐个访问。

访问者模式使用了“双重分派”的调用机制,即元素对象定义一个操作方法支持注入访问者对象,在操作方法内调用访问者的访问方法,并将当前元素对象传入到访问方法中。

在这里举一个工作当中的具体例子,在小公司的项目组当中,名义上区分了开发、测试等岗位,但实际上开发人员既要会开发,也有会测试,对于测试人员也是同样的要求,既要会测试,也要会开发。

在这里案例当中,开发人员、测试人员统称为元素,我们在这里先构建一个抽象的元素类。其代码示例如下:

public interface Element { // 定义一个接受访问者访问的抽象方法 void accept(Visitor visitor);}

对于开发人员类,根据自己的情况实现这个 accept() 方法,其代码如下:

public class Programmer implements Element { private String name = "开发人员"; public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public void accept(Visitor visitor) { visitor.visitProgrammer(this); }}

对于测试人员,根据自己的情况实现这个 accept() 方法,其代码如下:

public class Tester implements Element { private String name = "测试人员"; public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public void accept(Visitor visitor) { visitor.visitTester(this); }}

第二步,最重要的就是要定义好一个访问者类,在这里抽象出的访问者接口可以是以项目组为范围,为项目组中的每一个元素定义对应的访问方法。其代码示例如下:

public interface Visitor { void visitProgrammer(Programmer programmer); void visitTester(Tester tester);}

每当出现一个新的操作时,就可以实现访问者接口,注入不同的元素对象以实现不同的操作。

如下是开发人员和测试人员使用开发技能的代码示例:

public class DevelopVisitor implements Visitor { @Override public void visitProgrammer(Programmer programmer) { System.out.println(programmer.getName() + "在开发"); } @Override public void visitTester(Tester tester) { System.out.println(tester.getName() + "在开发"); }}

如下是开发人员和测试人员使用测试技能的代码示例:

public class TestVisitor implements Visitor { @Override public void visitProgrammer(Programmer programmer) { System.out.println(programmer.getName() + "在测试"); } @Override public void visitTester(Tester tester) { System.out.println(tester.getName() + "在测试"); }}

访问者模式的主要优点如下:

  • 能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能,符合开闭原则
  • 将有关元素的行为都封装到一个访问者对象中,每个访问者对象的功能都比较单一,符合单一职责原则

访问者模式的主要缺点如下:

  • 增加新的元素类需要在每一个访问者类中都增加相应的具体操作,这违背了开闭原则
  • 访问者对象可以访问并调用每一个元素对象的操作,这意味着元素对象有时候会暴露一些内部操作和内部状态,破坏了封装
  • 访问者模式依赖了具体类,而没有依赖抽象类,违反了依赖倒置原则

访问者模式的适用场景如下:

  • 对象结构中元素对象的类很少改变,但经常需要在此对象结构上定义新的操作

访问者模式提供一个方便的可维护的方式来操作一组对象,JDK 内置了这样的元素接口和访问者接口。

如下是元素接口 javax.lang.model.element.Element 的部分代码:

public interface Element extends javax.lang.model.AnnotatedConstruct { <R, P> R accept(ElementVisitor<R, P> v, P p);}

如下是访问者接口 javax.lang.model.element.ElementVisitor 的部分代码:

public interface ElementVisitor<R, P> { R visit(Element e, P p); default R visit(Element e) { return visit(e, null); }}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK