策略模式

策略模式定义了一系列算法和行为(也就是策略),他们可以在运行时相互替换。通常把这些算法封装为一个个独立的类,形成一个“算法族”,这一族算法有相同的接口。

这里的算法和行为的含义都是指某件事的做法,也就是策略 Strategy 的含义,而不局限于计算机科学中的具体算法。本文中会混用算法、行为和策略。含义是一样的。

例如新的税法颁布,计算个人所得税的新旧两种算法算一个算法族;试想如果将计算个人所得税的方法硬编码在用户类中,当新的税法颁布的时候,就要重写用户类的相关代码, 而如果使用策略模式,只需要遵循接口实现一个新的所的税算法类就行了,用户类只要确保成员变量设置为新的类的对象就行了。系统从而更有弹性和可维护性

应用案例

这个例子来源于 《Head First 设计模式》:某公司有个鸭子仿真器这样一套系统,可以模拟各种鸭子。原先有 Mollard Duck(绿头鸭),是一种野鸭,可以飞,可以呱呱叫; 现在新加入一种模型鸭 (ModelDuck),因为是模型,不能飞也不能叫; 面向对象的思想,很自然的我们将鸭子Duck 作为基类,MollardDuck 和 ModelDuck 继承Duck类,然后分别实现或者重写 fly() 和 quack() 方法。考虑到鸭子子类越来越多,大白鸭,小黄鸭,火箭鸭,丑小鸭... 这些鸭子的fly() 方法和quack()方法各异,每实现一个子类就要写一遍这些方法,而这些方法有些鸭种是相同的,如果反复重写这些方法就无法复用代码了; 而且对于丑小鸭来说,小的时候不会飞长大了是会飞的,丑小鸭变身——白天鹅。

如何提高复用性和弹性呢?答案是策略模式。将 flyBehavior 和 quackBehavior作为类的成员,将 flyBehavior和quackBehavior也封装为基类,使用多态达到多种行为(策略、算法)的封装和复用。

实现的关键

将算法、策略封装为类,语言特性即为多态技术。

Talk is cheap,let's See The Code

让我们直接看代码吧。https://github.com/sunchaothu/DesignPatternsCpp_Practice.git

1.定义鸭子基类

Duck.h

#ifndef STRATEGY_PATTERN_DUCK_H
#define STRATEGY_PATTERN_DUCK_H #include "QuackBehavior.h"
#include "FlyBehavior.h"
#include <memory>
class Duck {
public:
virtual ~Duck();
void performFly();
void performQuack();
virtual void display()=0;
void swim();
void setFlyBehavior(FlyBehavior* flyBehavior);
void setquackBehavior(QuackBehavior* quackBehavior) ; protected:
std::shared_ptr<FlyBehavior> flyBehavior_ptr;
std::shared_ptr<QuackBehavior> quackBehavior_ptr; }; #endif //STRATEGY_PATTERN_DUCK_H

注意到,这里用flyBehavior 和 quackBehavior 作为鸭子类的成员,实际上是提供了接口,后面我们会注意到,C++的抽象类指针可以

作为接口。这里用C++11 标准库的智能指针share_ptr管理内存,可以免去delete烦恼。

和鸭子基类类的实现 Duck.cpp

#include <iostream>
#include "Duck.h"
Duck::~Duck() { }
void Duck::swim() {
std::cout<<"As a duck, swim is a default skill!"<<std::endl;
}
void Duck::performFly() {
flyBehavior_ptr->fly();
} void Duck::performQuack() {
quackBehavior_ptr->quack();
}
void Duck::setFlyBehavior(FlyBehavior* flyBehavior) {
flyBehavior_ptr.reset(flyBehavior);
} void Duck::setquackBehavior(QuackBehavior* quackBehavior) {
quackBehavior_ptr.reset(quackBehavior);
}

2.几种鸭子派生类

MallardDuck.h

#ifndef STRATEGY_PATTERN_MALLARDDUCK_H
#define STRATEGY_PATTERN_MALLARDDUCK_H #include "Duck.h" class MallardDuck:public Duck{
public:
MallardDuck();
~MallardDuck();
void display();
};
#endif //STRATEGY_PATTERN_MALLARDDUCK_H

MallardDuck.cpp

#include "MallardDuck.h"
#include "FlyBehavior.h"
#include "QuackBehavior.h"
#include <iostream>
#include <memory>
MallardDuck::MallardDuck() {
FlyWithWings *f_ptr = new FlyWithWings();
QuackNormal *q_ptr = new QuackNormal();
setquackBehavior(q_ptr);
setFlyBehavior(f_ptr);
} MallardDuck::~MallardDuck(){ } void MallardDuck::display() {
std::cout<<"I am a MallardDuck."<<std::endl;
}

