簡體   English   中英

創建許多對象類型/類只是為了使用instanceof

[英]Creating many object types/classes just to use instanceof

我想知道我是否正在創建/分解對象類型為無意義的類,以及是否有更好的方法來做到這一點。

假設我有以下類( - > 擴展更高級的類):

Vehicle class - takes care of movement and a default speed
-->Car class - adds passengers
-->-->ElectricCar class - a default constructor
-->-->GasolineCar class - a default constructor
-->-->HybridCar class - a default constructor
-->Motorcycle class - a default constructor
-->Bike class - a default constructor, overrides speed
-->Segway class - a default constructor, overrides speed

如您所見,它們大多是默認構造函數。 所以我只是創建它們以防我需要使用instanceof條件語句。 我的大多數代碼最終都在Vehicle類中,因為我試圖避免在每個類中重復相同的代碼。 另外,我應該讓汽車抽象 ,對嗎? 我從不創建一個Vehicle對象。

這樣可以或有更好的方法嗎?

首先,只要代碼起作用並解決手頭的任務,我就會說它是“正確”的(所以是的, 沒關系 )。 話雖這么說,有些人更喜歡使用接口而不是抽象類(因為你可以實現多個接口但只能直接從一個祖先擴展)。 此外,如果您使用的是Java 8+,則可以向接口添加default方法。 其他選擇可能包括有一個Vehicle類,但一個VehicleType enum為外地Vehicle類。

只要你的課程有意義並且提供一個功能,就不會有“太多課程”這樣的事情。 然而,在我看來,有一種pointless abstraction

如果您100%確定您只使用這些類別來確定車輛類型(引自您的問題),

我曾經需要使用instanceof條件語句

然后可能讓子類有資格作為無意義的抽象。 只需使用枚舉來描述您的車輛類型並繼續前進。

但是,如果您預期或計划將子類用於不僅僅是類型,那么通過使用子類來完成它是完全正確的,並且事實上在您的Vehicle類中有很多if / else或switch語句。

正如評論和答案中已經指出的那樣:這完全取決於你在那里建模的內容

但首先,關於你提到的意圖:

所以我只是創建它們以防我需要使用instanceof條件語句。

小心一點。 您應該避免根據對象的類型對對象的不同行為進行建模。 這里,類型信息是否是無關緊要的

  • 通過instanceof檢查隱式提供
  • 顯式地通過boolean isMotorCycle()類的方法,如注釋中所建議的那樣
  • 顯式地通過enum Type { ... }switch類型。

它們都遇到同樣的問題:當您向層次結構中添加新的類/類型時,您必須采用並更新查詢此類型信息的所有位置。 這可能成為維持噩夢。

類型檢查合法用途。 但是當你最終編寫經常進行此類檢查的代碼時

void recharge(Vehicle v) {
    if (v instanceof ElectricCar) ((ElectricCar)v).attachPlug();
    if (v instanceof GasolineCar) ((GasolineCar)v).fillFuel();
    if (v instanceof Bike)        ((Bike)v).getDriver().takeRest();
    ...
}

然后,這表明您的層次結構存在問題。 可能是基類Vehicle還不夠強大。 在上面的例子中,可以考慮將recharge()方法拉入Vehicle類,並簡單地調用它,依賴於多態實現。

在最壞的情況下,也可能是您嘗試建模的概念太過無關,無法在單個層次結構中組合。


您提到要對這些對象進行碰撞檢測。 這聽起來像你已經接近這樣的解決方案:

class Bike extends Vehicle {
    @Override 
    void collideWith(Vehicle other) {
        if (other instanceof Car) collideWithCar((Car)other);
        if (other instanceof Segway) collideWithSegway((Segway)other);
        ...
    }
}

有更優雅的解決方案。 您可能想了解與Double Dispatch相關的問題,也許可以查看策略模式


更一般地說,關於你是否有“太多課程”的問題,拇指有一些一般規則。

其中之一是接口分段原則 ,聲明你應該創建serval客戶端特定的insterfaces,而不是一個大的接口,它完成所有事情,因此結合了其他不相關的方法。 所以你沒有“太多的課程”,只要每個課程都有用。 你可以問自己:

  • 誰必須區分GasolineCarElectricCar
  • 誰將不得不只處理其中一個接口?
  • 當它們都擴展相同的基類時:誰能夠使用基類(或者每個人都必須知道具體的實現?)

如果您需要區分ElectricCars,GasolineCars等,這一切都歸結為問題。如果沒有,您可以將所有內容放入車輛或汽車並創建車輛/汽車對象。

如果它不打算創建Vehicle對象,那么是的,它應該被標記為abstract。

暫無
暫無

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

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