#include <iostream>
void doSomething (int x) {std::cout << "Do something with " << x << std::endl;}
struct Base {
virtual int foo() const {return 5;}
virtual int goo() const {return 6;}
virtual int hoo() const {return 7;}
void noTemplatePattern() const {
// Code A
if (Base::foo() < 6) {
// Code B
}
doSomething (Base::goo());
// Code C
if (Base::hoo() > 10) {
// Code D
}
}
void templatePattern() const {
// Code A
if (foo() < 6) {
// Code B
}
doSomething (goo());
// Code C
if (hoo() > 10) {
// Code D
}
}
};
struct Derived : Base {
virtual int foo() const override {return 12;}
virtual int goo() const override {return 13;}
virtual int hoo() const override {return 14;}
};
int main() {
Derived d;
d.noTemplatePattern();
d.templatePattern();
}
How best to avoid repeating the codes contained in Code A, Code B, Code C, Code D, etc... other than creating helper functions for each? Is there a more generic way? I have functions that are identical except one uses the Template Pattern, and the other doesn't. The body of code between the virtual functions are identical. If I define a helper function for each identical part, it gets really messy, and there will be too many of them too.
In case you want more clarification, here is a snippet of my production code illustrating this. SpellCaster is derived from LivingBeing, and LivingBeing::cannotAttackLongRange(int) is overridden by SpellCaster::cannotAttackLongRange(int).
inline std::set<LivingBeingProxy*> LivingBeing::unattackableTargets() const {
std::set<LivingBeingProxy*> nonTargets;
if (isCharmed()) {
for (auto it = std::next(getStatesList(CHARM_SPELL).begin(), 1); it != getStatesList(CHARM_SPELL).end(); ++it)
nonTargets.emplace (std::dynamic_pointer_cast<CharmedStateBase>(*it)->getCharmer());
}
for (LivingBeingProxy* x : getLocation()->allBeingsAlive()) {
if ( (x->heightAboveGround() > damageInflictor(0)->getReach()) && !canFly()
&& LivingBeing::cannotAttackLongRange(distanceBetween(this, x->getActual()))) //*** virtual method here!
{nonTargets.emplace(x); continue;}
if ( (x->heightAboveGround()) < 0 && (x->getTerrain() == InWater) && !canSwim() )
{nonTargets.emplace(x); continue;}
}
// ...
return nonTargets;
}
inline std::set<LivingBeingProxy*> LivingBeing::unattackableTargetsIncludingBySpells() const {
std::set<LivingBeingProxy*> nonTargets;
if (isCharmed()) {
for (auto it = std::next(getStatesList(CHARM_SPELL).begin(), 1); it != getStatesList(CHARM_SPELL).end(); ++it)
nonTargets.emplace (std::dynamic_pointer_cast<CharmedStateBase>(*it)->getCharmer());
}
for (LivingBeingProxy* x : getLocation()->allBeingsAlive()) {
if ( (x->heightAboveGround() > damageInflictor(0)->getReach()) && !canFly()
&& cannotAttackLongRange (distanceBetween(this, x->getActual()))) //*** virtual method here!
{nonTargets.emplace(x); continue;}
if ( (x->heightAboveGround()) < 0 && (x->getTerrain() == InWater) && !canSwim() )
{nonTargets.emplace(x); continue;}
}
// ...
return nonTargets;
}
LivingBeing::unattackableTargets() computes all enemies that are not attackable by ordinary weapons, while LivingBeing::unattackableTargetsIncludingBySpells() computes all enemies that are not attackable by ordinary weapons and spells. A SpellCaster will want to call the first when attacking with an ordinary weapon, and will want to call the second when attacking with a spell.
Aucun commentaire:
Enregistrer un commentaire