当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:16:00  来源:本站整理

实现双重调派[Java编程]

赞助商链接



  本文“实现双重调派[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:

记着多形性只能通过办法调用才能表现出来,所以假定想使双重调派精确举行,必须履行两个办法调用:

在每种构造中都用一个来判断此中的范例.在Trash构造中,将利用一个新的办法调用addToBin(),它采取的参数是由TypeBin构成的一个数组.那个办法将在数组中遍历,尝试将自己加入得当的垃圾筒,这里恰是双重调派发生的地方.

新成立的分级构造是TypeBin,此中包含了它自己的一个办法,名为add(),并且也利用了多形性.但要注意一个新特点:add()已举行了“过载”处理,可承受差别的垃圾范例作为参数.因此,双重满意机制的一个关键点是它也要触及到过载.
程序的重新计划也带来了一个问题:目前的底子类Trash必须包含一个addToBin()办法.为办理这个问题,一个最直接的办法是复制全部代码,并改正底子类.但是,假定没有对源码的掌握权,那么还有另一个办法可以考虑:将addToBin()办法置入一个接口内部,保持Trash不变,并担当新的、特别的范例Aluminum,Paper,Glass以及Cardboard.我们在这里预备采纳后一个办法.
这个计划筹划顶用到的大大都类都必须设为public(公用)属性,所以它们安排于自己的类内.下面列出接口代码:

//: TypedBinMember.java
// An interface for adding the double dispatching
// method to the trash hierarchy without 
// modifying the original hierarchy.
package c16.doubledispatch;

interface TypedBinMember {
  // The new method:
  boolean addToBin(TypedBin[] tb);
} ///:~

在Aluminum,Paper,Glass以及Cardboard每个特定的子范例内,城市实现接口TypeBinMember的addToBin()办法,但每种情形下利用的代码“仿佛”都是完好一样的:

//: DDAluminum.java
// Aluminum for double dispatching
package c16.doubledispatch;
import c16.trash.*;

public class DDAluminum extends Aluminum 
    implements TypedBinMember {
  public DDAluminum(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;
  }
} ///:~
//: DDPaper.java
// Paper for double dispatching
package c16.doubledispatch;
import c16.trash.*;

public class DDPaper extends Paper 
    implements TypedBinMember {
  public DDPaper(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;
  }
} ///:~
//: DDGlass.java
// Glass for double dispatching
package c16.doubledispatch;
import c16.trash.*;

public class DDGlass extends Glass 
    implements TypedBinMember {
  public DDGlass(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;
  }
} ///:~
//: DDCardboard.java
// Cardboard for double dispatching
package c16.doubledispatch;
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;
  }
  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
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))
        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的调集初化化历程.
  以上是“实现双重调派[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • 实现双重调派
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .