美文网首页
1.策略模式

1.策略模式

作者: 你今天作业做了吗 | 来源:发表于2019-03-24 18:16 被阅读0次

模拟鸭子应用

需求

  • 游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。

一开始,是通过使用继承的方式,用派生类实现各种鸭子。

class Duck {
public:
    void quack();
    void swim();
    void display();
};

class MallardDuck : Duck {
public:
    void display() {
        // 外观是绿头
    }
};

class RedheadDuck {
    void display() {
        // 外观是红头
    }
};

以上缺点:

  • 代码在多个子类中重复;
  • 运行时的行为不容易改变;
  • 我们不能让鸭子跳舞;
  • 很难知道所有鸭子的全部行为;
  • 鸭子不能同是又飞又叫;
  • 改变会牵一发动全身,造成其他鸭子不想要的改变。

由于需求总在变化,现在我们需要让鸭子能飞起来。不同的鸭子,叫声、显示、飞行方式都可能不太一样。

面对这种情况,我们需要的是将不变的部分放在基类中,而将经常变化的部分分离出来,作为独立的部分进行封装。为此,我们做了以下工作:

  • 利用抽象类(接口)代表每个行为,比如说FlyBehavior和QuackBehavior,而行为的每个实现都将实现其中的一个抽象类。
  • 鸭子的子类将使用抽象类(FlyBehavior与QuackBehavior)所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中。
  • 此次使用的是组合方式,而不是继承的方式进行实现。

于是代码变成了如下:


// 定义飞行行为抽象类(接口),
// 将鸭子类中经常变化的部分进行分离与封装。
class FlyBehavior {
public:
    virtual void fly() = 0;
    
    // 该类为基类,是需要被继承的。
    // 因此,析构函数需要被写成虚函数形式,
    // 这样子资源才得以正确释放。
    virtual ~FlyBehavior() {};
};

// 使用飞行行为抽象类(接口),
// 实现用翅膀飞行的具体类,
// 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
class FlyWithWings : public FlyBehavior {
public:
    virtual void fly() {
        cout << "Fly with wings." << endl;
    }
};

// 使用飞行行为抽象类(接口),
// 实现没有飞行的具体类,
// 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
class FlyNoWay : public FlyBehavior {
public:
    virtual void fly() {
        cout << "FlyNoWay: 啥时都不干。" << endl;
    }
};

// 定义鸭叫行为抽象类(接口),
// 将鸭子类中经常变化的部分进行分离与封装。
class QuackBehavior {
public:
    virtual void quack() = 0;
    
    // 该类为基类,是需要被继承的。
    // 因此,析构函数需要被写成虚函数形式,
    // 这样子资源才得以正确释放。
    virtual ~QuackBehavior() {};
};

// 使用鸭叫行为抽象类(接口),
// 实现鸭的呱呱叫具体类,
// 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
class Quack : public QuackBehavior {
public:
    virtual void quack() {
        cout << "Quack quack..." << endl;
    }
};

// 使用鸭叫行为抽象类(接口),
// 实现鸭的唧唧叫具体类,
// 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
class Squeak : public QuackBehavior {
public:
    virtual void quack() {
        cout << "Squeak squeak..." << endl;
    }
};

// 使用鸭叫行为抽象类(接口),
// 实现鸭的哑叫(不叫)具体类,
// 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
class MuteQuack : public QuackBehavior {
public:
    virtual void quack() {
        cout << "mute quack..." << endl;
    }
};


// 鸭子作为具体基类,为后面各种鸭子的派生类做基础。
// 鸭子之所以作为基类而不是抽象类(接口),
// 是因为鸭子本身有具体的部分。
// 将鸭子的叫、飞行等方式通过组合的形式,而不是继承的方式实现,
// 可以获得在运行中动态改变,也实现了代码的最大化复用。
// 也不会出现引起继承所造成的牵一发动全身的缺点。
// 将不变的部分封装在基类即可。
class Duck {
public:
    Duck() {
        quackBehavior = nullptr;
        flyBehavior = nullptr;
    }

