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

“ 访问者设计模式学习心得分享”
适用于结构相对稳定的条目或者xxx对比时,其它相对稳定的层级组织架构使用该模式是OK滴
如条目中文件文件夹的访问,男人女人对同一件事情不同反应的对比
条目只分为文件和文件夹,人只分为男人和女人,这称之为结构稳定。
talk is cheap ,show me the code. 先看一张类图
23中设计模式之访问者visitor设计模式_第1张图片

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

自定义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 {
    /**
     * 访问文件
     * @param myFile
     */
    public abstract void visit(MyFile myFile);

    /**
     * 访问目录
     *
     * @param directory
     */
    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<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);
        }

    }
}

Main 客户端

package design_pattern.visitor.visitor2;

import java.util.Iterator;

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

}

总结

登场角色

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

23中设计模式之访问者visitor设计模式_第2张图片
23中设计模式之访问者visitor设计模式_第3张图片
写在最后
23中设计模式之访问者visitor设计模式_第4张图片

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

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

正所谓点动成线,线动成面,面动成一片
23中设计模式之访问者visitor设计模式_第5张图片
23中设计模式之访问者visitor设计模式_第6张图片

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

你可能感兴趣的:(jdk1.8,java,设计模式,访问者模式,java)