热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

访问者(Visitor)模式访问数据结构并处理数据

》》在Visitor模式中,数据结构与处理被分离开来。-------------下面的示例程序中:文件与文件夹作为访问者要访问的数据结构,         访问者会访问文件与文件夹

》》在Visitor 模式中,数据结构与处理被分离开来

-------------下面的示例程序中:文件与文件夹作为访问者要访问的数据结构,

                  访问者会访问文件与文件夹,然后显示出文件和文件夹的一览。

》》示例程序的类图:

        访问者(Visitor)模式--------访问数据结构并处理数据

》》Visitor类:

        package visitor;
/*
 * 访问者类
 */
public abstract class Visitor {
public abstract void visit(File file);                //访问文件
public abstract void visit(Directory directory);      //访问文件夹
}

      说明:该类是表示访问者的抽象类。访问者依赖于它所访问的数据结构

      (即 File 类和Directory 类 )

》》Element 接口;

       package visitor;
/*
 * Element 接口是接受访问者的访问的接口。
 */
public interface Element {
//声明 accept 方法
public abstract void accept(Visitor v);


}

      说明:该接口是接收访问者的访问的接口。

》》Entry 类:

        package visitor;


import java.util.Iterator;


public abstract class Entry implements Element{
public abstract String getName();                              //获取名字
public abstract int getSize();                                 //获取大小
public Entry add(Entry entry) throws FileTreatmentException{   //增加目录条目
throw new FileTreatmentException();
}

public Iterator iterator() throws FileTreatmentException{       //生成 Iterator
throw new FileTreatmentException();
}

public String toString(){                                      //显示字符串
return getName()+"("+getSize()+")";
}


}

》》File 类:

        package visitor;


public class File extends Entry{
private String name;                    //文件的名字
private int size;                       //文件的大小
public File(String name , int size){    //构造器
this.name = name;
this.size = size;
}
public String getName(){                 //获取文件的名字
return name;
}
public int getSize(){                    //获取文件的大小
return size;


public void accept(Visitor v){          //接收访问者
v.visit(this);
}


}

》》Directory 类:

        package visitor;
import java.util.ArrayList;
import java.util.Iterator;


public class Directory extends Entry{
public String name;                          //文件夹的名字
private ArrayList dir = new ArrayList();     //目录条目集合
public Directory(String name){                //构造函数
this.name = name;
}
public String getName(){                     //获取文件夹的名字
return name;
}
public int getSize(){                       //获取文件夹的大小
int size = 0;
Iterator it = dir.iterator();            //获取目录条目集合的迭代器
while(it.hasNext()){
Entry entry = (Entry)it.next();     //逐个获取集合中的元素
size += entry.getSize();
}
return size;
}

public Entry add(Entry entry){              //增加目录条目
dir.add(entry);                         //放在集合中
return this;
}

public Iterator iterator(){                 //生成 Iterator
return dir.iterator();
}

public void accept(Visitor v){             //接受访问者的访问
v.visit(this);
}
}

》》ListVisitor 类:

        package visitor;


import java.util.Iterator;


public class ListVisitor extends Visitor {
private String currentdir = "";               //当前访问的文件夹的名字
public void visit(File file) {                //访问文件夹时被调用
//像下面的字符串直接加上对象的引用,程序会自动调用该对象的 toString() 方法
System.out.println(currentdir  + "/"+file);
}
public void visit(Directory directory) {      //访问文件夹时被调用
System.out.println(currentdir + "/"+directory);
String savedir = currentdir;              //在savedir 中保存currentdir中原来的值
currentdir = currentdir+"/"+ directory.getName(); //currentdir 保存当前文件夹的路径
Iterator it = directory.iterator();
while(it.hasNext()){
Entry entry =(Entry)it.next();
entry.accept(this);
}
currentdir = savedir;
}


}

       说明:visit(File file)  这个方法是用来实现“对File 类的实例要进行的处理”;

          visit(Directory directory) 这个方法是用来实现“对 Directory  类的实例要进行的处理

       ******* 在 Visitor 模式中,则是 accept  方法与 visit 方法之间相互递归调用

》》FileTreatmentException 类:

         package visitor;
/*
 * 表示向文件中add时发生的异常的类
 */
public class FileTreatmentException extends RuntimeException{
public FileTreatmentException(){}
public FileTreatmentException(String msg){
super(msg);
}


}

》》Main 类------>测试程序

         package visitor;


import visitor.Directory;
import visitor.File;
import visitor.FileTreatmentException;


public class Main {
public static void main(String[] args){
try{
System.out.println("Making root entries...");
Directory rootdir = new Directory("root");
Directory bindir = new Directory("bin");
Directory tmpdir = new Directory("tmp");
Directory usrdir = new Directory("usr");

rootdir.add(bindir);
rootdir.add(tmpdir);
rootdir.add(usrdir);
bindir.add(new File("vi",10000));
bindir.add(new File("latex",20000));
rootdir.accept(new ListVisitor());;

System.out.println("");
System.out.println("Making user entries...");
Directory yuki = new Directory("yuki");
Directory hanako = new Directory("hanakpo");
Directory tomura = new Directory("tomura");
usrdir.add(yuki);
usrdir.add(hanako);
usrdir.add(tomura);
yuki.add(new File("diary.html",100));
yuki.add(new File("Composite.java",200));
hanako.add(new File("memo.tex",300));
tomura.add(new File("game.doc",400));
tomura.add(new File("junk.mail",500));
rootdir.accept(new ListVisitor());;


}catch(FileTreatmentException e){
e.printStackTrace();
}
}


}

》》运行结果:

         访问者(Visitor)模式--------访问数据结构并处理数据

       通过上面的示例程序,在Visitor 模式中,visit 方法将“处理”集中在

