策略模式的核心
定义算法簇,分别封装,让他们之间可以相互替换。最终使得算法可以独立于使用算法的客户。(从书上抄来的,看不懂不要 紧,继续往下看,看完全文再返回来你就理解了)
使用策略模式的原因
假设我们要写一个游戏,游戏里面有很多种类的鸭子,学过OO设计的我们一定会设计一个抽象鸭子类Duck,然后写一系列的具体的鸭子类型来继承Duck,像这样:
这里所有的鸭子都会游泳,所有的鸭子都会quack叫,但是由于不同的鸭子外形不同,所以在超类中我们定义display为虚函数,在子类中重载他。
可是当我们有一个这样的新的需求的时候:我们现在需要在游戏中加入一种橡皮鸭,橡皮鸭不会quack叫而是捏起来squeak这样叫的,或者我们要加入一个木头鸭子,他既不会叫也不会游泳(因为他会沉下去而橡皮鸭不会)。
这时候我们要怎么办呐,你可能会想到一个办法:在橡皮鸭和木头鸭子中重载quack方法,让这个方法为空 do nothing,但是要是我们又需要加入一大堆的玩具鸭子呐?他们有的会叫有的不会叫。
分开会变化的部分和不会变化的部分
这里我们用到一个设计原则:我们要找出应用中可能需要改变之处,把他们独立出来,不要和那些不需要变化的代码混淆在一起。
基于这个原则我们要把鸭子的各种行为独立出来变成一个类,这样我们就可以独立的更新和修改这些行为
针对变化的部分
我们要用到第二个设计原则:针对接口编程,而不是针对实现编程
为了进一步封装使得鸭子的实现不需要考虑方法的细节,我们要把鸭子的行为分开放到不同的类中,然后让具体的鸭子来使用这些不同的类
上图(鸭子叫的方法):
我们通过这种方法重新封装了鸭子的三种不同的叫法:呱呱,吱吱和不会叫。
抽象出了鸭子的各种行为以后如何组合成一个完整的鸭子呐?
组合而不是继承
1. 首先我们在Duck类中加入“两个实例变量指针”,分别是“flyBehavior”和“quackBehavior”,每个具体的鸭子会动态的设置这两个实例变量指针,然后我们用两个方法“performFly”和“performQuack”来条用前面的两个实例变量指针中的具体的quack函数和fly函数。
如图:
2. 然后我们实现perfrom:
Duck::performQuack() {
quack_behavior->quack();
}
3. 这样我们在具体的鸭子子类的构造函数中组装鸭子实现:
class MallardDuck : public Duck {
public:
MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
void display() {
cout << "I'm a real Mallard Duck" << endl;
}
}
这样Mallard鸭子叫行为的指针就指向了一个可以quack叫的子类。
模式整体实现
Duck.h & Duck.cpp
// Duck.h created by Zillior
#ifndef DESIGN_DUCK_H
#define DESIGN_DUCK_H
#include "FlyBehavior.h"
#include "QuackBehavoir.h"
class Duck {
protected:
QuackBehavoir* quack_behavior;
FlyBehavior* fly_behavior;
public:
void display();
void performQuack();
void performFly();
void set_fly_behavior(FlyBehavior*);
void set_quack_behavior(QuackBehavoir*);
};
class MallardDuck : public Duck {
public:
MallardDuck();
~MallardDuck();
};
class RedheadDuck : public Duck {
public:
RedheadDuck();
~RedheadDuck();
};
class RubberDuck : public Duck {
public:
RubberDuck();
~RubberDuck();
};
class DecoyDuck : public Duck {
public:
DecoyDuck();
~DecoyDuck();
};
#endif //DESIGN_DUCK_H
// Duck.cpp created by Zillior
#include "Duck.h"
void Duck::display() {
performFly();
performQuack();
}
void Duck::performQuack() {
quack_behavior->quack();
}
void Duck::performFly() {
fly_behavior->fly();
}
void Duck::set_fly_behavior(FlyBehavior* new_fly_behavior) {
if (fly_behavior != nullptr) delete fly_behavior;
fly_behavior = new_fly_behavior;
}
void Duck::set_quack_behavior(QuackBehavoir* new_quack_behavior) {
if (quack_behavior != nullptr) delete quack_behavior;
quack_behavior = new_quack_behavior;
}
MallardDuck::MallardDuck() {
this->quack_behavior = new Quack;
this->fly_behavior = new FlyWithWings;
}
RedheadDuck::RedheadDuck() {
this->quack_behavior = new Quack;
this->fly_behavior = new FlyWithWings;
}
RubberDuck::RubberDuck() {
this->quack_behavior = new Squeak;
this->fly_behavior = new FlyNoWay;
}
DecoyDuck::DecoyDuck() {
this->quack_behavior = new MuteQuack;
this->fly_behavior = new FlyNoWay;
}
鸭子飞行行为的实现
// FlyBehavior.h Created by zillior on 18-8-20.
#ifndef DESIGN_FLYBEHAVIOR_H
#define DESIGN_FLYBEHAVIOR_H
class FlyBehavior {
private:
public:
virtual void fly() = 0;
};
class FlyWithWings : public FlyBehavior {
private:
public:
virtual void fly() override;
};
class FlyNoWay : public FlyBehavior {
private:
public:
virtual void fly() override;
};
#endif //DESIGN_FLYBEHAVIOR_H
// FlyBehavior.cpp Created by zillior on 18-8-20.
//
#include <iostream>
#include "FlyBehavior.h"
void FlyWithWings::fly() {
std::cout << "fly with wings" << std::endl;
}
void FlyNoWay::fly() {
std::cout << "can't fly" << std::endl;
}
鸭子叫的行为的实现
// QuackBehavoir.h Created by zillior on 18-8-20.
//
#ifndef DESIGN_QUACKBEHAVOIR_H
#define DESIGN_QUACKBEHAVOIR_H
class QuackBehavoir {
private:
public:
virtual void quack() = 0;
};
class Quack : public QuackBehavoir {
private:
public:
void quack() override;
};
class Squeak : public QuackBehavoir {
private:
public:
void quack() override;
};
class MuteQuack : public QuackBehavoir {
private:
public:
void quack() override;
};
#endif //DESIGN_QUACKBEHAVOIR_H
// QuackBehavoir.cpp Created by zillior on 18-8-20.
//
#include <iostream>
#include "QuackBehavoir.h"
void Quack::quack() {
std::cout << "quack" << std::endl;
}
void Squeak::quack() {
std::cout << "squeak" << std::endl;
}
void MuteQuack::quack() {
// do nothing
}