I\'m stuck in this situation where:
Ammo
, with AmmoBox
and Clip
as chil
The problem with which you are wrestling comes from the need to call a different implementation based on the run-time types of both the ammo and the weapon. Essentially, the action of reloading needs to be "virtual" with respect to two, not one, object. This problem is called double dispatch.
One way to address it would be creating a visitor-like construct:
abstract class Ammo {
public virtual void AddToShellWeapon(ShellWeapon weapon) {
throw new ApplicationException("Ammo cannot be added to shell weapon.");
}
public virtual void AddToClipWeapon(ClipWeapon weapon) {
throw new ApplicationException("Ammo cannot be added to clip weapon.");
}
}
class AmmoBox : Ammo {
public override void AddToShellWeapon(ShellWeapon weapon) {
...
}
public override void AddToClipWeapon(ClipWeapon weapon) {
...
}
}
class Clip : Ammo {
public override void AddToClipWeapon(ClipWeapon weapon) {
...
}
}
abstract class Weapon {
public abstract void Reload(Ammo ammo);
}
class ShellWeapon : Weapon {
public void Reload(Ammo ammo) {
ammo.AddToShellWeapon(this);
}
}
class ClipWeapon : Weapon {
public void Reload(Ammo ammo) {
ammo.AddToClipWeapon(this);
}
}
"The magic" happens in the implementations of Reload
of the weapon subclasses: rather than deciding what kind of ammo they get, they let the ammo itself do "the second leg" of double dispatch, and call whatever method is appropriate, because their AddTo...Weapon
methods know both their own type, and the type of the weapon into which they are being reloaded.