2012-08-17 69 views
1

我需要添加一個子屬性(ProductOption和ProductAttribute)的列表,它們是名爲Product的父對象的屬性。所有這三個類都擴展了一個抽象類CMS。避免使用泛型的instanceof

我想一般性地調用方法「attachChildToParent」,但我推遲instanceof並將其轉換爲產品來推遲不可避免的情況。

有沒有一種方法我可以一般這樣寫,所以我可以避免演員?

要測試:

package puzzler; 

import java.util.ArrayList; 
import java.util.List; 

public class Tester { 
    public static void main(String[] args) { 
     Product p = new Product(); 
     ProductAttribute pa = new ProductAttribute(); 
     ProductOffering po = new ProductOffering(); 

     List<ProductAttribute> lpa = new ArrayList<ProductAttribute>(); 
     List<ProductOffering> lpo = new ArrayList<ProductOffering>(); 

     attachChildToParent(lpa, p); 
    } 

    static void attachChildToParent(List<? extends CMS> listChild, Product parent) { 
     for (CMS cmsItem : listChild) { 
      parent.attach(cmsItem);   
     } 
    } 
} 

Product類(父)

package puzzler; 

import java.util.List; 

abstract class CMS { 
    String node; 
} 
public class Product extends CMS { 
    List<ProductAttribute> lpa; 
    List<ProductOffering> lpo; 

    public List<ProductAttribute> getLpa() { 
     return lpa; 
    } 

    public void setLpa(List<ProductAttribute> lpa) { 
     this.lpa = lpa; 
    } 

    public List<ProductOffering> getLpo() { 
     return lpo; 
    } 

    public void setLpo(List<ProductOffering> lpo) { 
     this.lpo = lpo; 
    } 

    public void attach(ProductAttribute childNode) { 
     this.getLpa().add(childNode); 
    } 

    public void attach(ProductOffering childNode) { 
     this.getLpo().add(childNode); 
    } 

    // I want to avoid this. Defeats the purpose of generics. 
    public void attach(CMS cms) { 
     if (cms instanceof ProductOffering) { 
      this.getLpo().add((ProductOffering) cms); 
     } else   { 
      if (cms instanceof ProductAttribute) { 
       this.getLpa().add((ProductAttribute) cms); 
      } 
     } 
    } 
} 

兒童類1

package puzzler; 

import puzzler.CMS; 

public class ProductAttribute extends CMS { 
    String node; 

    public String getNode() { 
     return node; 
    } 

    public void setNode(String node) { 
     this.node = node; 
    } 
} 

兒童類2

package puzzler; 

import puzzler.CMS; 

public class ProductOffering extends CMS { 
    String node; 

    public String getNode() { 
     return node; 
    } 

    public void setNode(String node) { 
     this.node = node; 
    } 
} 
+0

我還沒有被使用的年齡java的,但在C#中,你可以做像這樣的聲明: FatherType foo = new ChildType(); 和 列表< – Salaros 2012-08-17 12:29:16

回答

5

您可以使用訪問者模式解決鑄件問題:在您的CMS類中,添加一個新的(抽象)方法attachTo(Product parent)。在每個子類中,您可以實現此方法以在父級上調用attach,並且正確的函數將被解析。

0

覆蓋?

public void attach(ProductOffering cms) { 
    this.getLpo().add(cms); 
} 

public void attach(ProductAttribute cms) { 
    this.getLpa().add(cms); 
} 
+0

此代碼已存在:問題是調用站點只知道超級類,它不會在運行時消除歧義。 – 2012-08-17 12:46:10

+0

Doh!對不起,快速解答我只是有一個適當的外觀,你是對的。由於運行時擦除類型,我認爲泛型不會有所幫助。我會有一個想法,但是因爲你有一個邏輯分支,當它傳遞給方法時,你需要在運行時區分實際的實現。你可能不得不重新考慮這個問題。 – Dan 2012-08-17 12:53:16

2

委派到子類:

public void attach(CMS cms) { 
    cms.callAdd(this); 

} 

在CMS添加:

public abstract void callAdd(Product product); 

而且在ProductOffering補充:

public void callAdd(Product product) { 
    getLpo().add(this)  
} 

一個類似的ProductAttribute ...

0

有一些方法可以避免這種情況,但不適用於泛型。泛型允許您編寫允許避免強制轉換的代碼,但在需要避免instanceof時無效。主要原因是所有具有泛型類型的變量在內部都被視爲Object

這就是爲什麼編譯器使用通用attach(CMS)方法,當你從attachChildToParent()叫它:類型孩子的附加將CMS - 有沒有辦法讓編譯器將保持你當你調用使用類型attachChildToParent()

唯一的解決辦法是寫一個在孩子附加方法:

public class ProductAttribute extends CMS { 
    @Override 
    public void attachTo(Product p) { 
     p.getLpo().add(this); 
    } 
} 
+0

謝謝。這是我原來的做法,但它假定父母始終是產品。事實上,這可能總是如此,我正在過度考慮這一點。但是這個難題讓我感到困擾。 – EdgeCase 2012-08-17 13:10:55

+0

您也可以創建一個接口並將其用作'attachTo()'中的參數類型。這可以讓你說「這個孩子可以附加到任何有getLpo()方法的東西」 – 2012-08-17 13:12:10

0

仿製藥也解決不了你的問題。由於您在<? extends CMS>之後鬆開了實例特定的信息,因此List中的所有元素僅爲CMS的子元素。

爲什麼不加簡單的方法,這需要兩個列表作爲適合你的設計也解決了您的問題,這是非常有效的參數

public void attach(List<ProductAttribute> lpa, List<ProductOffering> lpo) { 
    this.lpa.addAll(lpa); 
    this.lpo.addAll(lpo); 
}