zoukankan      html  css  js  c++  java
  • 设计模式C++实现(1)——策略(Strategy)模式

    策略模式

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

    这里的算法和行为的含义都是指某件事的做法,也就是策略 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

    著作权声明:本文系作者原创,欢迎转载分享,转载请标明来源。
  • 相关阅读:
    Java多线程、并发
    Java I/O系统
    Java注解
    Arthas(Java诊断工具)
    Java泛型
    Java内部类
    libpcap使用
    python文件服务器
    设计模式
    protobuf
  • 原文地址:https://www.cnblogs.com/sunchaothu/p/9860062.html
Copyright © 2011-2022 走看看