友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第196章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




import c16。trash。*;  

  

public class DDCardboard extends Cardboard   

    implements TypedBinMember {  

  public DDCardboard(double wt) { super(wt); }  

  public boolean addToBin(TypedBin'' tb) {  

    for(int i = 0; i 《 tb。length; i++)  

      if(tb'i'。add(this))  

        return true;  

    return false;  

  }  

} ///:~  

  

每个addToBin()内的代码会为数组中的每个TypeBin 对象调用add()。但请注意参数:this。对Trash 的每 

个子类来说,this 的类型都是不同的,所以不能认为代码“完全”一样——尽管以后在 Java 里加入参数化 

类型机制后便可认为一样。这是双重派遣的第一个部分,因为一旦进入这个方法内部,便可知道到底是 

Aluminum ,Paper,还是其他什么垃圾类型。在对add()的调用过程中,这种信息是通过this 的类型传递 

的。编译器会分析出对 add()正确的过载版本的调用。但由于tb'i'会产生指向基础类型 TypeBin 的一个句 

柄,所以最终会调用一个不同的方法——具体什么方法取决于当前选择的 TypeBin 的类型。那就是第二次派 

遣。  

下面是TypeBin 的基础类:  

  

//: TypedBin。java  

// Vector that knows how to grab the right type  

package c16。doubledispatch;  

import c16。trash。*;  

import java。util。*;  

  

public abstract class TypedBin {  

  Vector v = new Vector();  

  protected boolean addIt(Trash t) {  

    v。addElement(t);  

    return true;  

  }  

  public Enumeration elements() {  

    return v。elements();  

  }  

  public boolean add(DDAluminum a) {  

    return false;  



                                                                                          609 


…………………………………………………………Page 611……………………………………………………………

  }  

  public boolean add(DDPaper a) {  

    return false;  

  }  

  public boolean add(DDGlass a) {  

    return false;  

  }  

  public boolean add(DDCardboard a) {  

    return false;  

  }  

} ///:~  

  

可以看到,过载的 add()方法全都会返回false。如果未在衍生类里对方法进行过载,它就会一直返回 

false,而且调用者(目前是 addToBin())会认为当前Trash 对象尚未成功加入一个集合,所以会继续查找 

正确的集合。  

在TypeBin 的每一个子类中,都只有一个过载的方法会被过载——具体取决于准备创建的是什么垃圾筒类 

型。举个例子来说,CardboardBin 会过载 add(DDCardboard)。过载的方法会将垃圾对象加入它的集合,并返 

回true。而CardboardBin 中剩余的所有add()方法都会继续返回 false,因为它们尚未过载。事实上,假如 

在这里采用了参数化类型机制,Java 代码的自动创建就要方便得多(使用 C++的“模板”,我们不必费事地 

为子类编码,或者将addToBin()方法置入Trash 里;Java 在这方面尚有待改进)。  

由于对这个例子来说,垃圾的类型已经定制并置入一个不同的目录,所以需要用一个不同的垃圾数据文件令 

其运转起来。下面是一个示范性的 DDTrash。dat:  

  

c16。DoubleDispatch。DDGlass:54  

c16。DoubleDispatch。DDPaper:22  

c16。DoubleDispatch。DDPaper:11  

c16。DoubleDispatch。DDGlass:17  

c16。DoubleDispatch。DDAluminum:89  

c16。DoubleDispatch。DDPaper:88  

c16。DoubleDispatch。DDAluminum:76  

c16。DoubleDispatch。DDCardboard:96  

c16。DoubleDispatch。DDAluminum:25  

c16。DoubleDispatch。DDAluminum:34  

c16。DoubleDispatch。DDGlass:11  

c16。DoubleDispatch。DDGlass:68  

c16。DoubleDispatch。DDGlass:43  

c16。DoubleDispatch。DDAluminum:27  

c16。DoubleDispatch。DDCardboard:44  

c16。DoubleDispatch。DDAluminum:18  

c16。DoubleDispatch。DDPaper:91  

c16。DoubleDispatch。DDGlass:63  

c16。DoubleDispatch。DDGlass:50  

c16。DoubleDispatch。DDGlass:80  

c16。DoubleDispatch。DDAluminum:81  

c16。DoubleDispatch。DDCardboard:12  

c16。DoubleDispatch。DDGlass:12  

c16。DoubleDispatch。DDGlass:54  

c16。DoubleDispatch。DDAluminum:36  

c16。DoubleDispatch。DDAluminum:93  

c16。DoubleDispatch。DDGlass:93  

c16。DoubleDispatch。DDPaper:80  

c16。DoubleDispatch。DDGlass:36  



                                                                                          610 


…………………………………………………………Page 612……………………………………………………………

c16。DoubleDispatch。DDGlass:12  

c16。DoubleDispatch。DDGlass:60  

