Say, the player clicks the mouse -> The Event Handler conveys to the gun that it needs to be fired -> The gun can agree, creating a child projectile and telling the scene manager what to do with it ... or it can throw a variety of exceptions (say.. OutOfAmmo, Damaged, SafetyLatchOn, etc), the outer loop then catches the exception as a base class object and decides what to do with it, looking up in a predefined dictionary of functions, which have almost nothing to do with the gun itself.
O_o
Doing this with many if-else checks will be messy, I think.
o_O
You can't avoid those checks.
You've deliberately created a situation where examining an exception is the requirement in order to give reasonable feedback.
These situations that you've deemed worthy of an exception are going to be common events by virtue of their totally normal occurrence.
In a big shooter, do you always check if you have ammo before pulling the trigger?
What this means is, you'll have to transform this common event into an exception. That transformation requires checks. Example:
Code:
class IGun;
// ...
void IGun::Fire()
{
// ...
if(!mAmmo)
{
throw(OutOfAmmo());
}
// ...
if(!mRepair)
{
throw(Damaged());
}
// ...
if(!mSafety)
{
throw(SafetyLatchOn());
}
// ...
}
That only tells us half the story. Checks are needed higher in the engine. Example:
Code:
class IEngine;
// ...
void IEngine::handleEvent
(
int fEvendID
)
{
// ...
// handle other events
// ...
if(fEvendID == mWeaponFire)
{
try
{
getPlayerGun()->Fire();
}
catch(const OutOfAmmo &)
{
// code to trigger "dry fire" sound
}
catch(const Damaged &)
{
// code to trigger "force discard weapon"
}
catch(const SafetyLatchOn &)
{
// code to trigger "bolt catch" sound
}
}
// ...
// handle other events
// ...
}
All attempts that would simplify the code will also work as implemented with callbacks, returning objects, and simple conditional codes. Example:
Code:
// if this code works conceptually
// ...
if(fEvendID == mWeaponFire)
{
try
{
getPlayerGun()->Fire();
}
catch(const IGunException &)
{
GunExceptionTable[IGunException()->mID](*this, getPlayerGun());
}
}
// ...
// so does this
// ...
if(fEvendID == mWeaponFire)
{
if(int sID = getPlayerGun()->Fire())
{
GunExceptionTable[sID](*this, getPlayerGun());
)
}
// ...
// and this
// ...
if(fEvendID == mWeaponFire)
{
getPlayerGun()->Fire(*this); // uses table directly
}
// ...
In other words, here the use of the exception mechanism has bought you exactly nothing.
Soma