2012-03-22 149 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()并检查。但是,我想强调这一点,没有理由这样做,这是不好的做法。但是,你是。