        ListVisitor 里面了。

-------------------------------------------------------------------

       《Visitor 模式中的登场角色》

       **** Visitor (访问者)

              Visitor 角色负责对数据结构中每个具体的元素(ConcreteElement 角色)声明一个用于

        访问  xxx 的 visit(xxx) 的方法。 visit(xxx) 是用于处理 xxx 的方法,负责实现该方法的

         ConcreteVisitor 角色。在示例程序中,由 Visitor 类扮演此角色。

        **** ConcreteVisitor (具体的访问者)

                ConcreteVisitor 角色负责实现 Visitor 角色所定义的接口(API)。在示例程序中,由

          ListVisitor 类扮演此角色。

        **** Element (元素)

                Element 角色表示 Visitor 角色的访问对象。它声明了接受访问者的 accept 方法。

          accept 方法接收到的参数是 Visitor 角色。在示例程序中,由 Element 接口扮演此角色。

        ****  ConcreteElement 

               ConcreteElement 角色负责实现 Element 角色所定义的接口(API)。在示例程序中,

          由 File 类和 Directory 类扮演此角色。

       ****  ObjectStructure (对象结构)

              ObjectStructure 角色负责处理 Element 角色的集合。ConcreteVisitor 角色为每个Element

           角色都准备了处理方法。在示例程序中,由 Directory 类扮演此角色(一人分饰两角)。为了

         让 ConcreteVisitor 角色可以遍历处理每个 Element 角色,在示例程序中,我们在Directory

          类中实现了 iterator 方法。

-----------------------------------------------------

          《扩展思路的要点》

           1.双重分发

                 在Visitor 模式中,ConcreteVisitor 和 ConcreteElement  这两个角色共同决定了实际进行的

             处理。这种消息分发的方式一般被称为双重分发。

           2.为什么要弄得这么复杂

                   Visitor 模式的目的是:将处理从数据结构中分离出来。数据结构很重要,它能将元素集合和

               关联在一起。但是,需要注意的是,保存数据结构与以数据结构为基础进行处理是两种不同的

              东西。

                  在上面的示例程序中, Visitor 模式提高了  File 类和 Directory  类 作为组件的独立性。

           3.开闭原则------对扩展开放,对修改关闭

                   该原则主张类应当是下面这样的:

                   ****对扩展是开放的

                   ****对修改是关闭的

                   在设计类时,若无特殊理由,必须要考虑到将来可能会扩展类。绝不能毫无理由地禁止扩展类。

              这就是“对扩展是开放”的意思。

                   如果在每次扩展类时都需要修改现有的类就太麻烦了。所以我们需要在不用修改现有类的前提

              下能够扩展类,这就是“对修改是关闭”的意思。

                   对扩展开放、对修改关闭的类具有高可复用,可作为组件复用。设计模式和面向对象的目的正是

               为我们提供一种结构,可以帮助我们设计出这样的类。

           4.易于增加的 ConcreteVisitor 角色

                  使用Visitor 角色可以很容易地增加 ConcreteVisitor 角色。因为具体的处理被交给ConcreteVisitor

               角色负责,因此完全不用修改 ConcreteElement 角色。

           5.难以增加的   ConcreteElement  角色        

            6.Visitor 工作所需要的条件

                  “在 Visitor 模式中,对数据结构中的元素进行处理的任务被分离出来,交给 Visitor 类负责。”这样就

              实现了数据结构与处理的分离。但是要达到这个目的是有条件的,那就是 Element 角色必须向 Visitor

              角色公开足够多的信息。

                    访问者只有从数据结构中获取了足够多的信息后才能工作。如果无法获取到这些信息,它就无法

              工作。这样做的缺点是:如果公开了不应当被公开的信息,将来对数据结构的改良就会变得非常困难。

-----------------------------------------------------

              《相关的设计模式》

              1.Iterator 模式

              2.Composite 模式

              3.Interpreter 模式 


推荐阅读
  • 本文介绍了 Go 语言中的高性能、可扩展、轻量级 Web 框架 Echo。Echo 框架简单易用,仅需几行代码即可启动一个高性能 HTTP 服务。 ... [详细]
  • iOS 不定参数 详解 ... [详细]
  • Cookie学习小结
    Cookie学习小结 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • Bootstrap 插件使用指南
    本文详细介绍了如何在 Web 前端开发中使用 Bootstrap 插件,包括自动触发插件的方法、插件的引用方式以及具体的实例。 ... [详细]
  • iOS snow animation
    CTSnowAnimationView.hCTMyCtripCreatedbyalexon1614.Copyright©2016年ctrip.Allrightsreserved.# ... [详细]
  • 探讨PHP中不同文件读取方法的性能差异,特别是针对大文件的处理。 ... [详细]
  • 使用HTML和JavaScript实现视频截图功能
    本文介绍了如何利用HTML和JavaScript实现从远程MP4、本地摄像头及本地上传的MP4文件中截取视频帧,并展示了具体的实现步骤和示例代码。 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 本文介绍了如何使用Python爬取妙笔阁小说网仙侠系列中所有小说的信息,并将其保存为TXT和CSV格式。主要内容包括如何构造请求头以避免被网站封禁,以及如何利用XPath解析HTML并提取所需信息。 ... [详细]
  • 如何配置VisualSVN以确保提交时必须填写日志信息
    在软件开发团队中,成员们有时会忘记在提交代码时添加必要的备注信息。为了规范这一流程,可以通过配置VisualSVN来强制要求团队成员在提交文件时填写日志信息。本文将详细介绍如何设置这一功能。 ... [详细]
  • 小程序的授权和登陆
    小程序的授权和登陆 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
author-avatar
果博东方手机版
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有