ModelDuck.h

#ifndef STRATEGY_PATTERN_MODELDUCK_H
#define STRATEGY_PATTERN_MODELDUCK_H #include "Duck.h"
class ModelDuck:public Duck{
public:
ModelDuck();
~ModelDuck();
void display();
}; #endif //STRATEGY_PATTERN_MODELDUCK_H

MoedlDuck.cpp

#include "ModelDuck.h"
#include "QuackBehavior.h"
#include "FlyBehavior.h"
#include <iostream>
#include <memory>
ModelDuck::ModelDuck() { FlyNoWay *f_ptr = new FlyNoWay();
QuackNoWay *q_ptr = new QuackNoWay();
setquackBehavior(q_ptr);
setFlyBehavior(f_ptr);
} ModelDuck::~ModelDuck() {} void ModelDuck::display() {
std::cout<<"I am a model. "<<std::endl;
}

3.策略类

FlyBehavior.h

#ifndef STRATEGY_PATTERN_FLYBEHAVIOR_H
#define STRATEGY_PATTERN_FLYBEHAVIOR_H
class FlyBehavior {
public:
virtual void fly()=0;
};
class FlyNoWay:public FlyBehavior{
public:
virtual void fly();
};
class FlyWithWings:public FlyBehavior{
public:
virtual void fly();
};
#endif //STRATEGY_PATTERN_FLYBEHAVIOR_H

FlyBehavior.cpp

#include "FlyBehavior.h"
#include <iostream> void FlyWithWings::fly() {
std::cout<<"I'm flying with wings"<<std::endl;
} void FlyNoWay::fly(){
std::cout<<"I can't fly"<<std::endl;
}

QuackBehavior.h

#ifndef STRATEGY_PATTERN_QUACKBEHAVIOR_H
#define STRATEGY_PATTERN_QUACKBEHAVIOR_H
class QuackBehavior{
public:
virtual void quack()=0;
}; class QuackNoWay:public QuackBehavior {
public:
virtual void quack();
}; class QuackNormal:public QuackBehavior {
public:
virtual void quack();
};
#endif //STRATEGY_PATTERN_QUACKBEHAVIOR_H

QuackBehavior.cpp

#include "QuackBehavior.h"
#include <iostream> void QuackNoWay::quack() {
std::cout<<"<<Silence>>"<<std::endl;
} void QuackNormal::quack(){
std::cout<<"quack!" <<std::endl;
}

4.测试文件

main.cpp

#include <iostream>
#include "Duck.h"
#include "ModelDuck.h"
#include "MallardDuck.h"
int main() {
Duck* duck;
duck = new MallardDuck();
duck->display();
duck->performQuack();
duck->performFly();
delete duck;
duck = new ModelDuck();
duck->display();
duck->performQuack();
duck->performFly();
delete duck;
return 0;
}

5.构建文件 CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(Strategy_Pattern) set(CMAKE_CXX_STANDARD 11) add_library(Duck Duck.cpp MallardDuck.cpp ModelDuck.cpp)
add_library(Behavior FlyBehavior.cpp QuackBehavior.cpp)
target_link_libraries(Duck Behavior) add_executable(Strategy_Pattern main.cpp)
target_link_libraries(Strategy_Pattern Duck)

6.运行结果

I am a MallardDuck.
quack!
I'm flying with wings
I am a model.
<<Silence>>
I can't fly

设计思想

  1. 用组合代替继承,注意到 组合的含义是 Has-A 而继承的含义是 Is-A。使用组合的话,将算法类作为用户类的成员,所以在运行时可以通过更改成员进行算法的替换。
  2. 面向接口编程,而非面向实现编程。按照我的理解,为了系统的弹性和可维护性,将程序中容易变化的部分和不变的部分分离出来,接口Interface 定义了一种规范和约束,C++ 抽象基类(接口类)负责定义一组统一的不变的方法,子类必须实现这些方法,但是对于实现的细节没有约束。用鸭子的叫声这个行为为例子,定义了 QuackBehavior基类作为接口,要求子类必须实现void quack() 方法; 子类的实现可以是 呱呱叫, 咕咕叫,甚至是汪汪叫,也可以沉默(不叫)。

源码地址:https://github.com/sunchaothu/DesignPatternsCpp_Practice.git

参考

[1] Head First Design Patterns

