<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 16.6 多重分發 上述設計模式肯定是令人滿意的。系統內新類型的加入涉及添加或修改不同的類,但沒有必要在系統內對代碼作大范圍的改動。除此以外,RTTI并不象它在`RecycleA.java`里那樣被不當地使用。然而,我們仍然有可能更深入一步,以最“純”的角度來看待RTTI, 考慮如何在垃圾分類系統中將它完全消滅。 為達到這個目標,首先必須認識到:對所有與不同類型有特殊關聯的活動來說——比如偵測一種垃圾的具體類型,并把它置入適當的垃圾筒里——這些活動都應當通過多態性以及動態綁定加以控制。 以前的例子都是先按類型排序,再對屬于某種特殊類型的一系列元素進行操作。現在一旦需要操作特定的類型,就請先停下來想一想。事實上,多態性(動態綁定的方法調用)整個的宗旨就是幫我們管理與不同類型有特殊關聯的信息。既然如此,為什么還要自己去檢查類型呢? 答案在于大家或許不以為然的一個道理:Java只執行單一分發。也就是說,假如對多個類型未知的對象執行某項操作,Java只會為那些類型中的一種調用動態綁定機制。這當然不能解決問題,所以最后不得不人工判斷某些類型,才能有效地產生自己的動態綁定行為。 為解決這個缺陷,我們需要用到“多重分發”機制,這意味著需要建立一個配置,使單一方法調用能產生多個動態方法調用,從而在一次處理過程中正確判斷出多種類型。為達到這個要求,需要對多個類型結構進行操作:每一次分發都需要一個類型結構。下面的例子將對兩個結構進行操作:現有的Trash系列以及由垃圾筒(Trash Bin)的類型構成的一個系列——不同的垃圾或廢品將置入這些筒內。第二個分級結構并非絕對顯然的。在這種情況下,我們需要人為地創建它,以執行多重分發(由于本例只涉及兩次分發,所以稱為“雙重分發”)。 ## 16.6.1 實現雙重分發 記住多態性只能通過方法調用才能表現出來,所以假如想使雙重分發正確進行,必須執行兩個方法調用:在每種結構中都用一個來判斷其中的類型。在`Trash`結構中,將使用一個新的方法調用`addToBin()`,它采用的參數是由`TypeBin`構成的一個數組。那個方法將在數組中遍歷,嘗試將自己加入適當的垃圾筒,這里正是雙重分發發生的地方。 ![](https://box.kancloud.cn/b68957fc7b09b1772b7f843bcc30b99f_500x312.gif) 新建立的分級結構是`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`的集合初化化過程。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看