首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++ -鸭子模拟器中的策略模式

C++ -鸭子模拟器中的策略模式
EN

Code Review用户
提问于 2020-03-14 20:42:56
回答 1查看 591关注 0票数 5

我正在从头第一设计模式学习设计模式,为了获得自信,我计划在学习了相应的章节之后,在C++中实现每个模式。

至于“战略”模式,其结果是:

  • Duck.hpp
代码语言:javascript
复制
#ifndef DUCK_H
#define DUCK_H
#include <memory>
#include "FlyBehavior.hpp"
#include "QuackBehavior.hpp"
class Duck {
 private:
  std::unique_ptr<FlyBehavior> flyBehavior;
  std::unique_ptr<QuackBehavior> quackBehavior;
 public:
  Duck(std::unique_ptr<FlyBehavior>, std::unique_ptr<QuackBehavior>);
  void performFly();
  void performQuack();
  void setFlyBehavior(std::unique_ptr<FlyBehavior>);
  void setQuackBehavior(std::unique_ptr<QuackBehavior>);
  virtual void display() = 0;
};
#endif /* ifndef DUCK_H */
  • Duck.cpp
代码语言:javascript
复制
#include <algorithm>
#include <memory>
#include "Duck.hpp"
Duck::Duck(std::unique_ptr<FlyBehavior> fb,
           std::unique_ptr<QuackBehavior> qb)
  : flyBehavior(std::move(fb))
  , quackBehavior(std::move(qb))
{}
void Duck::performFly() {
  flyBehavior->fly();
};
void Duck::performQuack() {
  quackBehavior->quack();
};
void Duck::setFlyBehavior(std::unique_ptr<FlyBehavior> fb) {
  flyBehavior = std::move(fb);
};
void Duck::setQuackBehavior(std::unique_ptr<QuackBehavior> qb) {
  quackBehavior = std::move(qb);
};
  • RubberDuck.hpp
代码语言:javascript
复制
#ifndef RUBBERDUCK_H
#define RUBBERDUCK_H
#include "Duck.hpp"
class RubberDuck : public Duck {
 public:
  RubberDuck();
  void display() override;
};
#endif /* ifndef RUBBERDUCK_H */
  • RubberDuck.cpp
代码语言:javascript
复制
#include <iostream>
#include <memory>
#include "FlyNoWay.hpp"
#include "RubberDuck.hpp"
#include "Squeak.hpp"
RubberDuck::RubberDuck()
  : Duck(std::make_unique<FlyNoWay>(),
         std::make_unique<Squeak>()) {
};
void RubberDuck::display() {
  std::cout << "Hello, I am a rubber duck!\n";
};
  • SupersonicDuck.hpp
代码语言:javascript
复制
#ifndef SUPERSONICDUCK_H
#define SUPERSONICDUCK_H
#include "Duck.hpp"
class SupersonicDuck : public Duck {
 public:
  SupersonicDuck();
  void display() override;
};
#endif /* ifndef SUPERSONICDUCK_H */
  • SupersonicDuck.cpp
代码语言:javascript
复制
#include <iostream>
#include <memory>
#include "FlyRocketPowered.hpp"
#include "SupersonicDuck.hpp"
#include "SupersonicSqueak.hpp"

SupersonicDuck::SupersonicDuck()
  : Duck(std::make_unique<FlyRocketPowered>(),
         std::make_unique<SupersonicSqueak>()) {
}
void SupersonicDuck::display() {
  std::cout << "Hello, I am a supersonic duck!\n";
};
  • FlyBehavior.hpp
代码语言:javascript
复制
#ifndef FLYBEHAVIOR_H
#define FLYBEHAVIOR_H
class FlyBehavior {
 public:
  virtual void fly() = 0;
};
#endif /* ifndef FLYBEHAVIOR_H */
  • FlyNoWay.hpp
代码语言:javascript
复制
#ifndef NOFLY_H
#define NOFLY_H
#include "FlyBehavior.hpp"
class FlyNoWay : public FlyBehavior {
 public:
  void fly() override;
};
#endif /* ifndef NOFLY_H */
  • FlyNoWay.cpp
代码语言:javascript
复制
#include <iostream>
#include "FlyNoWay.hpp"
void FlyNoWay::fly() {
  std::cout << "I can't fly!\n";
};
  • FlyRocketPowered.hpp
代码语言:javascript
复制
#ifndef FLYROCKETPOWERED_H
#define FLYROCKETPOWERED_H
#include "FlyBehavior.hpp"
class FlyRocketPowered : public FlyBehavior {
  void fly() override;
};
#endif /* ifndef FLYROCKETPOWERED_H */
  • FlyRocketPowered.cpp
