草庐IT

c++ - 带状态的 C+11 策略模式

coder 2024-02-03 原文

Strategy Pattern 的例子从书中,Head First Design Patterns , 是用 C++ 编写的 [here] .我正在练习根据 Effective GoF Patterns with C++11 and Boost 将其转换为 C++11 样式如下所示。

嘎嘎行为:

struct Quack {
    static void quack()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct MuteQuack {
    static void quack()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

飞行行为:

struct FlyWithWings {
public:
    static void fly()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

struct FlyNoWay {
public:
    static void fly()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

Duck 层次结构:

class Duck
{
public:
    typedef std::function<void(void)> QUACK;
    typedef std::function<void(void)> FLY;

public:
    Duck(const QUACK &q, const FLY &f)
        : m_Quack(q), m_Fly(f) {}

    virtual ~Duck()
    {
    }

    void perform_quack()
    {
        m_Quack();
    }
    void perform_fly()
    {
        m_Fly();
    }

protected:
    QUACK   m_Quack;
    FLY     m_Fly;

private:
    Duck(const Duck&) = delete;
    Duck& operator=(const Duck&) = delete;
};

class MallardDuck
    : public Duck
{
public:
    MallardDuck()
        : Duck(&Quack::quack, &FlyWithWings::fly)
    {
    }
};

class PaintedDuck
    : public Duck
{
public:
    PaintedDuck()
        : Duck(&MuteQuack::quack, &FlyNoWay::fly)
    {
    }
};

到目前为止一切顺利,客户端运行良好。

int main()
{
    MallardDuck x1;
    x1.perform_quack();
    x1.perform_fly();

    PaintedDuck x2;
    x2.perform_quack();
    x2.perform_fly();

    return 0;
}

现在我想扩展一个新类 RubberDuckDuck 层次结构,并且 RubberDuck 使用新的飞行行为 FlyWithRocket 具有对象状态。如下:

新的飞行行为:

class FlyWithRocket {
public:
    FlyWithRocket() : m_Energy(3) {}
    void fly()
    {
        if(m_Energy > 0)
        {
            fly_with_rocket();
            --m_Energy;
        }
        else
        {
            fly_out_of_energy();
        }
    }

private:
    void fly_with_rocket()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
    void fly_out_of_energy()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    unsigned int m_Energy;
};

一个新的 Duck 类型:

class RubberDuck
    : public Duck
{
public:
    RubberDuck()
        : Duck(&MuteQuack::quack, std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket)))
        , m_flyrocket()
    {
    }
private:
    FlyWithRocket m_flyrocket;
};

从现在开始我想知道成员初始化顺序的规则。基础 Duck 在成员 m_flyrocket 之前初始化,但请注意基础 Duck 是使用绑定(bind) m_flyrocket 初始化的还没有初始化。 结果,当我在 VS2013 中运行它时,它在运行时没有任何错误。

但是代码真的不安全吗?如果没有,我该如何修改才能获得更好的设计?

最佳答案

它不安全,但除非您调用 m_Fly(),否则不太可能损坏来自基类构造函数。

不过,您可以通过以下任一方式轻松避免这种情况:

  1. 为基类构造函数提供一个虚拟的或默认构造的 std::function ,并重新分配 m_Fly到派生类构造函数中的绑定(bind)仿函数

    RubberDuck()
        : Duck(&MuteQuack::quack, std::function<void()>())
    {
        m_Fly = std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket));
    }
    
  2. 制作 FlyWithRocket一个仿函数本身(只需将 void fly 重命名为 void operator() )并按值传递它而不是保留私有(private)成员(它将由 m_Fly 函数对象拥有,如果需要,您可以通过 std::function::target<FlyWithRocket>() 访问它)

    class FlyWithRocket {
    public:
        FlyWithRocket() : m_Energy(3) {}
        void operator() () {
    // ...
    
    RubberDuck()
        : Duck(&MuteQuack::quack, FlyWithRocket()) {}
    

关于c++ - 带状态的 C+11 策略模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23360892/

有关c++ - 带状态的 C+11 策略模式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. ruby - 安装libv8(3.11.8.13)出错,Bundler无法继续 - 2

    运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

  10. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

随机推荐