这是类设计中很常见的问题,不幸的是,没有一个好的解决方案,因为解决方案会随着问题的细节而变化。比您现在拥有的更好的设计是通过一个通用接口(例如您的 Unit)来表达每种类型的类型信息和功能。
这是一种我认为更好的可能性,尽管有些人会认为它仍然不是很好,因为抛出 UnsupportedOperationException 的方法。我使用 Groovy 更简洁,但它与 Java 足够接近,您应该明白这一点。看看它是否满足您的需求:
abstract class Unit {
enum UnitType { TROOP, VEHICLE }
abstract UnitType getType()
TroopAbilities getTroopAbilities() {
throw new UnsupportedOperationException('not a Troop')
}
VehicleAbilities getVehicleAbilities() {
throw new UnsupportedOperationException('not a Vehicle')
}
}
interface TroopAbilities {
void doTroopThing()
}
interface VehicleAbilities {
void doVehicleThing()
}
class Troop extends Unit implements TroopAbilities {
void doTroopThing() { println 'something troopy' }
UnitType getType() { UnitType.TROOP }
TroopAbilities getTroopAbilities() { this }
}
class Vehicle extends Unit implements VehicleAbilities {
void doVehicleThing() { println 'something vehicle-ish' }
UnitType getType() { UnitType.VEHICLE }
VehicleAbilities getVehicleAbilities() { this }
}
List<Unit> units = [new Troop(), new Vehicle(), new Troop()]
for (Unit unit : units) {
switch (unit.getType()) {
case Unit.UnitType.TROOP:
unit.getTroopAbilities().doTroopThing()
break;
case Unit.UnitType.VEHICLE:
unit.getVehicleAbilities().doVehicleThing()
break;
default:
throw new IllegalStateException(
"New unit type that's not accounted for: " + unit.getType())
}
}
此外,如果你在接口和实现之间做出明确的突破,你的生活会更简单,所以 Unit 应该更像:
interface Unit {
enum UnitType { TROOP, VEHICLE }
UnitType getType()
TroopAbilities getTroopAbilities()
VehicleAbilities getVehicleAbilities()
}
abstract class AbstractUnit implements Unit {
TroopAbilities getTroopAbilities() {
throw new UnsupportedOperationException('not a Troop')
}
VehicleAbilities getVehicleAbilities() {
throw new UnsupportedOperationException('not a Vehicle')
}
}
然后,您的具体单元类型将扩展 AbstractUnit,然后您正确地使用继承来实现代码重用和多态性,以允许每个子类以自己的方式对消息做出反应。唯一的灰色区域是 get*Abilties() 方法,但目前我想不出解决这些问题的好方法。
更新以减少工作量:如果您想将其缩减到最低限度并删除一些可扩展性选项和枚举的安全性,您可以这样做:
interface Unit {
abstract String getType()
Troop asTroop()
Vehicle asVehicle()
}
abstract class AbstractUnit implements Unit {
Troop asTroop() {
throw new UnsupportedOperationException('not a Troop')
}
Vehicle asVehicle() {
throw new UnsupportedOperationException('not a Vehicle')
}
}
class Troop extends AbstractUnit {
void doTroopThing() { println 'something troopy' }
String getType() { "troop" }
Troop asTroop() { this }
}
class Vehicle extends AbstractUnit {
void doVehicleThing() { println 'something vehicle-ish' }
String getType() { "vehicle" }
Vehicle asVehicle() { this }
}
List<Unit> units = [new Troop(), new Vehicle(), new Troop()]
for (Unit unit : units) {
switch (unit.getType()) {
case "troop":
unit.asTroop().doTroopThing()
break;
case "vehicle":
unit.asVehicle().doVehicleThing()
break;
default:
throw new IllegalStateException(
"New unit type that's not accounted for: " + unit.getType())
}
}