天天看点

【Head First】 策略模式

    策略模式定义:定义算法族,分别封装起来,让它们之间可以相互替换;此模式让算法的变化独立于使用算法的客户。

一 策略模式的引入

         //参考Head First设计模式 - 策略模式 - 章节:设计模式入门

       假设要设计一个鸭子游戏系统,游戏要提供不同种类的鸭子供玩家选择,假设鸭子具备游泳,叫,飞和外观几个方法。 

      首先,想到的是继承,如下图:

【Head First】 策略模式

        缺点:

        (1)可扩充性差、可复用性差、 后期维护困难 - 原因:代码大量重复 算法没有独立的封装;

            比如 实现了基类的fly(),记这个fly()为fly()1,fly()1在基类的派生类中被继承是可以的,但是若派生类需要其他的fly()方法呢?假设客户需要fly()2 fly()3 fly()4的算法,总不能给每个派生类都重新检查改写一遍吧..

        (2)灵活性差;

            比如 编译时,飞行、叫的方式在就决定了,不能在运行中决定。

二 策略模式的内容   

       三个设计原则:

  1. 封装可变 - 找出应用中需要变化之处,将其独立出来封装,使得变化部分与不变部分隔离;
  2. 接口编程 - 针对接口编程而不是针对实现编程,关键在于多态;
  3. 多组合少继承 - 多用组合可以增加系统的弹性;

        类图:

【Head First】 策略模式

解释:

Duck 抽象基类 - 抽象策略角色 

FlyBehavior 可变封装 - 具体策略角色

Quack 最终给客户端调用 - 环境角色

Duck类  FlyBehavior类 - 这是两个不同的类,前者封装应用中的不变部分;后者封装应用中的可变部分; - 这里体现了封装可变原则; 

 is-a即继承关系:

MallardDuck 是 Duck 的派生类 

FlyWithWings 是 FlyBehavior 的派生类 - 把FlyWithWings FlyNoWay看成算法,则体现了接口编程原则; - 而接口编程的关键 在于 多态;

has-a即组合关系:

Duck类中实例化了两个FlyBehavior类的变量 - has-a关系 - 这里体现了多组合少继承原则; 

三 策略模式 Duck C++实现

//Duck.h

#ifndef _DUCK_H_

#define _DUCK_H_

#include <iostream>

using namespace std;

class FlyBehavior{

public:

        virtual ~FlyBehavior(){};

        virtual void fly(){};

};

class FlyWithWings:public FlyBehavior{

public:

        virtual void fly() { cout << "I can fly with wings." << endl; }

};

class FlyNoWay :public FlyBehavior{

public:

        virtual void fly(){ cout << "I can not fly." << endl; }

};

class QuackBehavior{

public:

        virtual ~QuackBehavior(){};

        virtual void quack(){};

};

class Quack :public QuackBehavior{

public:

        virtual void quack(){ cout << "Quack. " << endl; }

};

class Squack :public QuackBehavior{

public:

        virtual void quack(){ cout << "Squack. " << endl; }

};

class MuteQuack :public QuackBehavior{

public:

        virtual void quack(){ cout << "No quack. " << endl; }

};

class Duck{

protected:

        FlyBehavior *flyBehavior;

        QuackBehavior *quackBehavior;

public:

        virtual ~Duck(){};

        void swim(){ cout << "All of us can swim. " << endl; }

        void performQuack(){ quackBehavior->quack(); }

        void performFly(){ flyBehavior->fly(); }

        virtual void display() = 0;

        void setFlyBehavior(FlyBehavior *fly){ flyBehavior = fly; }

        void setQuackBehavior(QuackBehavior *quack){ quackBehavior = quack; }

};

class MallardDuck :public Duck{

public:

        MallardDuck(FlyBehavior *fly, QuackBehavior *quack)

        {

               flyBehavior = fly;

               quackBehavior = quack;

        }

        virtual void display(){ cout << "I am a mallardDuck. " << endl; }

};

class RedheadDuck :public Duck{

public:

        RedheadDuck(FlyBehavior *fly, QuackBehavior *quack)

        {

               flyBehavior = fly;

               quackBehavior = quack;

        }

        void display(){ cout << "I am a duck of red head." << endl; }

};

class RubberDuck :public Duck{

public:

        RubberDuck(FlyBehavior *fly, QuackBehavior *quack)

        {

               flyBehavior = fly;

               quackBehavior = quack;

        }

        void display(){ cout << "I am a rubber duck." << endl; }

};

class DecoyDuck :public Duck{

public:

        DecoyDuck(FlyBehavior *fly, QuackBehavior *quack)

        {

               flyBehavior = fly;

               quackBehavior = quack;

        }

        void display(){ cout << "I am a decoy duck." << endl; }

};

#endif

//Duck_maincpp

#include "Duck.h"

int main()

{

        FlyBehavior *fly = new FlyNoWay();

        QuackBehavior *quack = new MuteQuack();

        //

        Duck *d = new MallardDuck(fly,quack);

        d->display();

        d->performFly();

        d->performQuack();

        delete fly;

        delete quack;

        cout << endl;

        fly = NULL;

        quack = NULL;

        fly = new FlyWithWings();

        d->setFlyBehavior(fly);

        d->performFly();

        delete d;

        d = NULL;

        system("pause");

        return 0;

}

【Head First】 策略模式

四 敲代码中遇到的问题:

(1) 无法解析的外部符号 "public: virtual __thiscall FlyBehavior::~FlyBehavior(void)

原因:析构函数只声明,未定义。 如: 

class FlyBehavior{

public:

        virtual ~FlyBehavior();

        virtual void fly();

};

 解决:+个 {}

class FlyBehavior{

public:

        virtual ~FlyBehavior(){};

        virtual void fly(){};

};

(2)存疑:

继续阅读