【HeadFirst 设计模式】策略模式的C++实现

一、案例背景

J o e 上班的公司做了一套相当成功的模拟鸭子游戏:SimUDuck。游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。此系统的内部设计使用了标准的OO技术,设计了一个鸭子父类,并让各种鸭子继承此父类。
在这里插入图片描述

现在,需求发生了变化,需要添加会飞并且会叫的鸭子,怎么做合适?

二、案例分析

自然而然地,你可能会脱口而出:“这还不简单?找出父类,添加一个fly方法一个quack方法,解决!“。

嗯,看起来很完美,可以试一试。
在这里插入图片描述

不过很快你就发现了似乎不对劲:游戏里的“橡皮鸭”居然也会飞了!这太荒谬了!

你挠了挠头,马上又想起来补救之策:“可以把橡皮鸭中的fly方法给覆盖掉,让它什么也不做,这样它就不会飞了。”。

可是,如果以后我加入木头鸭呢?木头鸭既不会飞也不会叫,橡皮鸭不会飞,但会叫。

我们知道,并非所有的子类都具有飞行和呱呱叫的行为,所以继承并不是适当的解决方式。

刚开始出现继承这种机制的时候,很多程序员便很喜欢用这种方法解决问题。因为这很符合我们以往的认知习惯:某某人的儿子可以使用父亲手中的资源,这种使用似乎“理所应当”,很顺其自然的一件事。但是,写代码的时候你就会发现继承能做的事情,往往组合也能实现,并且有时候会比用继承更好。

直接继承如果不行的话,那如果把fly方法和quack方法定义成纯虚函数呢?这样一来,他们的子类就可以根据自身需要自己去实现fly方法和quack方法了。

软件开发中有个目标叫复用。如果你的代码里出现很多一模一样的函数,显然并不是一份很好的设计。软件的需求一直在变化,正如世界一样,我们的代码也需要与时俱进,否则就会死亡。一份程序在刚写好的时候仅仅是开始,后期花在维护,改进,更新上的时间要远远多于刚开始开发的时间,这些就是所谓的“change”,正是这些变化才造成了你不断的加班。对于软件开发来讲,唯一不变的是变化。

那么应该采取什么样的设计才能有效的抵御变化,少加班呢?

找出应用中可能需要变化之处,把他们独立出来,不要和稳定的代码混在一起。

换句话说,如果每次新的需求依赖,都会使某些方面的代码发生变化,那么你就可以确定,这部分的代码需要被抽离,和其他稳定的代码有所区分。也就是说把会变化的部分取出并封装起来,以便以后可以轻易地改动以扩充此部分而不影响其它部分。

这个概念很简单,几乎是每个设计模式背后的精神所在。所有的设计模式都提供了一套方法让“系统中的某部分改变不会影响其它部分”。

具体问题,具体分析。对于上述案例中每次变化的是一个有一个“行为”,比如飞行,比如呱呱叫,并且后期可能还会有其他的行为被添加进来,如何将它们隔离出来呢?

针对接口编程,而不是针对实现编程。
如何理解这句话?
还记得引言中的那个案例吗?这里的接口并不是指某个具体的函数,而是指抽象父类。子类通过override父类中的虚函数实现具体的行为,而利用父类指针又可以指向子类的实例,这使得我们可以在设计类的时候引入一个父类的指针,而在使用的时候可以插入具体的子类实例,从而实现更好的设计。

我们知道Duck类内的fly方法和quack方法会随着鸭子的不同而改变。为了要把这两个行为从Duck类中分开,我们将把它们从Duck类中取出来,建立一组新类来代表每个行为。

三、代码实现

这里给出相关案例的C++实现:

#include <iostream>
using namespace std;

//@brief: 飞行行为(抽象接口)
class FlyBehavior
{
public:
    virtual void fly() = 0;
};

//@brief: 飞行行为:翅膀飞行(具体实现)
class FlyWithWings : public FlyBehavior
{
public:
    void fly() override
    {
        cout << "Fly with Wings..." << endl;
    }
};

//@brief: 飞行行为:不能飞(具体实现)
class FlyNoway : public FlyBehavior
{
public:
    void fly()
    {
        cout << "i can not fly..." << endl;
    }
};

//@brief: 飞行行为:火箭飞行(具体实现)
class FlyWithRockets : public FlyBehavior
{
public:
    void fly()
    {
        cout << "Fly with Rockets..." << endl;
    }
};

//@brief: 鸣叫行为(抽象接口)
class QuackBehavior
{
public:
    virtual void quack() = 0;
};

//@brief: 鸣叫行为:呱呱叫(具体实现)
class Quack : public QuackBehavior
{
public:
    void quack() override
    {
        cout << "quack..." << endl;
    }
};

//@brief: 鸣叫行为:不会叫(具体实现)
class MuteQuack : public QuackBehavior
{
public:
    void quack() override
    {
        cout << "silence..." << endl;
    }
};

//@brief: 鸣叫行为:嘎嘎叫(具体实现)
class Squeak : public QuackBehavior
{
public:
    void quack() override
    {
        cout << "Squeak..." << endl;
    }
};

//@brief: 鸭子(抽象接口)
class Duck
{
    private:
    FlyBehavior* flyBehavior;
    QuackBehavior* quackBehavior;
public:
    Duck(FlyBehavior* fb, QuackBehavior* qb) : flyBehavior(fb), quackBehavior(qb) {}

    // 动态的设置各种行为,以防后期出现各种“变化”
    void setFlyBehavior(FlyBehavior* flyBehavior){
        this->flyBehavior = flyBehavior;
    }

    void setQuackBehavior(QuackBehavior* quackBehavior){
        this->quackBehavior = quackBehavior;
    }

    // 共有方法
    void swim()
    {
        cout << "Swimming..." << endl;
    }

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

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

//@brief: 绿头鸭(具体实现)
class MallardDuck : public Duck
{
public:
    MallardDuck(FlyWithWings* fw, Quack* q) : Duck(fw, q) {}
};

//@brief: 红头鸭(具体实现)
class RedheadDuck : public Duck
{
public:
    RedheadDuck(FlyWithWings* fw, Quack* q) : Duck(fw, q) {}
};

//@brief: 橡皮鸭(具体实现)
class RubberDuck : public Duck
{
public:
    RubberDuck(FlyNoway* fn, MuteQuack* q) : Duck(fn, q) {}
};

//测试方法
int main()
{
    // 创建并初始化鸭子
    Duck* mallard = new MallardDuck(new FlyWithWings(), new Quack());
    Duck* redhead = new RedheadDuck(new FlyWithWings(), new Quack());
    Duck* rubberDuck = new RubberDuck(new FlyNoway(), new MuteQuack());

    // 让��子表演
    mallard->quack();
    mallard->fly();
    mallard->swim();

    redhead->quack();
    redhead->fly();
    redhead->swim();

    rubberDuck->quack();
    rubberDuck->fly();
    rubberDuck->swim();

    // 释放资源
    delete mallard;
    delete redhead;
    delete rubberDuck;

    return 0;
}
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值