⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 visitorpattern.htm

📁 DesignPattern基于Java方面最好的书
💻 HTM
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>





  
  
  
  
  
  <link rel="stylesheet" href="css/stdlayout.css" type="text/css">





  
  
  
  
  
  <link rel="stylesheet" href="css/print.css" type="text/css">





  
  
  
  
  
  <meta content="text/html; charset=gb2312" http-equiv="content-type">





  
  
  
  
  
  <title>Visitor 模式</title>
</head>


<body>





<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>





<h1><a href="CppGossip.html">Design Pattern:&nbsp;Visitor 模式</a></h1>

在Java中所有的物件都继承自Object物件,这样作的优点之一,就是使得一些集合物件的资料结构容易管理,例如您可以将任何型态的物件放入Vector中。<br>
<br>
然而现在有个问题是,如果您的集合(connection)物件中不仅储存一种型态的物件,如果想要对这些物件作出一些个别化的操作,首要条件就是要知道该物件的型态,使用 instanceof 似乎是个不错的方式,在程式简单的情况下,也许您会这么作:<br>
<div style="margin-left: 40px;"><span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;public class ElementA { </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; // some implementing </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;} </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;</span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;public class ElementB { </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; // some implementing </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;} </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;public class ElementC { </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; // some implementing </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;} </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;// ...... </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; Iterator iterator = arrayList.iterator() </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; while (iterator.hasNext()) { </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (o instanceof ElementA) </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">     &nbsp;&nbsp; (ElementA) o.operationA(); </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (o instanceof ElementB) </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">    &nbsp;&nbsp;&nbsp;&nbsp; (ElementB) o.operationB(); </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">  &nbsp;&nbsp;&nbsp; else if (o instanceof ElementC) </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">    &nbsp;&nbsp;&nbsp;&nbsp; (ElementC) o.operationC(); </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">  &nbsp;&nbsp;&nbsp; else </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">    &nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
"Sorry! I don't know who you are! " </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + o.toString()); </span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //....</span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<br style="font-family: Courier New,Courier,monospace; font-weight: bold;">
<span style="font-family: Courier New,Courier,monospace; font-weight: bold;">&nbsp;&nbsp;&nbsp; //....</span><br>
</div>
&nbsp;<br>
这么作并不是不可以,只是将来的扩充性不大,如果今天您想要一次改变对每一种类型物件的操作,您必须修改很多地方。<br>
<br>
从物件自身的角度来想好了,物件在一个个的房子中,物件说:“不要在房子外费尽心思判断了,即然您不知道我是谁,那么您就进来访问我好了,我告诉您我是谁,这么一来您就知道如何操作我了!”<br>
<br>
用程式来实现上面这个描述:<br>
<ul>
  <li> IElement.java </li>
</ul>

<pre>public interface IElement { <br>    public void accept(IVisitor visitor); <br>} <br></pre>

<br>

<ul>
  <li> ElementA.java </li>
</ul>

<pre>public class ElementA implements IElement { <br>    public void accept(IVisitor visitor) { <br>        visitor.visit(this); <br>    }<br><br>    public void operationA() { <br>        System.out.println(<br>              "do A's job....such-and-such...."); <br>    } <br>} <br></pre>

<br>

<ul>
  <li> ElementB.java </li>
</ul>

<pre>public class ElementB implements IElement { <br>    public void accept(IVisitor visitor) { <br>        visitor.visit(this); <br>    }<br><br>    public void operationB() { <br>        System.out.println(<br>           "do B's job....such-and-such...."); <br>    }<br>} <br></pre>

<br>

<ul>
  <li> ElementC.java </li>
</ul>

<pre>public class <span class="createlink">ElementC</span> implements <span class="createlink">IElement</span> { <br>    public void accept(<span class="createlink">IVisitor</span> visitor) { <br>        visitor.visit(this); <br>    }<br><br>    public void operationC() { <br>        System.out.println(<br>            "do C's job....such-and-such...."); <br>    } <br>} <br></pre>

<br>

<ul>
  <li> IVisitor.java </li>
</ul>

<pre>public interface IVisitor { <br>    public void visit(ElementA element); <br>    public void visit(ElementB element); <br>    public void visit(ElementC element); <br>}  <br></pre>

