c++ - 两个其他方面相同的功能(一个使用模板模式,另一个不使用)

标签 c++ templates design-patterns

#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();
}

除了为每个代码创建辅助函数之外,如何最好地避免重复代码 A、代码 B、代码 C、代码 D 等中包含的代码?有更通用的方法吗?除了一个使用模板模式而另一个不使用之外,我有一些相同的功能。虚函数之间的代码体是相同的。如果我为每个相同的部分定义一个辅助函数,它会变得非常困惑,而且它们也会太多。

如果您想了解更多,这里是我的生产代码片段,说明了这一点。 SpellCaster源自 LivingBeing , 和 LivingBeing::cannotAttackLongRange(int)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()计算所有普通武器无法攻击的敌人,同时 LivingBeing::unattackableTargetsIncludingBySpells()计算所有普通武器和法术无法攻击的敌人。 SpellCaster用普通武器攻击时会想调用第一个,用法术攻击时会想调用第二个。

最佳答案

使用模板和 CRTP,如果合适的话,你可以这样做:

template <typename T, typename D>
void helper(const D& base)
 {
    // Code A
    if (base.T::foo() < 6) {
        // Code B
    }
    doSomething (base.T::goo());
    // Code C
    if (base.T::hoo() > 10) {
        // Code D
    }
}

struct Base {
    virtual ~Base() = default;
    virtual int foo() const {return 5;}
    virtual int goo() const {return 6;}
    virtual int hoo() const {return 7;}

    void noTemplatePattern() const
    {
        // use Base::foo, Base::goo and Base::hoo
        helper<Base>(*this);
    }
#if 0
    virtual void templatePattern() const = 0;
#endif
};

template <typename Derived>
struct BaseImpl : Base {
    template <typename Derived>
    void BaseImpl<Derived>::templatePattern() const {
        // use Derived::foo, Derived::goo and Derived::hoo
        helper<Derived>(static_cast<const Derived&>(*this));
    }
};

Live example

关于c++ - 两个其他方面相同的功能(一个使用模板模式,另一个不使用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27593518/

相关文章:

c++ - 程序在 CIN 输入处崩溃 | C++

c++ - 我如何将 std::function 类 1 绑定(bind)到类 2 的函数?

c++ - 如何在不违反类型别名规则的情况下解释消息负载?

java - 设计模式: Callback as a method parameter

java - 访客与组合

c++ - C++重载函数,包括bool和整数参数

c++ - 返回值会被临时销毁吗?

c++ - 混合模板与 std::enable_if_t 和特化

c++ - "No matching function"模板函数接受回调

c# - 带有双重检查锁的单例设计模式