创建许多对象类型/类只是为了使用instanceof

时间:2015-03-22 14:17:27

标签: java oop 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对象。

这样做还是有更好的方法吗?

4 个答案:

答案 0 :(得分:4)

首先,只要代码起作用并解决手头的任务,我就会说它足够“正确”(所以是的,它是好的)。话虽这么说,有些人更喜欢使用接口而不是抽象类(因为你可以实现多个接口但只能直接从一个祖先扩展)。此外,如果您使用的是Java 8+,则可以向接口添加default方法。其他替代方案可能包括为Vehicle类提供一个VehicleType类但enum Vehicle字段。

答案 1 :(得分:4)

从来没有这样的事情和#34;太多的课程"只要你的课程有意义并提供一个功能。然而,在我看来,有pointless abstraction这样的事情。

如果您100%确定您只会使用这些类别来确定车辆类型(引自您的问题),

  

我曾经需要使用条件语句的实例

然后可能让子类有资格作为无意义的抽象。只需使用枚举来描述您的车辆类型并继续前进。

但是,如果您预期或计划使用您的子类而不仅仅是类型,那么通过使用子类来完成它是完全正确的,并且它实际上更倾向于拥有大量的if /在您的Vehicle类中使用else或switch语句。

答案 2 :(得分:4)

正如评论和答案中已经指出的那样:这完全取决于你在那里尝试模型

但首先,关于你提到的意图:

  

所以我只是创建它们,以防我需要使用 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相关的问题,也许可以查看Strategy Pattern


更一般地说,关于你是否有“太多课程”的问题,拇指有一些一般规则。

其中一个是Interface Segration Principle,声明你应该创建serval客户端特定的insterfaces,而不是一个完成所有事情的大型接口,因此结合了其他不相关的方法。所以你没有“太多的课程”,只要每个课程都有用。你可以问自己:

  • 谁必须区分GasolineCarElectricCar
  • 谁将不得不只处理其中一个接口?
  • 当它们都扩展相同的基类时:谁能够使用基类(或者每个人都必须知道具体的实现?)

答案 3 :(得分:2)

如果您需要区分ElectricCars,GasolineCars等,这一切都归结为问题。如果没有,您可以将所有物品放入车辆或汽车中并创建车辆/汽车物品。

如果不打算创建Vehicle对象,那么应该将其标记为abstract。