C++ 策略模式的具体案例与优缺点

    策略模式:准备一组算法,并将每一个算法封装起来,使得它们可以互换。

1、策略模式中的角色与职责

    在策略模式中分为4个角色:环境类Context、具体环境类SubContext、策略类Stategy、具体策略类SubStrategy。

  • Context(环境类):环境类是一个抽象类,它通过属性成员m_pStrategy调用具体策略类里的函数,以实现不同功能。
  • SubContext(具体环境类、子环境类):继承环境类Context,实现对某个对象或环境的描写。
  • Strategy(策略类):是一个接口,里面有抽象的方法,这些抽象方法,需要SubStrategy去实现。
  • SubStrategy(具体策略类、子策略类):实现抽象策略类里的算法,在运行时,覆盖Strategy父对象,实现对某个具体业务的处理。
        如下:
图(1) 策略模式的UML类图

    Context环境类,是一个抽象类,它不仅仅可以代表上下左右的事物或场景,而且也可以代表某种生物,比如鸭子,它里面有3个函数:Flyed()、Quacked()、Display(),分别表示飞行、鸣叫、显示。鸭子分为很多种,有野鸭、红头鸭、道具鸭、模型鸭、橡皮鸭等,前2种有生命,后3种无生命,因此,野鸭、红头鸭、道具鸭等鸭属于子环境SubContext,鸭有翅膀,可以在水上飞、岸边飞、草场飞,这种飞行方式属于一种策略,因此放到Strategy接口里,然后再由具体策略类SubStrategy实现飞的方式。

    鸭子的鸣叫,有的是呱呱叫、有的是吱吱叫、还有的是嘎嘎叫等等,所以鸣叫也是一种策略,需要用接口来封装,然后再用子策略去实现。
    具体如下:

图(2) 飞行与鸣叫的策略模式

2、代码实现

2.1 飞行策略

    //FlyBahavior.h

#pragma once
#include <iostream>
using namespace std;

//------------  1) 飞行行为的接口 -----------------------//
class FlyBehavior {
    
    
public:
	virtual void Flyed() const = 0;
	virtual ~FlyBehavior() = default;
};

class FlyNoWay : public FlyBehavior {
    
    
public:
	void Flyed() const override {
    
    
		cout << "I can't fly!" << endl;
	}
};

class FlyRocketPowered :public FlyBehavior {
    
    
public:
	void Flyed() const override {
    
    
		cout << "I'm flying with a rocket" << endl;
	}
};

class FlyWithWings :public FlyBehavior {
    
    
public:
	virtual void Flyed() const override {
    
    
		cout << "I'm flying" << endl;
	}
};

2.2 鸣叫策略

    //QuackBehavior.h

#pragma once
#include <iostream>
using namespace std;

//----------------- 2) 鸣叫行为的接口 -----------------//
class QuackBehavior {
    
    
public:
	virtual void Quacked() const = 0;
	virtual ~QuackBehavior() = default;
};

class Quack :public QuackBehavior {
    
    
public:
	void Quacked() const override {
    
    
		cout << "Quack" << endl;
	}
};

class MuteQuack :public QuackBehavior {
    
    
public:
	void Quacked() const override {
    
    
		cout << "Silence" << endl;
	}
};

class Squeak : public QuackBehavior {
    
    
public:
	void Quacked() const override {
    
    
		cout << "Squeak" << endl;
	}
};

2.3 鸭子类

    //Duck.h

#pragma once
#include <iostream>
#include <memory>
#include "FlyBehavior.h"
#include "QuackBehavior.h"

using namespace std;

//--------------- 3) 鸭子类 --------------------//
class Duck {
    
    
public:
	std::unique_ptr<FlyBehavior>   m_pFlyBehavior;
	std::unique_ptr<QuackBehavior> m_pQuackBehavior;

	Duck(std::unique_ptr<FlyBehavior> pFlyed, std::unique_ptr<QuackBehavior> pQuack)
		:m_pFlyBehavior(std::move(pFlyed)), m_pQuackBehavior(std::move(pQuack))
	{
    
    

	};

	virtual ~Duck() = default;
	virtual void Display() const = 0;

	void Quacked() const {
    
    
		m_pQuackBehavior->Quacked();
	}
	void Flyed() const {
    
    
		m_pFlyBehavior->Flyed();
	}
	void Swim() const {
    
    
		cout << "All ducks float,even decoys" << endl;
	}

};

//--------------- 3.2) 道具鸭 --------------------//
class DecoyDuck :public Duck {
    
    
public:
	DecoyDuck()
		:Duck(std::make_unique<FlyNoWay>(), std::make_unique<MuteQuack>())
	{
    
    

	}

	void Display() const override {
    
    
		cout << "Decoy Duck" << endl;
	}
};

//--------------- 3.3) 野鸭 --------------------//
class MallardDuck :public Duck {
    
    
public:
	MallardDuck()
		:Duck(std::make_unique<FlyWithWings>(), std::make_unique<Quack>())
	{
    
    

	}
	void Display() const override {
    
    
		cout << "Mallard Duck" << endl;
	}
};

//--------------- 3.4) 模型鸭 --------------------//
class ModelDuck :public Duck {
    
    
public:
	ModelDuck()
		: Duck(std::make_unique<FlyWithWings>(), std::make_unique<Quack>())
	{
    
    

	}
	void Display() const override {
    
    
		cout << "Model Duck" << endl;
	}
};

//--------------- 3.5) 红头鸭 --------------------//
class RedHeadDuck :public Duck {
    
    
public:
	RedHeadDuck()
		:Duck(std::make_unique<FlyWithWings>(), std::make_unique<Quack>())
	{
    
    

	}
	void Display() const override {
    
    
		cout << "Red Head Duck" << endl;
	}
};

//--------------- 3.6) 橡皮鸭 --------------------//
class RubberDuck :public Duck {
    
    
public:
	RubberDuck()
		: Duck(std::make_unique<FlyNoWay>(), std::make_unique<Squeak>())
	{
    
    

	}
	void Display() const override {
    
    
		cout << "Rubber Duck" << endl;
	}
};

2.4 主入口

    //main.cpp

#include "FlyBehavior.h"
#include "QuackBehavior.h"
#include "Duck.h"

int main()
{
    
    
	MallardDuck mallard;
	mallard.Display();
	mallard.Swim();
	mallard.Quacked();
	mallard.Flyed();
	cout << "--------------- Mallard -----\n" << endl;

	RubberDuck rubberDuckie;
	rubberDuckie.Display();
	rubberDuckie.Swim();
	rubberDuckie.Quacked();
	rubberDuckie.Flyed();

	system("pause");
	return 0;
}


    效果如下:

图(3)策略模式的运行结果

3、策略模式的优缺点

3.1 优点

  • 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  • 使用策略模式可以避免多重条件选择语句。多重条件选择语句不易维护,它把采取哪一种算法或行为的逻辑,与算法或行为本身的实现逻辑混合在一起,将它们全部硬编码(Hard Coding)在一个庞大的多重条件选择语句中,比直接继承环境类的办法还要原始和落后。
  • 策略模式提供了一种算法的复用机制。由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。

3.2 缺点

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适用于客户端知道所有的算法或行为的情况,客户端的权限太大。
  • 策略模式将造成系统产生很多具体策略类,任何细小的变化都将导致系统要增加一个新的具体策略类,会造成文件夹中class类个数的暴增。

猜你喜欢

转载自blog.csdn.net/sanqima/article/details/125830400