<br>

<ul>
  <li> VisitorA.java </li>
</ul>

<pre>public class VisitorA implements IVisitor { <br>    public void visit(ElementA element) { <br>        element.operationA(); <br>    }<br><br>    public void visit(ElementB element) { <br>        element.operationB(); <br>    }<br><br>    public void visit(ElementC element) { <br>        element.operationC(); <br>    } <br>}  <br></pre>

<br>

<ul>
  <li> Main.java </li>
</ul>

<pre>public class Main { <br>    public static void main(String[] args) { <br>        // know nothing about their type <br>        // after storing them into Element array <br>        IElement[] list = {new ElementA(), <br>                           new ElementB(), <br>                           new ElementC()}; <br><br>        IVisitor visitor = new VisitorA();<br><br>        for (int i=0; i &lt; list.length; i++) <br>            list[i].accept(visitor); <br>    } <br>} </pre>
<br>
Visitor访问是基于overload来完成,对于每一个实现IElement的物件来说,它接受IVisitor来访问它,在accept()方法
中,IVisitor使用正确的方法来访问IElement(显然的,这么部份可以靠不同的函式名称,或是overload来达成),并在visit()
中对IElement作出对应的操作,如果您今天想要换掉每一个IElement的操作,只要更换IVisitor类型的物件就可以了,也就是这行:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">&nbsp;// IVisitor visitor = new VisitorA(); </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">&nbsp;// 换掉一个IVisitor,就可以换掉所有的操作</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">&nbsp;// 不用修改多个地方</span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">&nbsp;IVisitor visitor = new VisitorB(); </span><br>
</div>
&nbsp;<br>
<br>
举个实际的例子,假设VisitorA只是个懒惰的推销员好了,今天有一个比较勤快的推销员VisitorB,在访问过IElement之后,会对 IElement作出更多的操作,要在程式中实现VisitorB,只要增加一个VisitorB类别就可以了:<br>
<ul>
  <li> VisitorB.java </li>
</ul>

<pre>public class VisitorB implements IVisitor { <br>    public void visit(ElementA element) { <br>        System.out.println("VisitorB is a hard worker...."); <br>        element.operationA(); <br>        System.out.println(<br>            "I want to do some extra work on A...."); <br>    }<br><br>    public void visit(ElementB element) { <br>        System.out.println("VisitorB is a hard worker...."); <br>        element.operationB(); <br>        System.out.println(<br>                   "I want to do some extra work on B...."); <br>    }<br><br>    public void visit(ElementC element) { <br>        System.out.println("VisitorB is a hard worker...."); <br>        element.operationC(); <br>        System.out.println(<br>                  "I want to do some extra work on C...."); <br>    } <br>} <br></pre>


<br>
改一下Main来示范:<br>

<ul>
  <li> Main.java </li>
</ul>

<pre>public class Main { <br>    public static void main(String[] args) { <br>        IElement[] list = {new ElementA(), <br>                           new ElementB(), <br>                           new ElementC()}; <br><br>        System.out.println("visitorA is coming......."); <br>        IVisitor visitorA = new VisitorA(); <br>        for (int i=0; i &lt; list.length; i++) <br>           list[i].accept(visitorA);<br><br>        System.out.println("\nvisitorB is coming......."); <br>        IVisitor visitorB = new VisitorB(); <br>        for (int i=0; i &lt; list.length; i++) <br>            list[i].accept(visitorB); <br>    } <br>} <br></pre>

<br>
在范例中的System.out.println();只是个示意,它也可能是您对IElement的额外方法的直接调用。 <br>
<br>
Visitor模式的 UML 结构类图如下:<br>
<div style="text-align: center;"><img style="width: 544px; height: 430px;" alt="Visitor" title="Visitor" src="images/visitor-1.jpg"><br>
<br>
</div>
在<a href="http://www.javaworld.com">Java World</a>中有一篇文章,提到可以利用reflection来改进使用访问者模式时的弹性,有兴趣的可以进一步参考一下<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip98.html">Reflect on the Visitor design pattern</a>。<br>
<br>





</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -