2012-03-22 77 views
0

類:如何在運行時識別對象的類型?

public abstract class BaseHolidayPackageVariant { 
    private Integer variantId; 
    private HolidayPackage holidayPackage; 
    private String holidayPackageType; 
} 

public class LandHolidayPackageVariant extends BaseHolidayPackageVariant{ 

} 

public class FlightHolidayPackageVariant extends BaseHolidayPackageVariant{ 
    private Destination originCity; 
} 

public class HolidayPackage{ 
    ArrayList<BaseHolidayPackageVariant> variants; 

    BaseHolidayPackageVariant defaultVariant; 
} 

在運行時,我怎麼能知道,如果在多個變[]給定對象爲LandPackageVariant類型或FlightPackageVariant沒有做各種各樣的東西:

if(holidayPackageType.equals("LandHolidayPackageVariant") 
obj = (LandHolidayPackageVariant)variant[i]; 
else if(holidayPackageType.equals("FlightHolidayPackageVariant") 
obj = (FlightHolidayPackageVariant)variant[i]; 

這個問題源於從設計的問題,我問here

回答

5

在一個好的面向對象的設計中,你永遠不需要知道對象是否是特定的類型。你只需調用它的方法,該對象就是正確的。

例如,FlightHolidayPackageVariant有一個字段originCity,是不是在其他HolidayPackageVariant類,要渲染,在UI。解決這個問題的面向對象的方式是讓HolidayPackageVariant以某種方式來控制自己的渲染。假設您的用戶界面將顯示每個變體的屬性列表。您可以讓變型提供這些列表:

public abstract class BaseHolidayPackageVariant { 
    private int cost; 

    public Map<String, String> getDetails() { 
     HashMap<String, String> details = new HashMap<String, String>(); 
     details.put("cost", String.format("%.2f", cost/100.0)); 
     return details; 
    } 
} 

public class FlightHolidayPackageVariant extends BaseHolidayPackageVariant { 
    private Destination originCity; 

    @Override 
    public Map<String, String> getDetails() { 
     Map<String, String> details = super.getDetails(); 
     details.put("origin city", originCity.getName()); 
     return details; 
    } 
} 

現在,你的UI代碼可以簡單地詢問其詳細信息的每個變量對象,而不必知道它是什麼樣的變異體。

+0

同意關於特定類型。否則我不知道如何建模。例如如果您查看「FlightHolidayPackageVariant」,它會添加一個成員:「OriginCity」。在給定的'HolidayPackageVariant'變體[]中,當我渲染一個'FlightHolidayPackageVariant'時,我想呈現'OriginCity'的名字。我無法從'BaseHolidayPackageVariant'中檢索到這個文件。 – brainydexter 2012-03-22 14:04:49

+0

增加了一個可能解決這個問題的例子。 – 2012-03-22 14:50:08

+0

感謝您的編輯,我明白了您的觀點。我的腦袋裏有一個相關的問題,我似乎無法回答。遵循以不同方式呈現變體的同一個示例,我還想將(視圖)aka渲染細節保留在我的對象模型之外。我如何使用您提供的解決方案來支持? – brainydexter 2012-03-22 18:59:37

3

試試這個:

if (variant[i] instanceof LandHolidayPackageVariant) { 
    LandHolidayPackageVariant obj = (LandHolidayPackageVariant)variant[i]; 
    // do stuff 
} 
else if (variant[i] instanceof FlightHolidayPackageVariant) { 
    FlightHolidayPackageVariant obj = (FlightHolidayPackageVariant)variant[i]; 
    // do other stuff 
} 

請注意,如果您也有類型派生自這些類型之一,則應檢查那些的第一個,因爲上面的檢查也會在該情況下返回true。

更好的方法可能是讓派生類通過定義適當的方法在基類上重寫來實現所需的特定邏輯。這樣你就不需要檢查類型,並且可以充分利用多態性。

+0

只需注意,如果變體[i]是類型爲「DerivedLandHolidayPackageVariant」[它擴展了LandHolidayPackageVariant],它可能會返回'true',這可能是也可能不是您想要的 - 只是意識到它。 – amit 2012-03-22 13:59:41

+0

@ Botz3000這種方法很容易出現問題,具體取決於if條件的順序,特別是如果在其派生類型之前檢查超類型。我現在有一個小的變體列表,但我有用例,這將會增長。有沒有更好的方法來處理這個問題? – brainydexter 2012-03-22 14:00:35

+0

當然。在我的文章中添加了一些說明。 @brainydexter也許你可以將邏輯移動到你的基類上的一個方法,所以派生類可以自己提供邏輯?那麼你也不需要typechecks。 – Botz3000 2012-03-22 14:01:55

1

這樣的:

if(object instanceof LandPackageVariant) { 
    System.out.println("it's a LandPackageVariant"); 
} 
1
if(holidayPackageType.equals("LandHolidayPackageVariant") 
obj = (LandHolidayPackageVariant)variant[i]; 
else if(holidayPackageType.equals("FlightHolidayPackageVariant") 
obj = (FlightHolidayPackageVariant)variant[i]; 

那麼這樣做obj必須是一個BaseHolidayPackageVariant,所以你甚至不需要投也不做if啄。

如果你想要一個特定類Land或Flight來調用特定方法的對象,那麼你可能應該檢查你的Object模型。

0

您可以使用instanceof。

例如: {

enter code here 
if (variant[i] instanceof LandHolidayPackageVariant) { 
    //do something 
} else if(variant[i] instanceof FlightHolidayPackageVariant){ 
    //do something 
} 

}

看看:HTTP://www.java2s.com/Tutorial/Java/0060__Operators/TheinstanceofKeyword.htm

甲更好的選擇是設計你的程序,以便你不需要instanceof Operator。

0

可以使用instanceof運營商這樣的:

if (variant[i] instanceof LandHolidayPackageVariant) 
    obj = (LandHolidayPackageVariant) variant[i]; 

但是,通常你應該不需要它。有幾個很好的理由使用instanceof來區分類,但通常子類本身應該提供通過它們的通用超類接口所需的不同功能。

0

是的,這裏的答案都是 - 自相矛盾 - 對。

湯姆的答案是你的問題是可疑的是在球上。通常沒有理由從其層次結構中確定對象的特定類型。 (我的意思是在幻想的反射用途之外)

Botz3000的答案是(就像我剛剛出現的所有其他人一樣)在技術上是正確的。

有人猜測,你正在研究在該類中調用哪種方法?在這種情況下,使用@Override註釋,重新定義子類中的方法,並在父級(或基礎事物的具體版本?)中提供抽象方法。

從您的類名稱,我懷疑你應該在抽象工廠模式和(非常簡單)的戰略模式中有一個快速的標準。

PS如果你想得到看中並使用反射,你可以調用getClass()並檢查。但是,我想強調這一點,沒有理由這樣做,這是不好的做法。但是,你是。