快速业务通道

诊断Java代码: 设计可扩展的应用程序,第2部分 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-19
设计模式的最初书籍( 《设计模式》,Gamma 等;请参阅 参考资料)提出的设计模式之一。这一模式背后的思想是为复合数据类型定义一个抽象的“访问者”类。这个访问者类包含明显不同的方法,分别用于每一个具体的子类型。对我们的 Tree 类这种情况来说,我们可以定义一个抽象的 TreeVisitor 类,如下:

清单 3. 定义一个抽象的“树访问者”类

interface TreeVisitor {   public Object forBranch(Branch that);   public Object forLeaf(Leaf that); }

Tree 的每一个子类型都必须包含一个 accept 方法,该方法带一个 TreeVisitor 参数并调用自身的 TreeVisitor 的 accept方法:

清单 4. accept 方法必须调用自身对应的 accept 方法

// in class Tree: public abstract Object accept(TreeVisitor that); // in class Branch: public Object accept(TreeVisitor that) {   return that.forBranch(this); } // in class Leaf: public Object accept(TreeVisitor that) {   return that.forLeaf(this); }

现在,当我们想把新的功能性添加到树中时,我们可以只是定义 TreeVisitor 的新的具体子类并适当地定义 for方法(即 forBranch 和 forLeaf 方法)。例如,我们可以添加一个生成树的深度拷贝功能,如下:

清单 5. 新的 TreeCopier 功能对树进行拷贝

class TreeCopier implements TreeVisitor {   public Object forBranch(Branch that) {    return new Branch(that.getValue(),             (Tree)that.getLeft().accept(this),             (Tree)that.getRight().accept(this));   }   public Object forLeaf(Leaf that) {    // There are no subcomponents to visit in a Leaf.    return new Leaf();   } }

诊断Java代码: 设计可扩展的应用程序,第2部分(3)

时间:2011-02-11 IBM Eric E. Allen

访问者带来的麻烦

但如果我们也想扩展类 Tree 的具体子类型集合,则采用这种办法就会碰上麻烦。

第一个问题是现有的 TreeVisitors 将不包含用于新数据类型的 for 方法。这个问题可以这样解决:用包含这些新方法的新 TreeVisitors 建立现有 TreeVisitors 的子类型,并实现一个包含这些新方法的新子接口。

在我们的深度拷贝示例(清单 5)中,如果单元素叶被添加到我们的树中,则我们可以按如下方式扩展 TreeCopier (注意,必须给 NonEmptyLeaf 的 accept方法添加一个强制转型):

清单 6. 为非空叶而做的扩展

interface TreeVisitor2 extends TreeVisitor {   public Object forNonEmptyLeaf(NonEmptyLeaf that); } ...   // in class NonEmptyLeaf   public Object accept(TreeVisitor that) {    return ((TreeVisitor2)that).forNonEmptyLeaf(this);   } class TreeCopier2 extends TreeCopier implements TreeVisitor2 {   public Object forNonEmptyLeaf(NonEmptyLeaf that) {    return new NonEmptyLeaf(that.getValue());   } }

但仅仅以这种方式扩展 TreeVisitors 是不够的。

如果访问者带来更多访问者会怎么样?

原始的 TreeVisitors 可能会构造 TreeVisitors 的新实例。 TreeVisitor 的子类的实例现在将构造它们的超类的实例。

这个问题是常见的。通常,当在访问者中包含额外参数是很自然的时候,这些额外参数被传递到访问者的构造器,然后构造器把这些参数放置到字段中。在一个递归下降数据结构中,如果必须使用递归调用中的这些参数的不同值,则将会构造一个使用了新参数的新访问者。

例如,假设我们想创建一个 TreeVisitor ,用于对 Tree 的元素进行美化打印。我们可以用 TreeVisitor 的一个字段来跟踪打印子树时的缩进程度,以

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号