• 23中设计模式之访问者visitor设计模式


    “ 访问者设计模式学习心得分享”
    talk is cheap ,show me the code. 先看一张类图
    在这里插入图片描述

    jdk 使用到的访问者模式示例
    java.nio.file.FileVisitor
    java.nio.file.Files#walkFileTree

     Path directory = Paths.get("target/perf-logs/");
     //作用:删除文件下的所有目录及文件,并将该文件夹也删掉
     if (Files.exists(directory)) {
      Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
       @Override
       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        Files.delete(file);
        return FileVisitResult.CONTINUE;
       }
       @Override
       public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
        Files.delete(dir);
        return FileVisitResult.CONTINUE;
       }
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    自定义MyElement 接口

    package design_pattern.visitor.visitor2;
    /**
     * 元素接口
     */
    public interface MyElement {
         void accept(Visitor visitor);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    MyEntry 条目抽象类

    package design_pattern.visitor.visitor2;
    
    import java.util.Iterator;
    
    /**
     * 条目抽象类
     */
    public abstract class MyEntry implements MyElement {
        public abstract String getName();
    
        public abstract int getSize();
    
        public abstract void printList(String prefix);
    
        public void printList() {
            printList("");
        }
    
        public MyEntry add(MyEntry entry) throws RuntimeException {
            throw new RuntimeException();
        }
    
        public Iterator iterator() throws RuntimeException {
            throw new RuntimeException();
        }
    
        public String toString() {
            return getName() + "<" + getSize() + ">";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    MyFile 自定义文件类

    package design_pattern.visitor.visitor2;
    
    /**
     * 自定义文件类
     */
    public class MyFile extends MyEntry {
    
        private String name;
        private int size;
    
        public MyFile(String name, int size) {
            this.name = name;
            this.size = size;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public int getSize() {
            return size;
        }
    
        @Override
        public void printList(String prefix) {
            System.out.println(prefix + "/" + this);
        }
        @Override
        public void accept(Visitor visitor) {
             //重点代码
            visitor.visit(this);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    MyDirectory 自定义目录类

    package design_pattern.visitor.visitor2;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /**
     * 自定义目录类
     */
    public class MyDirectory extends MyEntry {
    
        private String name;
        private ArrayList entrys = new ArrayList();
    
        public MyDirectory(String name) {
            this.name = name;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public int getSize() {
            int size = 0;
            Iterator it = entrys.iterator();
            while (it.hasNext()) {
                size += ((MyEntry) it.next()).getSize();
            }
            return size;
        }
    
        @Override
        public MyEntry add(MyEntry entry) {
            entrys.add(entry);
            return this;
        }
    
        @Override
        public Iterator iterator() {
            return entrys.iterator();
        }
    
        @Override
        public void printList(String prefix) {
            System.out.println(prefix + "/" + this);
            //用for 遍历迭代器写法 快捷键itco,今晚刚发现滴
            for (Iterator iterator = entrys.iterator(); iterator.hasNext(); ) {
                MyEntry entry = (MyEntry) iterator.next();
                entry.printList(prefix + "/" + name);
            }
        }
    
        @Override
        public void accept(Visitor visitor) {
        	//重点代码
            visitor.visit(this);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    Visitor 抽象访问者

    package design_pattern.visitor.visitor2;
    
    /**
     * 抽象访问者
     */
    public abstract class Visitor {
        /**
         * 访问文件
         * @param myFile
         */
        public abstract void visit(MyFile myFile);
    
        /**
         * 访问目录
         *
         * @param directory
         */
        public abstract void visit(MyDirectory directory);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    FileFoundVisitor 查找指定文件访问者

    package design_pattern.visitor.visitor2;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /**
     * 查找指定文件访问者
     */
    public class FileFoundVisitor extends Visitor {
    
        private String currentDir = "";
        private String suffix;
        private ArrayList files = new ArrayList();
    
        public FileFoundVisitor(String suffix) {
            this.suffix = suffix;
        }
    
        @Override
        public void visit(MyFile myFile) {
            if (myFile.getName().endsWith(suffix)) {
                files.add(currentDir + "/" + myFile);
            }
        }
    
        public void visit(MyDirectory directory) {
            //先保存当前目录
            String saveDir = currentDir;
            //当前目录被改变
            currentDir += ("/" + directory.getName());
            Iterator it = directory.iterator();
            while (it.hasNext()) {
                MyEntry entry = (MyEntry) it.next();
                entry.accept(this);
            }
            //将当前目录改回来
            currentDir = saveDir;
        }
    
        public Iterator getFoundFiles() {
            return files.iterator();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    ListVisitor 查找所有文件访问者

    package design_pattern.visitor.visitor2;
    
    import java.util.Iterator;
    
    /**
     * 查找所有文件访问者
     */
    public class ListVisitor extends Visitor {
    
        String currentDir = "";
    
        public void visit(MyFile myFile) {
            System.out.println(currentDir + "/" + myFile);
        }
    
        public void visit(MyDirectory directory) {
            System.out.println(currentDir + "/" + directory);
            String saveDir = currentDir;
            currentDir += ("/" + directory.getName());
            Iterator it = directory.iterator();
            while (it.hasNext()) {
                MyEntry entry = (MyEntry) it.next();
                entry.accept(this);
            }
           currentDir = saveDir;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    ObjectStructure 对象结构

    package design_pattern.visitor.visitor2;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /**
     * 对象结构
     */
    public class ObjectStructure extends ArrayList<MyElement> implements MyElement {
        @Override
        public void accept(Visitor visitor) {
            //调用ArrayList的iterator方法
            for (Iterator<MyElement> iterator = this.iterator(); iterator.hasNext(); ) {
                MyElement element = iterator.next();
                element.accept(visitor);
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Main 客户端

    package design_pattern.visitor.visitor2;
    
    import java.util.Iterator;
    
    /**
     * 登场角色
     * >元素
     *    >>条目
     *      |--文件
     *      |--文件夹
     * >访问者
     *     |-- 查找指定文件访问者
     *     |-- 查找所有文件访问者
     * >对象结构【其实内部就是个封装了ArrayList的容器,加了个accept方法】
     *
     * <p>
     * 使用场景:当出现有组织结构、树形结构、多层级访问、问答场景 需要访问各个条目时,可以考虑用使用访问者设计模式
     * 相关模式:
     * 1.迭代器设计模式
     * 2.组合设计模式
     * <p>
     * 另外:
     * MyDirectory#printList(java.lang.String)方法 为我们提供了一种新的递归访问模型
     * 另外一种新的思路就是像本visitor模式一样使用【双重分发】
     * <pre>
     *     public void accept(Visitor visitor) {
     *         visitor.visit(this);
     *     }
     *  <pre/>
     *  他们是相反的关系,element接收visitor,visitor访问element,
     *  这种消息分发的方式被称为双重分发【double dispatch】
     *
     *  为什么要弄得这么复复杂?
     *  visitor模式的主要目的是将【处理】从数据结构中分离出来,
     *  【保存数据结构】和【以数据结构为基础】进行处理是两码事
     *  缺点:
     *  visitor模式适用于元素基本不变的情况
     *  添加新的元素非常麻烦
     */
    public class Main {
    
        public static void main(String[] args) {
            //准备数据
            MyDirectory root = getData();
            //处理数据 可以替换为doData 、doData1、doData2
            doData3(root);
        }
    
        private static void doData3(MyDirectory root) {
            ObjectStructure objectStructure = new ObjectStructure();
            objectStructure.add(root);
            objectStructure.add(new MyFile("我是小孩也是王", 1));
            objectStructure.accept(new ListVisitor());
        }
    
        /**
         * 处理数据1:全部访问
         *
         * @param root
         */
        private static void doData(MyDirectory root) {
            root.accept(new ListVisitor());
        }
    
        /**
         * 处理数据2:访问数据并查找指定格式的文文件
         *
         * @param root
         */
        private static void doData2(MyDirectory root) {
            FileFoundVisitor visitor = new FileFoundVisitor(".psd");
            root.accept(visitor);
            //打印获取到的指定文件
            Iterator it = visitor.getFoundFiles();
            while (it.hasNext()) {
                System.out.println(it.next());
            }
        }
    
        private static MyDirectory getData() {
            MyDirectory root = new MyDirectory("根目录");
    
            MyDirectory life = new MyDirectory("我的生活");
            MyFile eat = new MyFile("吃火锅.txt", 100);
            MyFile sleep = new MyFile("睡觉.html", 100);
            MyFile study = new MyFile("学习.txt", 100);
            life.add(eat);
            life.add(sleep);
            life.add(study);
    
            MyDirectory work = new MyDirectory("我的工作");
            MyFile write = new MyFile("写博客.doc", 200);
            MyFile paper = new MyFile("写论文.html", 200);
            MyFile homework = new MyFile("写家庭作业.docx", 200);
            work.add(write);
            work.add(paper);
            work.add(homework);
    
            MyDirectory relax = new MyDirectory("我的休闲");
            MyFile music = new MyFile("听听音乐.js", 200);
            MyFile walk = new MyFile("出去转转.psd", 200);
            relax.add(music);
            relax.add(walk);
    
            MyDirectory read = new MyDirectory("我的阅读");
            MyFile book = new MyFile("学习书籍.psd", 200);
            MyFile novel = new MyFile("娱乐小说.txt", 200);
            read.add(book);
            read.add(novel);
    
            root.add(life);
            root.add(work);
            root.add(relax);
            root.add(read);
            return root;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118

    总结

    登场角色

    元素 >>条目 |–文件 |–文件夹
    访问者 |-- 查找指定文件访问者 |-- 查找所有文件访问者
    对象结构【其实内部就是个封装了ArrayList的容器,加了个accept方法】
    使用场景:当出现有组织结构、树形结构、多层级访问、问答场景
    需要访问各个条目时,可以考虑用使用访问者设计模式

    相关模式:
    1.迭代器设计模式
    2.组合设计模式
    另外:MyDirectory#printList(java.lang.String)方法 为我们提供了一种新的递归访问模型 另外一种新的思路就是像本visitor模式一样使用【双重分发】
    public void accept(Visitor visitor) {
    visitor.visit(this);
    }

    他们是相反的关系,element接收visitor,visitor访问element, 
    这种消息分发的方式被称为双重分发【double dispatch】 
    
    为什么要弄得这么复复杂?
    visitor模式的主要目的是将【处理】从数据结构中分离出来, 
    【保存数据结构】和【以数据结构为基础】进行处理是两码事 
    缺点:
    visitor模式适用于元素基本不变的情况 
    添加新的元素非常麻烦 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    在这里插入图片描述
    写在最后
    在这里插入图片描述

    总结:本片文章我们主要描述了什么是访问者visitor设计模式,以及使用场景。以及本设计模式相关联的模式:如迭代器设计模式和组合设计模式

    ,这些都是相互关联的,设计模式是一种套路、是一种模板、是一种经验,是一种角色扮演,每个模式都有其登场角色,我们自己在设计和编程时,要思考一下学习过的设计模,是否适用于当前场景。

    正所谓点动成线,线动成面,面动成一片
    在这里插入图片描述
    在这里插入图片描述

    你现在多努力一份,以后老婆就多漂亮一分,加油吧,少年!!!

  • 相关阅读:
    postgres 查看全部数据库
    第五十章 开发自定义标签 - 使用Rule类
    如何制作网页-初学者入门HTML+CSS
    c++ deque 的使用
    【算法基础】分解质因数
    基于JAVA评标专家管理信息系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    数据结构-难点突破(线索化二叉树与遍历 C++中序线索化二叉树,前序线索二叉树,后序线索二叉树)
    实时配送跟踪功能的实现:外卖跑腿小程序的技术挑战
    【云原生之Docker实战】使用Docker部署Flarum开源论坛
    nginx的location的优先级和匹配方式和重定向
  • 原文地址:https://blog.csdn.net/ljh_learn_from_base/article/details/125485861