我想知道我是否正在创建/分解对象类型为无意义的类,以及是否有更好的方法来实现它。
说我有以下课程( - > 延伸更高级别):
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对象。
这样做还是有更好的方法吗?
答案 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,而不是一个完成所有事情的大型接口,因此结合了其他不相关的方法。所以你没有“太多的课程”,只要每个课程都有用。你可以问自己:
GasolineCar
和ElectricCar
? 答案 3 :(得分:2)
如果您需要区分ElectricCars,GasolineCars等,这一切都归结为问题。如果没有,您可以将所有物品放入车辆或汽车中并创建车辆/汽车物品。
如果不打算创建Vehicle对象,那么应该将其标记为abstract。