会见器范式
当前位置:以往代写 > JAVA 教程 >会见器范式
2019-06-14

会见器范式

会见器范式

接下来,让我们思考如何将具有完全差异方针的一个设计范式应用到垃圾归类系统。
对这个范式,我们不再体贴在系统中插手新型Trash时的优化。事实上,这个范式使新型Trash的添加显得越发巨大。假定我们有一个根基类布局,它是牢靠稳定的;它或者来自另一个开拓者或公司,我们无权对谁人布局举办任何修改。然而,我们又但愿在谁人布局里插手新的多形性要领。这意味着我们一般必需在基本类的接口里添加某些对象。因此,我们今朝面对的逆境是一方面需要向基本类添加要领,另一方面又不能窜改基本类。奈何办理这个问题呢?
“会见器”(Visitor)范式使我们能扩展根基范例的接口,要领是建设范例为Visitor的一个独立的类布局,对今后需对根基范例采纳的操纵举办虚拟。根基范例的任务就是简朴地“吸收”会见器,然后挪用会见器的动态绑定要领。看起来就象下面这样:

接见器范式

此刻,如果v是一个指向Aluminum(铝成品)的Visitable句柄,那么下述代码:
PriceVisitor pv = new PriceVisitor();
v.accept(pv);
会造成两个多形性要领挪用:第一个会选择accept()的Aluminum版本;第二个则在accept()里——用基本类Visitor句柄v动态挪用visit()的特定版本时。
这种设置意味着可采纳Visitor的新子类的形式将新的成果添加到系统里,没须要打仗Trash布局。这就是“会见器”范式最主要的利益:可为一个类布局添加新的多形性成果,同时不必窜改布局——只要安装好了accept()要领。留意这个利益在这儿是有用的,但并不必然是我们在任何环境下的首选方案。所以在最开始的时候,就要判定这到底是不是本身需要的方案。
此刻留意一件没有做成的工作:会见器方案防备了从主控Trash序列向单独范例序列的归类。所以我们可将所有对象都留在单主控序列中,只需用适当的会见器通过谁人序列通报,即可到达但愿的方针。尽量这好像并非会见器范式的本意,但确实让我们到达了很但愿到达的一个方针(制止利用RTTI)。
会见器范式中的双生调派认真同时判定Trash以及Visitor的范例。在下面的例子中,各人可看到Visitor的两种实现方法:PriceVisitor用于判定总计及价值,而WeightVisitor用于跟踪重量。
可以看到,所有这些都是用接纳措施一个新的、改造过的版本实现的。并且和DoubleDispatch.java一样,Trash类被保持孤独,并建设一个新接口来添加accept()要领:

 

//: Visitable.java
// An interface to add visitor functionality to 
// the Trash hierarchy without modifying the 
// base class.
package c16.trashvisitor;
import c16.trash.*;

interface Visitable {
  // The new method:
  void accept(Visitor v);
} ///:~

Aluminum,Paper,Glass以及Cardboard的子范例实现了accept()要领:

 

//: VAluminum.java
// Aluminum for the visitor pattern
package c16.trashvisitor;
import c16.trash.*;

public class VAluminum extends Aluminum 
    implements Visitable {
  public VAluminum(double wt) { super(wt); }
  public void accept(Visitor v) {
    v.visit(this);
  }
} ///:~
//: VPaper.java
// Paper for the visitor pattern
package c16.trashvisitor;
import c16.trash.*;

public class VPaper extends Paper 
    implements Visitable {
  public VPaper(double wt) { super(wt); }
  public void accept(Visitor v) {
    v.visit(this);
  }
} ///:~
//: VGlass.java
// Glass for the visitor pattern
package c16.trashvisitor;
import c16.trash.*;

public class VGlass extends Glass 
    implements Visitable {
  public VGlass(double wt) { super(wt); }
  public void accept(Visitor v) {
    v.visit(this);
  }
} ///:~
//: VCardboard.java
// Cardboard for the visitor pattern
package c16.trashvisitor;
import c16.trash.*;

public class VCardboard extends Cardboard 
    implements Visitable {
  public VCardboard(double wt) { super(wt); }
  public void accept(Visitor v) {
    v.visit(this);
  }
} ///:~

由于Visitor基本类没有什么需要实在的对象,可将其建设成一个接口:

 

//: Visitor.java
// The base interface for visitors
package c16.trashvisitor;
import c16.trash.*;

interface Visitor {
  void visit(VAluminum a);
  void visit(VPaper p);
  void visit(VGlass g);
  void visit(VCardboard c);
} ///:~

 

c16.TrashVisitor.VGlass:54
c16.TrashVisitor.VPaper:22
c16.TrashVisitor.VPaper:11
c16.TrashVisitor.VGlass:17
c16.TrashVisitor.VAluminum:89
c16.TrashVisitor.VPaper:88
c16.TrashVisitor.VAluminum:76
c16.TrashVisitor.VCardboard:96
c16.TrashVisitor.VAluminum:25
c16.TrashVisitor.VAluminum:34
c16.TrashVisitor.VGlass:11
c16.TrashVisitor.VGlass:68
c16.TrashVisitor.VGlass:43
c16.TrashVisitor.VAluminum:27
c16.TrashVisitor.VCardboard:44
c16.TrashVisitor.VAluminum:18
c16.TrashVisitor.VPaper:91
c16.TrashVisitor.VGlass:63
c16.TrashVisitor.VGlass:50
c16.TrashVisitor.VGlass:80
c16.TrashVisitor.VAluminum:81
c16.TrashVisitor.VCardboard:12
c16.TrashVisitor.VGlass:12
c16.TrashVisitor.VGlass:54
c16.TrashVisitor.VAluminum:36
c16.TrashVisitor.VAluminum:93
c16.TrashVisitor.VGlass:93
c16.TrashVisitor.VPaper:80
c16.TrashVisitor.VGlass:36
c16.TrashVisitor.VGlass:12
c16.TrashVisitor.VGlass:60
c16.TrashVisitor.VPaper:66
c16.TrashVisitor.VAluminum:36
c16.TrashVisitor.VCardboard:22

