我正在从头第一设计模式学习设计模式,为了获得自信,我计划在学习了相应的章节之后,在C++中实现每个模式。
至于“战略”模式,其结果是:
Duck.hpp:#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:#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:#ifndef RUBBERDUCK_H
#define RUBBERDUCK_H
#include "Duck.hpp"
class RubberDuck : public Duck {
public:
RubberDuck();
void display() override;
};
#endif /* ifndef RUBBERDUCK_H */RubberDuck.cpp:#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:#ifndef SUPERSONICDUCK_H
#define SUPERSONICDUCK_H
#include "Duck.hpp"
class SupersonicDuck : public Duck {
public:
SupersonicDuck();
void display() override;
};
#endif /* ifndef SUPERSONICDUCK_H */SupersonicDuck.cpp:#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:#ifndef FLYBEHAVIOR_H
#define FLYBEHAVIOR_H
class FlyBehavior {
public:
virtual void fly() = 0;
};
#endif /* ifndef FLYBEHAVIOR_H */FlyNoWay.hpp:#ifndef NOFLY_H
#define NOFLY_H
#include "FlyBehavior.hpp"
class FlyNoWay : public FlyBehavior {
public:
void fly() override;
};
#endif /* ifndef NOFLY_H */FlyNoWay.cpp:#include <iostream>
#include "FlyNoWay.hpp"
void FlyNoWay::fly() {
std::cout << "I can't fly!\n";
};FlyRocketPowered.hpp:#ifndef FLYROCKETPOWERED_H
#define FLYROCKETPOWERED_H
#include "FlyBehavior.hpp"
class FlyRocketPowered : public FlyBehavior {
void fly() override;
};
#endif /* ifndef FLYROCKETPOWERED_H */FlyRocketPowered.cpp:#include <iostream>
#include "FlyRocketPowered.hpp"
void FlyRocketPowered::fly() {
std::cout << "WHOOOOOOMMMMMM\n";
};QuackBehavior.hpp#ifndef QUACKBEHAVIOR_H
#define QUACKBEHAVIOR_H
class QuackBehavior {
public:
virtual void quack() = 0;
};
#endif /* ifndef QUACKBEHAVIOR_H */Squeak.hpp#ifndef SQUEAK_H
#define SQUEAK_H
#include "QuackBehavior.hpp"
class Squeak : public QuackBehavior {
public:
void quack() override;
};
#endif /* ifndef SQUEAK_H */Squeak.cpp#include <iostream>
#include "Squeak.hpp"
void Squeak::quack() {
std::cout << "Squeak!\n";
};SupersonicSqueak.hpp#ifndef SUPERSONICSQUEAK_H
#define SUPERSONICSQUEAK_H
#include "QuackBehavior.hpp"
class SupersonicSqueak : public QuackBehavior {
public:
void quack() override;
};
#endif /* ifndef SUPERSONICSQUEAK_H */SupersonicSqueak.cpp#include <iostream>
#include "SupersonicSqueak.hpp"
void SupersonicSqueak::quack() {
std::cout << "SQUEEEEAAAAK!\n";
};main.cpp#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;setFlyBehavior和setQuackBehavior可以在运行时更改对象的行为,因此不能更改的唯一两件事是对象本身的类型,以及那些尚未从Duck类中分解出来的方法(如display)。发布于 2020-03-15 04:27:29
密码看上去不错。让包含保护宏与文件名(_H vs .hpp)相一致可能是个好主意。
有一种实现策略模式的更简单的方法--存储std::functions而不是指向基类的智能指针:
struct Duck {
using behavior_t = std::function<void()>;
behavior_t fly;
behavior_t quack;
behavior_t display; // maybe const; but that disables moving
};现在一切都要简单得多:
// 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是一个合理的选择。
我一直试图在头文件和实现文件中分割一个翻译单元;
对于简单的操作,也可以在头文件中定义内联的方法。
我没有定义默认构造函数,而是定义了两个参数构造函数,因为如果没有这两种行为,就不应该存在鸭子;
考虑检查空指针。
方法
setFlyBehavior和setQuackBehavior可以在运行时更改对象的行为,因此不能更改的唯一两件事是对象本身的类型,以及那些尚未从Duck类中分解出来的方法(例如显示)。
这是好的,如果它符合您的程序的语义。注意,还可以通过不提供相应的修饰符方法来使用不可变属性的策略模式。
https://codereview.stackexchange.com/questions/238901
复制相似问题