设计模式学习笔记——访问者(Visitor)模式

    xiaoxiao2021-03-27  37

    设计模式学习笔记——访问者(Visitor)模式

    @(设计模式)[设计模式, 访问者模式, visitor]

    设计模式学习笔记访问者Visitor模式 基本介绍访问者案例 类图实现代码 Visitor抽象类ListVisitor类Element接口Entry抽象类File类Directory类FileTreatmentException类测试类运行结果 访问者模式中的角色 Visitor访问者ConcreteVisitor具体的访问者Element元素ConcreteElementObjectStructure对象结构类图

    基本介绍

    访问者模式主要的作用是对对象中元素进行操作。 使用访问者模式,在更改对元素的操作时,不需要更改类的定义。

    访问者案例

    类图

    实现代码

    Visitor抽象类

    package com.pc.visitor.example; /** * 访问者抽象类 * Created by Switch on 2017-02-22. */ public abstract class Visitor { /** * 访问文件 * * @param file 文件对象 */ public abstract void visit(File file); /** * 访问文件夹 * * @param directory 文件夹对象 */ public abstract void visit(Directory directory); }

    ListVisitor类

    package com.pc.visitor.example; import java.util.Iterator; /** * 列表访问类 * Created by Switch on 2017-02-22. */ public class ListVisitor extends Visitor { /** * 当前访问的文件夹的名字 */ private String currentDir = ""; @Override public void visit(File file) { System.out.println(this.currentDir + "/" + file); } @Override public void visit(Directory directory) { System.out.println(currentDir + "/" + directory); // 递归调用,回溯法 String saveDir = this.currentDir; this.currentDir = this.currentDir + "/" + directory.getName(); Iterator<Entry> iterator = directory.iterator(); while (iterator.hasNext()) { Entry entry = iterator.next(); entry.accept(this); } this.currentDir = saveDir; } }

    Element接口

    package com.pc.visitor.example; /** * 元素接口(代表可以接受访问) * Created by Switch on 2017-02-22. */ public interface Element { /** * 接受访问者对象访问 * * @param visitor 访问者对象 */ void accept(Visitor visitor); }

    Entry抽象类

    package com.pc.visitor.example; /** * 条目抽象类 * Created by Switch on 2017-02-21. */ public abstract class Entry implements Element { /** * 获取名字 * * @return 名字 */ public abstract String getName(); /** * 获取占用空间 * * @return 占用空间 */ public abstract int getSize(); /** * 添加 * * @param entry 条目对象 * @return 返回文件夹对象 * @throws FileTreatmentException 文件处理异常 */ public Entry add(Entry entry) throws FileTreatmentException { throw new FileTreatmentException("只有文件夹才能添加条目!"); } /** * 使用默认前缀,显示目录条目 */ public void printList() { printList(""); } /** * 指定前缀,显示目录条目 * * @param prefix 前缀 */ protected abstract void printList(String prefix); @Override public String toString() { return this.getName() + " (" + this.getSize() + ")"; } }

    File类

    package com.pc.visitor.example; /** * 文件类 * Created by Switch on 2017-02-21. */ public class File extends Entry { /** * 文件名 */ private String name; /** * 文件占用空间 */ private int size; /** * 构造方法,传入文件名和文件占用空间 * * @param name 文件名 * @param size 文件占用空间 */ public File(String name, int size) { this.name = name; this.size = size; } @Override public String getName() { return this.name; } @Override public int getSize() { return this.size; } @Override protected void printList(String prefix) { System.out.println(prefix + "/" + this); } @Override public void accept(Visitor visitor) { visitor.visit(this); } }

    Directory类

    package com.pc.visitor.example; import com.pc.abstractfactory.example.factory.Item; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 文件夹类 * Created by Switch on 2017-02-21. */ public class Directory extends Entry { /** * 文件夹名 */ private String name; /** * 文件夹中的条目集合 */ private List<Entry> entries = new ArrayList<>(); /** * 构造方法,传入文件夹名 * * @param name 文件夹名 */ public Directory(String name) { this.name = name; } @Override public String getName() { return this.name; } @Override public int getSize() { int size = 0; for (Entry entry : entries) { size += entry.getSize(); } return size; } @Override public Entry add(Entry entry) { this.entries.add(entry); return this; } @Override protected void printList(String prefix) { System.out.println(prefix + "/" + this); for (Entry entry : entries) { // 打印文件夹下的文件列表,以文件夹前缀,文件名作为前缀 entry.printList(prefix + "/" + this.name); } } @Override public void accept(Visitor visitor) { visitor.visit(this); } /** * 获取迭代器 * * @return 迭代器 */ public Iterator<Entry> iterator() { return this.entries.iterator(); } }

    FileTreatmentException类

    package com.pc.visitor.example; /** * 文件处理异常 * Created by Switch on 2017-02-21. */ public class FileTreatmentException extends RuntimeException { public FileTreatmentException() { } public FileTreatmentException(String message) { super(message); } }

    测试类

    package com.pc.visitor.example.test; import com.pc.visitor.example.Directory; import com.pc.visitor.example.File; import com.pc.visitor.example.FileTreatmentException; import com.pc.visitor.example.ListVisitor; import org.junit.Test; /** * Visitor Tester. * * @author Switch * @version 1.0 */ public class VisitorTest { /** * 测试访问者模式 */ @Test public void testVisitor() { try { System.out.println("添加文件和文件夹:"); System.out.println("Making root entries..."); Directory rootDir = new Directory("root"); Directory binDir = new Directory("bin"); Directory usrDir = new Directory("usr"); rootDir.add(binDir); rootDir.add(usrDir); binDir.add(new File("java", 5000)); binDir.add(new File("javac", 10000)); rootDir.accept(new ListVisitor()); System.out.println(); System.out.println("接着添加文件和文件夹:"); System.out.println("Making user entries..."); Directory switchvov = new Directory("switchvov"); Directory kity = new Directory("kity"); Directory tom = new Directory("tom"); Directory bob = new Directory("bob"); usrDir.add(switchvov); usrDir.add(kity); usrDir.add(bob); switchvov.add(new File("readme.txt", 1000)); switchvov.add(new File("hello.txt", 400)); kity.add(new File("find.sh", 5000)); rootDir.accept(new ListVisitor()); } catch (FileTreatmentException e) { e.printStackTrace(); } } }

    运行结果

    添加文件和文件夹: Making root entries... /root (15000) /root/bin (15000) /root/bin/java (5000) /root/bin/javac (10000) /root/usr (0) 接着添加文件和文件夹: Making user entries... /root (21400) /root/bin (15000) /root/bin/java (5000) /root/bin/javac (10000) /root/usr (6400) /root/usr/switchvov (1400) /root/usr/switchvov/readme.txt (1000) /root/usr/switchvov/hello.txt (400) /root/usr/kity (5000) /root/usr/kity/find.sh (5000) /root/usr/bob (0)

    访问者模式中的角色

    Visitor(访问者)

    Visitor角色负责对数据结构中每个具体的元素(ConcreteElement角色)声明一个用于访问xxxxx的visit(XXXXX)方法。visit(XXXXX)是用于处理xxxxx的方法,负责实现该方法的是ConcreteVisitor角色。在案例中,由Visitor类扮演此角色。

    ConcreteVisitor(具体的访问者)

    ConcreteVisitor角色负责实现Visitor角色所定义的接口(API )。它要实现所有的visit(XXXXX)方法,即实现如何处理每个ConcreteElement角色。在案例中,由ListVisitor类扮演此角色。如同在ListVisitor中, currentdir字段的值不断发生变化一样,随着visit(XXXXX)处理的进行,ConcreteVisitor角色的内部状态也会不断地发生变化。

    Element(元素)

    Element角色表示Visitor角色的访问对象。它声明了接受访问者的accept方法。accept方法接收到的参数是Visitor角色。在案例中,由Element接口扮演此角色。

    ConcreteElement

    ConcreteElement角色负责实现Element角色所定义的接口(API)。在案例中,由File类和Directory类扮演此角色。

    ObjectStructure(对象结构)

    ObjectStructur角色负责处理Element角色的集合。ConcreteVisitor角色为每个Element角色都准备了处理方法。在案例中,由Directory类扮演此角色( 一人分饰两角)。为了让ConcreteVisitor角色可以遍历处理每个Element 角色,在案例中,我们在Directory类中实现了iterator方法。

    类图

    GitHub:DesignPatternStudy

    ——————参考《图解设计模式》

    转载请注明原文地址: https://ju.6miu.com/read-664474.html

    最新回复(0)