策略模式
一、问题的提出
公司现有一个鸭子基类,其他类继承此类:
现在需要让鸭子能飞,则由继承很容易想到了在基类Duck中添加一个fly()方法,让所有继承此类的子类都有fly的功能:
但问题1:并非所有鸭子都能飞,在基类中添加新行为,使得某些不合适该行为的子类也具有该行为(比如:会飞的橡皮鸭)。对代码所做的局部修改,影响层面不只是局部。
当然,可以通过复写fly()方法来解决问题1, 让它什么都不做,但是如果继续有新的需求又要进行重写,代码无法复用且不好管理。
二、设计模式的解决方案
设计原则:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需变化的代码混在一起。
1、分开变化和不会变化的部分
由于Duck类中的quack()和fly()会随着鸭子的不同,行为不同,因此是变化的部分,将它们从Duck中独立出来,建立一组新类来代表每个行为。
2、设计鸭子行为
针对接口编程,而不是针对实现编程。
利用接口代表每个行为,如:FlyBehavior和QuackBehavior两个接口,而行为的每个实现都将实现其中的一个接口。
3、实现鸭子行为
这样的设计,可以让飞行和叫的动作被其他对象复用,因为这些行为被独立出来,与Duck类无关了,具有了复用的好处,却没有继承带来的包袱。
4、整合鸭子的行为
经过以上的设计,整合后的类图:
5、C++代码实现
头文件:
#ifndef DUCK__H
#define DUCK__H
//飞行行为抽象类
class FlyBehavior
{
public:
virtual void fly() = 0;
};
//能飞行具体类
class FlyWithWings : public FlyBehavior
{
public:
void fly();
};
//不能飞行具体类
class FlyNoWay : public FlyBehavior
{
public:
void fly();
};
//叫声行为抽象类
class QuackBehavior
{
public:
virtual void quack() = 0;
};
//叫声具体类“Quack”
class Quack : public QuackBehavior
{
public:
void quack();
};
//叫声具体类“Quiet”
class MuteQuack : public QuackBehavior
{
public:
void quack();
};
//叫声具体类“Squeak”
class Squeak : public QuackBehavior
{
public:
void quack();
};
//基类
class Duck
{
public:
virtual void performFly();
virtual void performQuack();
//基类的指针,用于动态绑定确定动作的行为
FlyBehavior* flyBehavior;
QuackBehavior* quackBehavior;
};
class MallardDuck : public Duck
{
public:
MallardDuck();
~MallardDuck();
void display();
};
#endif
cpp文件:
#include "Duck.h"
#include<iostream>
void FlyWithWings::fly()
{
std::cout<<"I'm flying"<<std::endl;
}
void FlyNoWay::fly()
{
std::cout<<"I can't fly"<<std::endl;
}
void Quack::quack()
{
std::cout<<"Quack"<<std::endl;
}
void MuteQuack::quack()
{
std::cout<<"Silence"<<std::endl;
}
void Squeak::quack()
{
std::cout<<"Squeak"<<std::endl;
}
void Duck::performFly()
{
flyBehavior->fly();
}
void Duck::performQuack()
{
quackBehavior->quack();
}
//初始化,用能飞行的具体类和“Quack”叫声的具体类初始化指针,
MallardDuck::MallardDuck()
{
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
}
//析构
MallardDuck::~MallardDuck()
{
if(NULL != flyBehavior)
delete flyBehavior;
if(NULL != quackBehavior)
delete quackBehavior;
}
策略模式:定义了算法簇,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
三、总结
1.对C++的动态绑定理解清楚,这是多态的前提(基类的指针或引用指向子类对象)
2.多用类来进行提取可变操作,尽量让可变的代码分离出来。
3.个人感觉类似乎有点多。。
4.希望能和有缘人多多交流,虽然只是很基础,但是本人领悟不够好,这个学习方式貌似比较适合偶。。。望有缘人看到多多交流。