栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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() {
   @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;
   }
  });

自定义MyElement 接口

package design_pattern.visitor.visitor2;

public interface MyElement {
     void accept(Visitor visitor);
}

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() + ">";
    }
}

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);
    }

}

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);
    }

}

Visitor 抽象访问者

package design_pattern.visitor.visitor2;


public abstract class Visitor {
    
    public abstract void visit(MyFile myFile);

    
    public abstract void visit(MyDirectory directory);

}

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();
    }

}

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;
    }

}

ObjectStructure 对象结构

package design_pattern.visitor.visitor2;

import java.util.ArrayList;
import java.util.Iterator;


public class ObjectStructure extends ArrayList implements MyElement {
    @Override
    public void accept(Visitor visitor) {
        //调用ArrayList的iterator方法
        for (Iterator iterator = this.iterator(); iterator.hasNext(); ) {
            MyElement element = iterator.next();
            element.accept(visitor);
        }

    }
}

Main 客户端

package design_pattern.visitor.visitor2;

import java.util.Iterator;


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());
    }

    
    private static void doData(MyDirectory root) {
        root.accept(new ListVisitor());
    }

    
    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;
    }

}

总结

登场角色

元素 >>条目 |–文件 |–文件夹
访问者 |-- 查找指定文件访问者 |-- 查找所有文件访问者
对象结构【其实内部就是个封装了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模式适用于元素基本不变的情况 
添加新的元素非常麻烦 



写在最后

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

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

正所谓点动成线,线动成面,面动成一片

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995286.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号