c16。DoubleDispatch。DDPaper:66  

c16。DoubleDispatch。DDAluminum:36  

c16。DoubleDispatch。DDCardboard:22  

  

下面列出程序剩余的部分:  

  

//: DoubleDispatch。java  

// Using multiple dispatching to handle more  

// than one unknown type during a method call。  

package c16。doubledispatch;  

import c16。trash。*;  

import java。util。*;  

  

class AluminumBin extends TypedBin {  

  public boolean add(DDAluminum a) {  

    return addIt(a);  

  }  

}  

  

class PaperBin extends TypedBin {  

  public boolean add(DDPaper a) {  

    return addIt(a);  

  }  

}  

  

class GlassBin extends TypedBin {  

  public boolean add(DDGlass a) {  

    return addIt(a);  

  }  

}  

  

class CardboardBin extends TypedBin {  

  public boolean add(DDCardboard a) {  

    return addIt(a);  

  }  

}  

  

class TrashBinSet {  

  private TypedBin'' binSet = {  

    new AluminumBin();  

    new PaperBin();  

    new GlassBin();  

    new CardboardBin()  

  };  

  public void sortIntoBins(Vector bin) {  

    Enumeration e = bin。elements();  

    while(e。hasMoreElements()) {  

      TypedBinMember t =   

        (TypedBinMember)e。nextElement();  

      if(!t。addToBin(binSet))  



                                                                                             611 


…………………………………………………………Page 613……………………………………………………………

        System。err。println(〃Couldn't add 〃 + t);  

    }  

  }  

  public TypedBin'' binSet() { return binSet; }  

}  

  

public class DoubleDispatch {  

  public static void main(String'' args) {  

    Vector bin = new Vector();  

    TrashBinSet bins = new TrashBinSet();  

    // ParseTrash still works; without changes:  

    ParseTrash。fillBin(〃DDTrash。dat〃; bin);  

    // Sort from the master bin into the   

    // individually…typed bins:  

    bins。sortIntoBins(bin);  

    TypedBin'' tb = bins。binSet();  

    // Perform sumValue for each bin。。。  

    for(int i = 0; i 《 tb。length; i++)  

      Trash。sumValue(tb 'i'。v);  

    // 。。。 and for the master bin  

    Trash。sumValue(bin);  

  }  

} ///:~  

  

其中,TrashBinSet 封装了各种不同类型的 TypeBin,同时还有 sortIntoBins()方法。所有双重派遣事件都 

会在那个方法里发生。可以看到,一旦设置好结构,再归类成各种TypeBin 的工作就变得十分简单了。除此 

以外,两个动态方法调用的效率可能也比其他排序方法高一些。  

注意这个系统的方便性主要体现在 main()中,同时还要注意到任何特定的类型信息在main()中都是完全独立 

的。只与Trash 基础类接口通信的其他所有方法都不会受到Trash 类中发生的改变的干扰。  

添加新类型需要作出的改动是完全孤立的:我们随同 addToBin()方法继承Trash 的新类型,然后继承一个新 

的TypeBin (这实际只是一个副本,可以简单地编辑),最后将一种新类型加入TrashBinSet 的集合初化化 

过程。  



16。7 访问器范式  



接下来,让我们思考如何将具有完全不同目标的一个设计范式应用到垃圾归类系统。  

对这个范式,我们不再关心在系统中加入新型 Trash 时的优化。事实上,这个范式使新型Trash 的添加显得 

更加复杂。假定我们有一个基本类结构,它是固定不变的;它或许来自另一个开发者或公司,我们无权对那 

个结构进行任何修改。然而,我们又希望在那个结构里加入新的多形性方法。这意味着我们一般必须在基础 

类的接口里添加某些东西。因此,我们目前面临的困境是一方面需要向基础类添加方法,另一方面又不能改 

动基础类。怎样解决这个问题呢?  

 “访问器”(Visitor)范式使我们能扩展基本类型的接口,方法是创建类型为Visitor 的一个独立的类结 

构,对以后需对基本类型采取的操作进行虚拟。基本类型的任务就是简单地“接收”访问器,然后调用访问 

器的动态绑定方法。看起来就象下面这样:  

  



                                                                                       612 


…………………………………………………………Page 614……………………………………………………………

                                                         

  

现在,假如 v 是一个指向 Aluminum (铝制品)的Visitable 句柄,那么下述代码:  

PriceVisitor pv = new PriceVisitor();  

v。accept(pv);  

会造成两个多形性方法调用:第一个会选择accept()的Aluminum 版本;第二个则在 accept()里——用基础 

类Visitor 句柄v 动态调用 visit()的特定版本时。  

这种配置意味着可采取 Visitor 的新子类的形式将新的�
返回目录 上一页 下一页 回到顶部 赞(0) 踩(0)
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!