Reputation: 11
I am quite new to java and need help in setting up the implementation of the method in a more sophisticated way - I have written this, but was told I need to use one of the GoF patterns in order to beautify it. Some help as to what I need to do would be most appropriated
protected void setWeapon() {
if (this.getClass().getSimpleName().equals("FighterJet")) {
this.weapon = new GuidedMissileSystem();
System.out.println("FighterJet " + id + " equipped with " + weapon.getClass().getSimpleName());
} else if (this.getClass().getSimpleName().equals("AttackHelicopter")) {
this.weapon = new GrenadeLauncher();
System.out.println("AttackHelicopter " + id + " equipped with " + weapon.getClass().getSimpleName());
} else if (this.getClass().getSimpleName().equals("Tank")) {
this.weapon = new Cannon();
System.out.println("Tank " + id + " equipped with " + weapon.getClass().getSimpleName());
} else if (this.getClass().getSimpleName().equals("InfantryMobilityVehicle")) {
this.weapon = new MachineGun();
System.out.println("InfantryMobilityVehicle " + id + " equipped with " + weapon.getClass().getSimpleName());
} else if (this.getClass().getSimpleName().equals("Warship")) {
this.weapon = new RocketLauncher();
System.out.println("Warship " + id + " equipped with " + weapon.getClass().getSimpleName());
} else if (this.getClass().getSimpleName().equals("Submarine")) {
this.weapon = new TorpedoTube();
System.out.println("Submarine " + id + " equipped with " + weapon.getClass().getSimpleName());
}
}
Upvotes: 0
Views: 73
Reputation: 7900
@AndyTurner's answer can be illustrated by the following diagram:
Although this solution works, I disagree that it follows the Dependency Inversion principle, since the concrete classes are responsible for creating the Weapon
objects. Furthermore, I belive it violates the Open-Closed Principle. Imagine that your Weapon
is crashed during a battle. You couldn't just replace it for another.
I like to propose another solution, that is structurally similar, but functionally different:
interface WarVehicle {
boolean atack(WarVehicle other);
boolean defend(WarVehicle from);
void setWeapon(WarVehicle from);
Weapon getWeapon();
boolean acceptsWeapon();
}
abstract class AbstractWarVehicle {
private Weapon weapon;
public AbstractWarVehicle(Weapon weapon) {
setWeapon(weapon);
}
public final void setWeapon(Weapon weapon) {
if (!acceptsWeapon(weapon)) {
throw new IllegalArgumentException("Weapon of type "
+ weapon.getClass().getName()
+ " cannot be added to WarVehicle of type "
+ this.getClass().getName());
}
this.weapon = weapon;
}
public final Weapon getWeapon() {
return this.weapon;
}
public boolean attack(WarVehicle other) {
if (other != this) {
return !other.defend(this);
}
}
public boolean defend(WarVehicle from) {
return this.getWeapon().getDefensePower() >=
from.getWeapon().getFirePower();
}
}
class FighterJet extends AbstractWarVehicle {
public boolean acceptsWeapon(Weapon weapon) {
return weapon instanceof GuidedMissilesystem;
}
}
class AttackHelicopter extends AbstractWarVehicle {
public boolean acceptsWeapon(Weapon weapon) {
return weapon instanceof GrenadeLauncher;
}
}
// And so on...
Using it:
Weapon jet = new FighterJet(new GuidedMissleSystem()); // OK
Weapon jet2 = new FighterJet(new Cannon()); // throws!
Weapon
with a similar one by using setWeapon
.Weapon
s. A FighterJet
will accept anything that is an instance of GuidedMissileSystem
, which means if your game is expanded and you get a SuperUltraMegaBlasterGeorgeForemanMissileSystem
, you will still be able to use it if it inherits from GuidedMissileSystem
.acceptsWeapon
are static, so they can't be changed on runtime.Upvotes: 1
Reputation: 140328
Since this appears to be based on which subclass the instance is concretely, you could simply set a field in the constructor.
For instance:
class ParentClass {
final Weapon weapon;
ParentClass(Weapon weapon) {
this.weapon = weapon;
}
}
Then, in the Warship
class:
class Warship extends ParentClass {
Warship() {
super(new RocketLauncher());
}
}
(Visibility modifiers and other fields omitted for clarity)
Mind you, dependency injection isn't a GoF pattern, I don't think. It's just the cleanest one to use here.
Upvotes: 1