#p#分页标题#e#

措施剩余的部门将建设特定的Visitor范例,并通过一个Trash工具列表发送它们:

 

//: TrashVisitor.java 
// The "visitor" pattern
package c16.trashvisitor;
import c16.trash.*;
import java.util.*;

// Specific group of algorithms packaged
// in each implementation of Visitor:
class PriceVisitor implements Visitor {
  private double alSum; // Aluminum
  private double pSum; // Paper
  private double gSum; // Glass
  private double cSum; // Cardboard
  public void visit(VAluminum al) {
    double v = al.weight() * al.value();
    System.out.println(
      "value of Aluminum= " + v);
    alSum += v;
  }
  public void visit(VPaper p) {
    double v = p.weight() * p.value();
    System.out.println(
      "value of Paper= " + v);
    pSum += v;
  }
  public void visit(VGlass g) {
    double v = g.weight() * g.value();
    System.out.println(
      "value of Glass= " + v);
    gSum += v;
  }
  public void visit(VCardboard c) {
    double v = c.weight() * c.value();
    System.out.println(
      "value of Cardboard = " + v);
    cSum += v;
  }
  void total() {
    System.out.println(
      "Total Aluminum: ___FCKpd___7quot; + alSum + "\n" +
      "Total Paper: ___FCKpd___7quot; + pSum + "\n" +
      "Total Glass: ___FCKpd___7quot; + gSum + "\n" +
      "Total Cardboard: ___FCKpd___7quot; + cSum);
  }
}

class WeightVisitor implements Visitor {
  private double alSum; // Aluminum
  private double pSum; // Paper
  private double gSum; // Glass
  private double cSum; // Cardboard
  public void visit(VAluminum al) {
    alSum += al.weight();
    System.out.println("weight of Aluminum = "
        + al.weight());
  }
  public void visit(VPaper p) {
    pSum += p.weight();
    System.out.println("weight of Paper = "
        + p.weight());
  }
  public void visit(VGlass g) {
    gSum += g.weight();
    System.out.println("weight of Glass = "
        + g.weight());
  }
  public void visit(VCardboard c) {
    cSum += c.weight();
    System.out.println("weight of Cardboard = "
        + c.weight());
  }
  void total() {
    System.out.println("Total weight Aluminum:"
        + alSum);
    System.out.println("Total weight Paper:"
        + pSum);
    System.out.println("Total weight Glass:"
        + gSum);
    System.out.println("Total weight Cardboard:"
        + cSum);
  }
}

public class TrashVisitor {
  public static void main(String[] args) {
    Vector bin = new Vector();
    // ParseTrash still works, without changes:
    ParseTrash.fillBin("VTrash.dat", bin);
    // You could even iterate through
    // a list of visitors!
    PriceVisitor pv = new PriceVisitor();
    WeightVisitor wv = new WeightVisitor();
    Enumeration it = bin.elements();
    while(it.hasMoreElements()) {
      Visitable v = (Visitable)it.nextElement();
      v.accept(pv);
      v.accept(wv);
    }
    pv.total();
    wv.total();
  }
} ///:~

留意main()的形状已再次产生了变革。此刻只有一个垃圾(Trash)筒。两个Visitor工具被吸收到序列中的每个元素内,它们会完本钱身份内的事情。Visitor跟踪它们本身的内部数据,计较出总重和价值。
最好,将对象从序列中取出的时候,除了不行制止地向Trash造型以外,再没有运行期的范例验证。若在Java里实现了参数化范例,甚至谁人造型操纵也可以制止。
比拟之前先容过的双重调派方案,区分这两种方案的一个步伐是:在双重调派方案中,每个子类建设时只会过载个中的一个过载要领,即add()。而在这里,每个过载的visit()要领都必需在Visitor的每个子类中举办过载。

1. 更多的团结?
这里尚有其他很多代码,Trash布局和Visitor布局之间存在着明明的“团结”(Coupling)干系。然而,在它们所代表的类集内部,也存在着高度的凝结力:都只做一件工作(Trash描写垃圾或废品,而Visitor描写对垃圾采纳什么动作)。作为一套优秀的设计方案,这无疑是个精采的初步。虽然就今朝的环境来说,只有在我们添加新的Visitor范例时才气体会到它的长处。但在添加新范例的Trash时,它却显得有些碍手碍脚。
类与类之间低度的团结与类内高度的凝结无疑是一个重要的设计方针。但只要稍不把稳,就大概故障我们获得一个本该更精彩的设计。从外貌看,有些类不行制止地彼此间存在着一些“亲密”干系。这种干系凡是是成对产生的,可以叫作“春联”(Couplet)——好比荟萃和担任器(Enumeration)。前面的Trash-Visitor对好像也是这样的一种“春联”。

    关键字:

在线提交作业