代码语言:javascript
复制
#include <iostream>
#include "FlyRocketPowered.hpp"
void FlyRocketPowered::fly() {
  std::cout << "WHOOOOOOMMMMMM\n";
};
  • QuackBehavior.hpp
代码语言:javascript
复制
#ifndef QUACKBEHAVIOR_H
#define QUACKBEHAVIOR_H
class QuackBehavior {
 public:
  virtual void quack() = 0;
};
#endif /* ifndef QUACKBEHAVIOR_H */
  • Squeak.hpp
代码语言:javascript
复制
#ifndef SQUEAK_H
#define SQUEAK_H
#include "QuackBehavior.hpp"
class Squeak : public QuackBehavior {
 public:
  void quack() override;
};
#endif /* ifndef SQUEAK_H */
  • Squeak.cpp
代码语言:javascript
复制
#include <iostream>
#include "Squeak.hpp"
void Squeak::quack() {
  std::cout << "Squeak!\n";
};
  • SupersonicSqueak.hpp
代码语言:javascript
复制
#ifndef SUPERSONICSQUEAK_H
#define SUPERSONICSQUEAK_H
#include "QuackBehavior.hpp"
class SupersonicSqueak : public QuackBehavior {
 public:
  void quack() override;
};
#endif /* ifndef SUPERSONICSQUEAK_H */
  • SupersonicSqueak.cpp
代码语言:javascript
复制
#include <iostream>
#include "SupersonicSqueak.hpp"
void SupersonicSqueak::quack() {
  std::cout << "SQUEEEEAAAAK!\n";
};
  • main.cpp
代码语言:javascript
复制
#include <memory>
#include "RubberDuck.hpp"
#include "SupersonicDuck.hpp"
#include "FlyRocketPowered.hpp"
#include "Squeak.hpp"
int main() {
  RubberDuck rd;
  rd.display();
  rd.performFly();
  rd.performQuack();

  SupersonicDuck sd;
  sd.display();
  sd.performFly();
  sd.performQuack();

  // enhance rd with rockets:
  rd.setFlyBehavior(std::make_unique<FlyRocketPowered>());
  rd.display();
  rd.performFly();
  rd.performQuack();
}

代码工作正常,因此我在这里发布了一个not on Stack溢出,但是我对以下选择有一些顾虑:

  • 我使用过make_unique/unique_ptr,但也可以使用make_shared/shared_ptr
  • 我一直试图在头文件和实现文件中分割一个翻译单元;
  • 我没有定义默认构造函数,而是定义了两个参数构造函数,因为如果没有这两种行为,就不应该存在鸭子;
  • 方法setFlyBehaviorsetQuackBehavior可以在运行时更改对象的行为,因此不能更改的唯一两件事是对象本身的类型,以及那些尚未从Duck类中分解出来的方法(如display)。
EN

回答 1

Code Review用户

回答已采纳

发布于 2020-03-15 04:27:29

密码看上去不错。让包含保护宏与文件名(_H vs .hpp)相一致可能是个好主意。

有一种实现策略模式的更简单的方法--存储std::functions而不是指向基类的智能指针:

代码语言:javascript
复制
struct Duck {
    using behavior_t = std::function<void()>;
    behavior_t fly;
    behavior_t quack;
    behavior_t display; // maybe const; but that disables moving
};

现在一切都要简单得多:

代码语言:javascript
复制
// for example
const auto plain_fly   = [] { std::cout << "(flies)\n"; };
const auto plain_quack = [] { std::cout << "(quacks)\n"; };

// can even determine operation dynamically
struct hello_display {
    std::string name;
    void operator()() const
    {
        std::cout << "Hello, I am a " << name << "!\n";
    }
};

int main()
{
    Duck plain_duck{plain_fly, plain_quack, hello_display{"plain duck"}};
    plain_duck.fly();
    plain_duck.quack();
    plain_duck.display();
}

(现场演示)

我使用过make_unique/unique_ptr,但也可以使用make_shared/shared_ptr

如果资源仅为一个智能指针所拥有,而不是由多个智能指针共享,则unique_ptr是一个合理的选择。

我一直试图在头文件和实现文件中分割一个翻译单元;

对于简单的操作,也可以在头文件中定义内联的方法。

我没有定义默认构造函数,而是定义了两个参数构造函数,因为如果没有这两种行为,就不应该存在鸭子;

考虑检查空指针。

方法setFlyBehaviorsetQuackBehavior可以在运行时更改对象的行为,因此不能更改的唯一两件事是对象本身的类型,以及那些尚未从Duck类中分解出来的方法(例如显示)。

这是好的,如果它符合您的程序的语义。注意,还可以通过不提供相应的修饰符方法来使用不可变属性的策略模式。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/238901

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档