设计模式C++实现(1)——策略(Strategy)模式的更多相关文章

  1. 设计模式C++描述----15.策略(Strategy)模式

    一. 举例说明 以前做了一个程序,程序的功能是评价几种加密算法时间,程序的使用操作不怎么变,变的是选用各种算法. 结构如下: Algorithm:抽象类,提供算法的公共接口. RSA_Algorith ...

  2. 《Head First 设计模式》ch.1 策略(Strategy)模式

    策略模式 定义了算法族,分别封装起来,让它们可以互相替换,让算法的变化独立于使用算法的客户. 模式名词的意义 威力强大,交流的不止是模式名称,而是一整套模式背后所象征的质量.特性.约束 用更少的词汇做 ...

  3. 策略(strategy)模式

    Head First一书中对于策略(strategy)模式的正式定义是:策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户. 为了介绍这个算法,书中讲了 ...

  4. Java 实现策略(Strategy)模式

    策略模式:行为型模式 将同一行为,不同的处理算法分别封装起来.让它们之间能够互相替换 1. 定义一个超类型接口,及 行为方法 2. 定义不同的实现类,实现该行为的 不同的算法 /** * 策略模式:针 ...

  5. 《图解设计模式》读书笔记4-2 STRATEGY模式

    目录 示例程序 角色 想法 Strategy模式即策略模式,在编程中,策略指的就是算法.利用此模式可以整体替换算法,即使用不同方式解决同一个问题.比如设计一个围棋程序,通过切换算法可以方便地切换AI的 ...

  6. C++设计模式实现--策略(Strategy)模式

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/L_Andy/article/details/30489331 一. 举例说明 曾经做了一个程序,程序 ...

  7. Head First 设计模式 - 01. 策略 (Strategy) 模式

    当涉及到"维护"时,为了"复用"目的而使用继承,结局并不完美 P4 对父类代码进行修改时,影响层面可能会很大 思考题 利用继承来提供 Duck 的行为,这会导致 ...

  8. Java设计模式透析之 —— 策略(Strategy)

    今天你的leader兴致冲冲地找到你,希望你能够帮他一个小忙.他如今急着要去开会.要帮什么忙呢?你非常好奇. 他对你说.当前你们项目的数据库中有一张用户信息表.里面存放了非常用户的数据.如今须要完毕一 ...

  9. Java设计模式(18)策略模式(Strategy模式)

    Strategy是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类. Stratrgy应用比较广泛,比如,公司经营业务变化图,可能有两种实现方式,一个是线条曲线, ...

随机推荐

  1. PAT——1056. 组合数的和

    给定N个非0的个位数字,用其中任意2个数字都可以组合成1个2位的数字.要求所有可能组合出来的2位数字的和.例如给定2.5.8,则可以组合出:25.28.52.58.82.85,它们的和为330. 输入 ...

  2. stateless 无状态组件

    使用:

  3. 数据存储之归档解档 NSKeyedArchiver NSKeyedUnarchiver

    在构建应用程序时,有一个重要的问题是如何在每次启动之间持久化数据,以便重现最后一次关闭应用前的状态.在iOS和OS X上,苹果提供了三种选择:Core Data.属性列表(Property List) ...

  4. c#网络传输

    接着前面简单讲的,给大家聊聊服务开发. 网络传输 先说网络传输开发,总体来说,可以看成4中模型 我们把传输过程看做网线,那么在通过传输的过程中.2边就涉及池化问题,也就是我们常见的异步传输. 在业务端 ...

  5. 关于osi的7层与tcp的4层网络协议的理解

    osi 七层模型 应用层 提供接口 表示层 机器语言的二进制转换 对话层 决定是否传输 传输层 确定可不可靠 排差错 控流 网络层 提供逻辑地址 选路 数据链路层 mac 错误检测 物理层 设备间的比 ...

  6. 在mac上使用tar.gz安装mysql

    官方: download: https://dev.mysql.com/downloads/mysql/ mysql参考文档:https://dev.mysql.com/doc/ 环境: macOS ...

  7. js如何获取键盘高度

    在移动端或混合app开发中,js如何获取键盘高度,直接贴上代码吧 input是一个html input 标签 var timer = { id:null, run:function (callback ...

  8. linux用户及文件管理

    帮助命令 whatis 命令  #显示命令的简短功能 man    命令  #查看手册页和命令描述 命令--help    #适用于外部命令 help    命令  #适用于内部命令 type 命令  ...

  9. AC自动机(简单版)(施工ing)

    声明 想看加强版的戳这里(施工ing,作者正努力中)~ 先贴题目吧哎~   AC自动机加强版  洛谷 P3796 题目: 洛谷 P3808 (数据范围困了我好久 TAT) 反正涉及字符串的算法都很玄学 ...

  10. Oracle入门第三天(下)——子查询

    一.子查询 1.子查询语法 SELECT select_list FROM table WHERE expr operator (SELECT select_list FROM table) 示例: ...