    // 该类为基类,是需要被继承的。
    // 因此,析构函数需要被写成虚函数形式,
    // 这样子资源才得以正确释放。
    virtual ~Duck() {};

    // 将鸭叫行为委托给行为类实现,
    // 实现类中经常变化的部分分离,得以封装。
    // 也实现了将变化的代码最大化的复用与灵活性。
    void performQuack() {
        quackBehavior->quack();
    };

    // 将飞行行为委托给行为类实现,
    // 实现类中经常变化的部分分离,得以封装。
    // 也实现了将变化的代码最大化的复用与灵活性。
    void performFly() {
        flyBehavior->fly();
    };

    virtual void display() {
        cout << "Duck display" << endl;
    }

    // 获得该类的鸭叫行为类
    const QuackBehavior const* getQuackBehavior() {
        return quackBehavior;
    }

    // 获得该类的飞行行为类
    const FlyBehavior const* getFlyBehavior() {
        return flyBehavior;
    }

    // 设置该类的鸭叫行为类
    void setQuackBehavior(QuackBehavior* quack) {
        delete quackBehavior;
        quackBehavior = quack;
    }

    // 设置该类的飞行行为类
    void setFlyBehavior(FlyBehavior* fly) {
        delete flyBehavior;
        flyBehavior = fly;
    }

// 类成员使用保护方式,将实现派生类可以访问该类成员,
// 实现该类在具体运行过程中可以动态改变行为。
protected:
    QuackBehavior* quackBehavior;
    FlyBehavior* flyBehavior;
};

class MallardDuck : public Duck {
public:
    // 初始化派生类的行为类
    MallardDuck() {
        quackBehavior = new Quack;
        flyBehavior = new FlyWithWings;
    }

    // 释放派生类所拥有的资源
    virtual ~MallardDuck() {
        delete quackBehavior;
        delete flyBehavior;
    }

    // 实现派生类的显示
    virtual void display() {
        cout << "MallardDuck display..." << endl;
    }
};

class RedHeadDuck : public Duck {
public:
    // 初始化派生类的行为类
    RedHeadDuck() {
        quackBehavior = new Squeak;
        flyBehavior = new FlyNoWay;
    }

    // 释放派生类所拥有的资源
    virtual ~RedHeadDuck() {
        delete quackBehavior;
        delete flyBehavior;
    }

    // 实现派生类的显示
    virtual void display() {
        cout << "RedHeadDuck display..." << endl;
    }
};

相关文章

  • 11.7设计模式-策略模式-详解

    设计模式-策略模式 策略模式详解 策略模式在android中的实际运用 1.策略模式详解 2.策略模式在andro...

  • 设计模式[13]-策略模式-Strategy Pattern

    1.策略模式简介 策略模式(Strategy Patter)是行为型(Behavioral)设计模式,策略模式封装...

  • 1. 策略模式

    设计原则 找出应用中可能需要变化之处,把它们独立出来。不要和那些不需要变化的代码混在一起 针对接口编程,而不是针对...

  • 1.策略模式

    模拟鸭子应用 需求 游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。 一开始,是通过使用继承的方式,用派生类实现各...

  • 1. 策略模式

    什么是策略模式? 定义算法族,分别封装起来,让他们可以互相替换,从而让算法的变化独立于实用算法的客户。 举个例子:...

  • iOS 设计模式-策略模式

    1.策略模式简介   策略模式(Strategy Pattern),是行为型模式之一(设计模式分类:https:/...

  • if-else代码优化方案①策略模式 ②Map+Function

    if-else?解决方案①策略模式 ②Map+Function函数式接口 1.策略模式解决if-else 策略模式...

  • java 策略模式

    策略模式1.策略模式简介策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具...

  • 策略模式

    本文参考自: 《JAVA设计模式》之策略模式(Strategy) 1. 作用 策略模式属于对象的行为模式。其用意是...

  • 策略模式

    1.策略模式概念 策略模式(Strategy Pattern),实现一个类的行为或其算法可以在运行时更改。策略模式...

网友评论

      本文标题:1.策略模式

      本文链接:https://www.haomeiwen.com/subject/euauvqtx.html