【问题标题】:Creating many object types/classes just to use instanceof创建许多对象类型/类只是为了使用 instanceof
【发布时间】:2015-03-22 14:17:27
【问题描述】:

我想知道我是否将对象类型创建/分解为无意义的类,以及是否有更好的方法。

假设我有以下类(--> 扩展更高的类):

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 abstract,对吗?我从不创建 Vehicle 对象。

这样可以吗?或者有更好的方法吗?

【问题讨论】:

  • 我对您使用这些类的方式很感兴趣。
  • 这完全取决于您将如何使用它们。到目前为止,您的结构没有任何问题。您不仅可以将它用于 instanceof,还可以用于诸如 boollean needsPetrol()... canHavePassengers() 之类的方法,您将在子类中实现这些方法,而不是使用 if instanceof 语句链。
  • 你想做什么?
  • 记住一件事,避免在代码中使用instanceof。这就像要求第三方告诉你的类的结构,在这方面它是在询问编译器。而是在摩托车内部创建一个类似public boolean isMotercycle() {return true;} 的函数,但在车辆类中,使用public boolean isMotercycle () {return false;}。这就像类本身提供有关自身的信息
  • 我正在编写一个游戏,这些都是不同的游戏对象。当我进行碰撞检测时,根据碰撞中涉及的对象类型会发生不同的事情。这些不是确切的对象类型,但它是一个类似的示例。啊,感谢那头漂亮的牛,这很有道理。

标签: java oop instanceof


【解决方案1】:

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

【讨论】:

  • @Downvoter:至少也要分享你的想法,同时投反对票。它通过了解他们的错误来帮助社区前进
  • @nIcEcOw 我总是感谢建设性的反馈和改进我的答案的机会。
  • 感谢您的建议,我会考虑使用枚举/状态作为替代方案。再多一分,我可以投票赞成一些答案哈哈。
【解决方案2】:

只要您的类有意义并提供功能,就永远不会出现“太多类”这样的事情。然而,在我看来,有 pointless abstraction 这样的东西。

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

我曾经需要使用 instanceof 条件语句

那么也许有子类就被认为是毫无意义的抽象。只需使用枚举来描述您的车辆类型并继续前进。

但是,如果您预计或计划将您的子类不仅仅用于类型,那么通过使用子类来做到这一点是完全可以的,而且实际上最好在您的 Vehicle 类中使用大量 if/else 或 switch 语句.

【讨论】:

  • 好吧,就目前情况而言,枚举可能更可取。谢谢。
【解决方案3】:

正如在 cmets 和答案中已经指出的那样:这完全取决于您尝试在那里 建模 的内容。

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

所以我只在需要使用 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,它指出您应该创建多个客户端特定的接口,而不是一个可以完成所有工作并因此组合其他不相关方法的大型接口。所以你没有“太多的类”,只要它们每个都有一个目的。你可以问问自己:

  • 谁必须区分GasolineCarElectricCar
  • 谁只需要处理这些接口之一?
  • 当它们都扩展同一个基类时:谁可以使用基类(或者每个人都必须知道具体的实现?)

【讨论】:

  • 感谢您的深入回答。您的 charge() 示例非常有意义,并且确实消除了我在 instanceof 和 isMotorcyle() 方法中使用的条件语句。这就是我无法解决的问题,试图以最多态的方式做到这一点。我很难弄清楚谁推荐了最好的方法,因为有很多方法可以解决,但你的答案的所有部分似乎都是正确的。
【解决方案4】:

这一切都归结为一个问题,您是否需要区分 ElectricCars、GasolineCars 等。如果不需要,您可以将所有内容放入 Vehicle 或 Car 并创建 Vehicle/Car 对象。

如果它不打算创建 Vehicle 对象,那么是的,它应该被标记为抽象的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-23
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 2019-09-10
    • 2021-08-02
    • 2020-08-10
    相关资源
    最近更新 更多