これはクラス設計でよくある問題ですが、問題の詳細によって解決策が異なるため、残念ながら、単一の適切な解決策はありません。現在の設計よりも優れた設計は、各型の型情報と機能が、ユニットなどの共通のインターフェースを介して表現される設計です。
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())
}
}
また、インターフェースと実装の間にすっきりとした休憩をとれば、あなたの生活はよりシンプルになるので、ユニットは実際には次のようになります。
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())
}
}