简体   繁体   English

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

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

I'm wondering if I'm creating/breaking down object types into meaningless classes and if there is a better way to do it. 我想知道我是否正在创建/分解对象类型为无意义的类,以及是否有更好的方法来做到这一点。

Say I've got the following classes (--> extends the higher class): 假设我有以下类( - > 扩展更高级的类):

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

As you can see, they're mostly default constructors. 如您所见,它们大多是默认构造函数。 So I'm only creating them in case I ever need to use an instanceof conditional statement. 所以我只是创建它们以防我需要使用instanceof条件语句。 Most of my code ends up in the Vehicle class because I'm trying to avoid repeating the same code in every class. 我的大多数代码最终都在Vehicle类中,因为我试图避免在每个类中重复相同的代码。 Also, I should make Vehicle abstract , correct? 另外,我应该让汽车抽象 ,对吗? I never create a Vehicle object. 我从不创建一个Vehicle对象。

Is this OK or is there a better way to do it? 这样可以或有更好的方法吗?

First, as long as the code functions and solves the task at hand I would say it is "correct" enough (so yes, it is okay ). 首先,只要代码起作用并解决手头的任务,我就会说它是“正确”的(所以是的, 没关系 )。 That being said, some people prefer to use interface(s) instead of abstract classes (because you can implement multiple interfaces but only directly extend from one ancestor). 话虽这么说,有些人更喜欢使用接口而不是抽象类(因为你可以实现多个接口但只能直接从一个祖先扩展)。 Further, if you're using Java 8+ you can add default methods to interface(s). 此外,如果您使用的是Java 8+,则可以向接口添加default方法。 Other alternatives might include having one Vehicle class but a VehicleType enum field for the Vehicle class. 其他选择可能包括有一个Vehicle类,但一个VehicleType enum为外地Vehicle类。

There's never such a thing as "too many classes" as long as your classes make sense and serve a function. 只要你的课程有意义并且提供一个功能,就不会有“太多课程”这样的事情。 There is however such a thing as pointless abstraction in my opinion. 然而,在我看来,有一种pointless abstraction

If you're 100% sure that you will only ever use these classes to determine the vehicle type (quote from your question), 如果您100%确定您只使用这些类别来确定车辆类型(引自您的问题),

I ever need to use an instanceof conditional statement 我曾经需要使用instanceof条件语句

Then maybe having sub classes qualifies as pointless abstraction. 然后可能让子类有资格作为无意义的抽象。 Just use an enum instead which describes your vehicles type and move on. 只需使用枚举来描述您的车辆类型并继续前进。

If however you anticipate or plan on using your sub classes for more than just the type, it's completely fine to do it by having sub classes and it's in fact preferred to having lots of if/else or switch statements in your Vehicle class. 但是,如果您预期或计划将子类用于不仅仅是类型,那么通过使用子类来完成它是完全正确的,并且事实上在您的Vehicle类中有很多if / else或switch语句。

As already pointed out in the comments and answers: It all depends on what you are trying to model there. 正如评论和答案中已经指出的那样:这完全取决于你在那里建模的内容

But first of all, regarding the intention that you mentioned: 但首先,关于你提到的意图:

So I'm only creating them in case I ever need to use an instanceof conditional statement. 所以我只是创建它们以防我需要使用instanceof条件语句。

Be careful with that. 小心一点。 You should avoid modeling the different behavior of objects depending on their type. 您应该避免根据对象的类型对对象的不同行为进行建模。 Here, it does not matter whether the type information is 这里,类型信息是否是无关紧要的

  • implicitly available via instanceof checks 通过instanceof检查隐式提供
  • explicitly via a method like boolean isMotorCycle() , as suggested in a comment 显式地通过boolean isMotorCycle()类的方法,如注释中所建议的那样
  • explicitly via something like an enum Type { ... } and a switch over the type. 显式地通过enum Type { ... }switch类型。

They all suffer from the same problem: When you add a new class/type to your hierarchy, then you have to adopt and update all places where this type information was queried. 它们都遇到同样的问题:当您向层次结构中添加新的类/类型时,您必须采用并更新查询此类型信息的所有位置。 This may become a maintainance nightmare. 这可能成为维持噩梦。

There are legitimate uses for type checks. 类型检查合法用途。 But when you end up with writing code that frequently does checks like this 但是当你最终编写经常进行此类检查的代码时

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();
    ...
}

then this is a strong indication that something is wrong with your hierarchy. 然后,这表明您的层次结构存在问题。 It might be that the base class, Vehicle , is simply not powerful enough. 可能是基类Vehicle还不够强大。 In the example above, one could then consider pulling the recharge() method into the Vehicle class, and simply call it, relying on the polymorphic implementation. 在上面的例子中,可以考虑将recharge()方法拉入Vehicle类,并简单地调用它,依赖于多态实现。

It might, in the worst case, also be that the concepts that you are trying to model are simply too unrelated to be combined in a single hierarchy. 在最坏的情况下,也可能是您尝试建模的概念太过无关,无法在单个层次结构中组合。


You mentioned that you want to do collision detection for these objects. 您提到要对这些对象进行碰撞检测。 This sounds like you're already approaching a solution like this: 这听起来像你已经接近这样的解决方案:

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

There are more elegant solutions for that. 有更优雅的解决方案。 You might want to read about the problem related to Double Dispatch , and maybe have a look at the Strategy Pattern . 您可能想了解与Double Dispatch相关的问题,也许可以查看策略模式


More generally, concerning the question of whether you have "too many classes", there are some general rules fo thumb. 更一般地说,关于你是否有“太多课程”的问题,拇指有一些一般规则。

One of them is the Interface Segration Principle , stating that you should create serval client-specific insterfaces, instead of one large interface that does everything and therefore combines otherwise unrelated methods. 其中之一是接口分段原则 ,声明你应该创建serval客户端特定的insterfaces,而不是一个大的接口,它完成所有事情,因此结合了其他不相关的方法。 So you don't have "too many classes", as long as each of them serves a purpose. 所以你没有“太多的课程”,只要每个课程都有用。 You could ask yourself: 你可以问自己:

  • Who will have to differentiate between a GasolineCar and an ElectricCar ? 谁必须区分GasolineCarElectricCar
  • Who will have to deal with only one of these interfaces? 谁将不得不只处理其中一个接口?
  • When they both extend the same base class: Who will be able to use the base class (or will everybody have to know the specific implementation anyhow?) 当它们都扩展相同的基类时:谁能够使用基类(或者每个人都必须知道具体的实现?)

It all comes down to question if you will ever need to distinguish between ElectricCars, GasolineCars etc. If not, you could just put everything into Vehicle or Car and create Vehicle/Car objects. 如果您需要区分ElectricCars,GasolineCars等,这一切都归结为问题。如果没有,您可以将所有内容放入车辆或汽车并创建车辆/汽车对象。

If it is not intended to create Vehicle objects, then yes, it should be marked abstract. 如果它不打算创建Vehicle对象,那么是的,它应该被标记为abstract。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM