JAVA范式三--模擬垃圾回收站
發(fā)布時(shí)間:2008-08-06 閱讀數(shù): 次 來(lái)源:網(wǎng)樂(lè)原科技
這個(gè)問(wèn)題的本質(zhì)是若將垃圾丟進(jìn)單個(gè)垃圾筒,事實(shí)上是未經(jīng)分類的。但在以后,某些特殊的信息必須恢復(fù),以便對(duì)垃圾正確地歸類。在最開(kāi)始的解決方案中,RTTI扮演了關(guān)鍵的角色(詳見(jiàn)第11章)。
這并不是一種普通的設(shè)計(jì),因?yàn)樗黾恿艘粋€(gè)新的限制。正是這個(gè)限制使問(wèn)題變得非常有趣——它更象我們?cè)诠ぷ髦信龅降哪切┓浅B闊┑膯?wèn)題。這個(gè)額外的限制是:垃圾抵達(dá)垃圾回收站時(shí),它們?nèi)际腔旌显谝黄鸬摹3绦虮仨殲槟切├姆诸惗ǔ鲆粋€(gè)模型。這正是RTTI發(fā)揮作用的地方:我們有大量不知名的垃圾,程序?qū)⒄_判斷出它們所屬的類型。
//: RecycleA.java
// Recycling with RTTI
package c16.recyclea;
import java.util.*;
import java.io.*;
abstract class Trash {
private double weight;
Trash(double wt) { weight = wt; }
abstract double value();
double weight() { return weight; }
// Sums the value of Trash in a bin:
static void sumValue(Vector bin) {
Enumeration e = bin.elements();
double val = 0.0f;
while(e.hasMoreElements()) {
// One kind of RTTI:
// A dynamically-checked cast
Trash t = (Trash)e.nextElement();
// Polymorphism in action:
val += t.weight() * t.value();
System.out.println(
"weight of " +
// Using RTTI to get type
// information about the class:
t.getClass().getName() +
" = " + t.weight());
}
System.out.println("Total value = " + val);
}
}
class Aluminum extends Trash {
static double val = 1.67f;
Aluminum(double wt) { super(wt); }
double value() { return val; }
static void value(double newval) {
val = newval;
}
}
class Paper extends Trash {
static double val = 0.10f;
Paper(double wt) { super(wt); }
double value() { return val; }
static void value(double newval) {
val = newval;
}
}
class Glass extends Trash {
static double val = 0.23f;
Glass(double wt) { super(wt); }
double value() { return val; }
static void value(double newval) {
val = newval;
}
}
public class RecycleA {
public static void main(String[] args) {
Vector bin = new Vector();
// Fill up the Trash bin:
for(int i = 0; i < 30; i++)
switch((int)(Math.random() * 3)) {
case 0 :
bin.addElement(new
Aluminum(Math.random() * 100));
break;
case 1 :
bin.addElement(new
Paper(Math.random() * 100));
break;
case 2 :
bin.addElement(new
Glass(Math.random() * 100));
}
Vector
glassBin = new Vector(),
paperBin = new Vector(),
alBin = new Vector();
Enumeration sorter = bin.elements();
// Sort the Trash:
while(sorter.hasMoreElements()) {
Object t = sorter.nextElement();
// RTTI to show class membership:
if(t instanceof Aluminum)
alBin.addElement(t);
if(t instanceof Paper)
paperBin.addElement(t);
if(t instanceof Glass)
glassBin.addElement(t);
}
Trash.sumValue(alBin);
Trash.sumValue(paperBin);
Trash.sumValue(glassBin);
Trash.sumValue(bin);
}
} ///:~
要注意的第一個(gè)地方是package語(yǔ)句:
package c16.recyclea;
這意味著在本書(shū)采用的源碼目錄中,這個(gè)文件會(huì)被置入從c16(代表第16章的程序)分支出來(lái)的recyclea子目錄中。第17章的解包工具會(huì)負(fù)責(zé)將其置入正確的子目錄。之所以要這樣做,是因?yàn)楸菊聲?huì)多次改寫(xiě)這個(gè)特定的例子;它的每個(gè)版本都會(huì)置入自己的“包”(package)內(nèi),避免類名的沖突。
其中創(chuàng)建了幾個(gè)Vector對(duì)象,用于容納Trash句柄。當(dāng)然,Vector實(shí)際容納的是Object(對(duì)象),所以它們最終能夠容納任何東西。之所以要它們?nèi)菁{Trash(或者從Trash衍生出來(lái)的其他東西),唯一的理由是我們需要謹(jǐn)慎地避免放入除Trash以外的其他任何東西。如果真的把某些“錯(cuò)誤”的東西置入Vector,那么不會(huì)在編譯期得到出錯(cuò)或警告提示——只能通過(guò)運(yùn)行期的一個(gè)違例知道自己已經(jīng)犯了錯(cuò)誤。
Trash句柄加入后,它們會(huì)丟失自己的特定標(biāo)識(shí)信息,只會(huì)成為簡(jiǎn)單的Object句柄(上溯造型)。然而,由于存在多形性的因素,所以在我們通過(guò)Enumeration sorter調(diào)用動(dòng)態(tài)綁定方法時(shí),一旦結(jié)果Object已經(jīng)造型回Trash,仍然會(huì)發(fā)生正確的行為。sumValue()也用一個(gè)Enumeration對(duì)Vector中的每個(gè)對(duì)象進(jìn)行操作。
表面上持,先把Trash的類型上溯造型到一個(gè)集合容納基礎(chǔ)類型的句柄,再回過(guò)頭重新下溯造型,這似乎是一種非常愚蠢的做法。為什么不只是一開(kāi)始就將垃圾置入適當(dāng)?shù)娜萜骼锬??(事?shí)上,這正是撥開(kāi)“回收”一團(tuán)迷霧的關(guān)鍵)。在這個(gè)程序中,我們很容易就可以換成這種做法,但在某些情況下,系統(tǒng)的結(jié)構(gòu)及靈活性都能從下溯造型中得到極大的好處。
該程序已滿足了設(shè)計(jì)的初衷:它能夠正常工作!只要這是個(gè)一次性的方案,就會(huì)顯得非常出色。但是,真正有用的程序應(yīng)該能夠在任何時(shí)候解決問(wèn)題。所以必須問(wèn)自己這樣一個(gè)問(wèn)題:“如果情況發(fā)生了變化,它還能工作嗎?”舉個(gè)例子來(lái)說(shuō),厚紙板現(xiàn)在是一種非常有價(jià)值的可回收物品,那么如何把它集成到系統(tǒng)中呢(特別是程序很大很復(fù)雜的時(shí)候)?由于前面在switch語(yǔ)句中的類型檢查編碼可能散布于整個(gè)程序,所以每次加入一種新類型時(shí),都必須找到所有那些編碼。若不慎遺漏一個(gè),編譯器除了指出存在一個(gè)錯(cuò)誤之外,不能再提供任何有價(jià)值的幫助。
RTTI在這里使用不當(dāng)?shù)年P(guān)鍵是“每種類型都進(jìn)行了測(cè)試”。如果由于類型的子集需要特殊的對(duì)待,所以只尋找那個(gè)子集,那么情況就會(huì)變得好一些。但假如在一個(gè)switch語(yǔ)句中查找每一種類型,那么很可能錯(cuò)過(guò)一個(gè)重點(diǎn),使最終的代碼很難維護(hù)。在下一節(jié)中,大家會(huì)學(xué)習(xí)如何逐步對(duì)這個(gè)程序進(jìn)行改進(jìn),使其顯得越來(lái)越靈活。這是在程序設(shè)計(jì)中一種非常有意義的例子。