簡體   English   中英

具有分層復合模式的Java泛型錯誤

[英]Java generics error with layered composite pattern

我正在使用泛型來限制復合層次結構中的子類型,這樣我就可以在層次結構的不同層強制使用不同的類型。

例如,具有(Business:Division:Department:Group:Person)層次結構,其中每個級別的復合節點僅接受正確類型的子節點(層次結構中的下一個較低級別)。 因此,我將在實例化的每個級別類型中使用泛型構造復合中的級別,以僅接受來自下一個較低級別的節點。

但是我對泛型有誤,並且不確定它是否表示設計錯誤,或者只是java Generics不能為我做的事情。 這個想法似乎有效,我只想限制add()方法接受的類型,只接受層次結構中特定下一級的子類型來強制結構級別。 由於我只是在每個階段降低類型的上限,所以發送到列表的所有消息仍然有效。

典型GOF-Composite模式中的頂級節點:

   public abstract class Business { ... }

復合節點層次結構頂級:

  public abstract class Group extends Business {

    protected List<Business> subs;      // composite links
    public Group add(Business comp) {
        subs.add(comp);
        return this;
    }

復合層次結構中的后續級別:

 public class Area<T extends Business> extends Group {

    protected List<Business> subs;      // composite links

    public Area(String title){
        super(title);
        subs = new ArrayList<Business>();
    }

    @Override
    public Group add(T comp) {    // ** Error Here **
        super.add(comp);
        return this;
    }

錯誤是:

  Multiple markers at this line - The method add(T) of type Area<T> must override a superclass method 

- 名稱沖突:類型為Area的add(T)方法與Group類型的add(Business)具有相同的擦除功能但不覆蓋它

我嘗試了一個變體,我給了Group :: add()方法一個類似的類型,所以他們會有相同的類型簽名,

public group add(T comp){...}

但是同樣失敗了:

  Multiple markers at this line 

- 類型的方法add(T)必須覆蓋超類方法 - 覆蓋labs.composite.company.Group.add - 名稱沖突:類型為Area的方法add(T)與add(T)類型具有相同的刪除分組,但不會覆蓋它

我在這里遺漏了什么嗎??? TIA

PS:實際上我認為這種泛型的使用並不能完全符合我的要求(即使它確實有效!),因為我不僅希望改變每個級別的上限,而且需要特定的單個級別。類型層次結構,而不是任何協變參數類型。 我真的想要這樣的東西,“ 對於任何類型的T,它是Composite的子類型,在add()方法中只接受那種類型的對象 ”,我認為相反,泛型說“ 接受任何對象作為參數是Composite的子類型 “。 我認為這是不可能的,因為Java中的參數是協變的,並且LSP將始終允許使用子類型。

如果你的問題是為什么錯誤,原因很簡單: TArea可以的無限Business的子類,而BusinessGroup是一個非常具體的類。 兩種方法都不一樣。 編譯器在執行類型檢查時主要使用完整類型(即使它還考慮了某種警告和特殊情況的刪除)。 這是仿制葯的全部要點。 否則,最好還原為pre-generics代碼樣式(仍然支持)。

如果沒有,那么我不明白這個問題。 但是,我還要補充幾點意見:

1)繼承描述“是一種”關系,而不是“有”或“由......組成”的關系。 在代碼中,您說Group是一種Business ,而Area是一種Group 對我而言,認為Group 屬於 Business (即Business 擁有 Group )更為自然。 Group s和Area s也是如此。 這兩種關系都不是遺傳,而是構成。

2)當在class Group<T extends Business>定義方法add(T comp) ,在class Area<T extends Business>定義方法add(T comp) ,你說Group::addArea:add有相同的簽名。 那不對。 組中的通用參數T 完全獨立於區域中的T 為什么? 假設B1B2是Bussiness的子類,但彼此不是。 沒有人可以說Area<B1>:add()Group<B2>:add()具有相同的簽名。 事實上,這種等價的唯一情況是泛型參數是相同的(即Area<B1>Group<B1> )。 當等效性僅在少數特定情況下(代碼未另外描述)時,Java不能認為簽名等效。

3)GOF的復合設計模式不適用於這種情況,因為它不代表層次結構 ,而是我們稱之為“不受限制”的組合。 根據這種模式, aComposite可以包含differentComponents Component ,但是這些Component可以是任何類型的Composite ,無論類層次結構有多高或多低。 你想要的是differentComponents ,它們是最低級的。 不多也不少。

我不記得曾將此案例視為一種設計模式。 可能是因為它太簡單了。 請參閱下一點中的最后一個變體4)。

4)您的代碼應該采用以下形式:

public class Grouping<C,T> {
    C curr;
    List<T> subs;
    public C add(T comp) {
        this.subs.add(comp);
        return this.curr ;
    }
}

public class Business extends Grouping<Business,Group> {
    // Grouping::add does not need to be overriden
}
public class Group extends Grouping<Group,Area> {
    // Grouping::add does not need to be overriden
}

等等。 如果允許方法add返回void而不是C ,則可以刪除所有類中的泛型參數:

public class Grouping<T> {
    List<T> subs;
    public void add(T comp) {
        this.subs.add(comp);
    }
}

public class Business extends Grouping<Group> {
    // Grouping::add does not need to be overriden
}
public class Group extends Grouping<Area> {
    // Grouping::add does not need to be overriden
}

如果你想讓它變得非常簡單(但也許不那么強大):

public class Business {
    List<Group> subs;
    public Business add(Group comp) {
        this.subs.add(comp);
        return this ;
    }
}
public class Group {
    List<Area> subs;
    public Group add(Area comp) {
        this.subs.add(comp);
        return this ;
    }
}

這會創建代碼重復(在每個類中add方法),在更現實的情況下可能會更高(您可能還需要方法countlistretrieve等)。

覆蓋是指當您擁有相同的簽名時,您的簽名是不同的,因此它不是有效的覆蓋。 你的方法簽名應該是。

public Group add(Business comp)

  1. 既然T必須擴展業務,我無法理解為什么這是一個問題,如果它只是擺脫覆蓋注釋。

  2. 您可能會混淆覆蓋重載,這是簽名不同但名稱相同的情況。

  3. 從技術上講, @Override注釋沒有任何功能,它只是在那里捕獲程序員錯誤,所以如果它不編譯只是擺脫它

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM