设计模式之策略模式

设计模式之策略模式策略模式:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

大家好,欢迎来到IT知识分享网。

策略(Strategy)模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

本章将以一下简单的商场收银系统来介绍策略模式,我们还是按照一步步改进程序的方法进行讲解。

设计模式之策略模式

先让我们来完成收银系统的1.0版

// main.cpp
#include <iostream>

using namespace std;

int main()
{
    double total(0.0);
    do
    {
      try  
      {
        double price(0.0);
    		int count(0);
        cout << "请输入商品单价:" << endl;
        cin >> price;
        cout << "请输入商品数量:" << endl;
        cin >> count;
        if (price > 0 && count > 0)
        {
          	double totalSomeGoods  = price * count;
            total += totalSomeGoods;
            cout << "单价:" << price << "元 数量:"
                 << count << " 合计:" << totalSomeGoods << "元" << endl;
            cout << "总计:" << total << "元" << endl;
        }
      }
      catch (const exception &e)
      {
        cerr << e.what() << '\n';
      }
    } while (price > 0 && count > 0);

    return 0;
}

程序运行效果示例

设计模式之策略模式

商场会经常做些打折的活动,那收银系统就需要增加打折的功能。商场收银系统V1.1

// main.cpp
#include <iostream>

using namespace std;

int main()
{
    double total(0.0);
    do
    {
      	try
        {
          double price(0.0);
    			int count(0), mode(0);
          cout << "请输入商品单价:" << endl;
          cin >> price;
          cout << "请输入商品数量:" << endl;
          cin >> count;
          cout << "请选择以下数字,确认商品的销售模式:" << endl;
          cout << "1.原价 2.八折 3.七折" << endl;
          cin >> mode;
          if (price > 0 && count > 0)
          {
            	double totalSomeGoods(0.0);
              switch (mode)
              {
              case 1:
                  totalSomeGoods = price * count;
                  break;
              case 2:
                  totalSomeGoods = price * count * 0.8;
              case 3:
                  totalSomeGoods = price * count * 0.7;
                  break;
              default:
                  cout << "选择的销售模式无效。" << endl;
                  continue;
              }

              total += totalSomeGoods;
              cout << "单价:" << price << "元 数量:"
                   << count << " 合计:" << totalSomeGoods << "元" << endl;
              cout << "总计:" << total << "元" << endl;
          }
      }
      catch (const exception &e)
      {
        cerr << e.what() << '\n';
      }
    } while (price > 0 && count > 0);

    return 0;
}

程序运行效果示例

设计模式之策略模式

现在程序算是写出来了,但是重复代码很多,3个分支要执行的语句除了打折多少以外几乎没什么不同,而且程序扩展性不好。如果商场要做更多活动,例如满300返100,满200返50等,就要不停地加分支,这种情况下我们可以引入简单工厂模式。

// cash.h
#ifndef CASH_H
#define CASH_h

#include <cmath>

class Cash
{
public:
    virtual double payCash(double price, int count) = 0;
};

class CashNormal : public Cash
{
public:
    double payCash(double price, int count)
    {
        return price * count;
    }
};

class CashDiscount : public Cash
{
public:
    CashDiscount(double discount)
    : discount(discount)
    {}

    double payCash(double price, int count)
    {
        return price * count * discount;
    }

private:
    double discount;
};

class CashRebate : public Cash
{
public:
    CashRebate(double condition, double rebate)
        : condition(condition)
        , rebate(rebate)
    {}

    double payCash(double price, int count)
    {
        if (condition > 0)
        {
            int total = price * count;
            if (total > 0)
            {
                total -= floor(total / condition) * rebate;

                return total;
            }
        }
    }

private:
    double condition;
    double rebate;
};

#endif
// cashfactory.h
#ifndef CASHFACTORY_H
#define CASHFACTORY_H

#include "cash.h"

#include <stdexcept>

class CashFactory
{
public:
    static Cash *createCashMode(int mode)
    {
        Cash *cash = nullptr;
        switch (mode)
        {
        case 1:
            cash = new CashNormal();
            break;
        case 2:
            cash = new CashDiscount(0.8);
            break;
        case 3:
            cash = new CashDiscount(0.7);
            break;
        case 4:
            cash = new CashRebate(300, 100); // 满300返100
            break;
        default:
            throw std::invalid_argument("选择的模式无效");
            break;
        }

        return cash;
    }
};

#endif
// main.cpp
#include "cashfactory.h"

#include <iostream>

using namespace std;

int main()
{
    double total(0.0);
    string exit;
    do
    {
        try
        {
            cout << "请输入商品单价:" << endl;
          	doube price(0);
            cin >> price;
            cout << "请输入商品数量:" << endl;
          	int count(0);
            cin >> count;
            if (price <= 0 || count <= 0)
            {
                cout << "商品单价或者商品数量不能小于或等于零" << endl;
                continue;
            }

            cout << "请选择以下数字,确认商品的销售模式:" << endl;
            cout << "1.原价 2.八折 3.七折 4.满300返100" << endl;
            cin >> mode;
            Cash *cash = CashFactory::createCashMode(mode);
            double totalSomeGoods = cash->payCash(price, count);
            delete cash;
            cash = nullptr;
            total += totalSomeGoods;
            cout << "单价:" << price << "元 数量:"
                 << count << " 合计:" << totalSomeGoods << "元" << endl;
            cout << "总计:" << total << "元" << endl;
            cout << "是否退出系统?(y/n)" << endl;
            cin >> exit;
        }
        catch (const exception &e)
        {
            cerr << e.what() << '\n';
        }
    } while (exit.compare("y") != 0);

    return 0;
}

简单工厂模式虽然也能解决这个问题,但这个模式只是解决对象的创建问题,而且由于工厂本身包括所有的收费方式,商场是可能经常性地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需重新编译部署,这真的是很糟糕的处理方式,所以用它不是最好的办法。面对算法的时常变动,我们可以引入策略模式。

商场收银系统V1.2。

创建策略类CashContext类

// cashcontext.h
#ifndef CASHCONTEXT_H
#define CASHCONTEXT_H

#include "cash.h"

#include <stdexcept>

class CashContext
{
public:
    CashContext(int mode)
    : mode(mode)
    {}

    double getResult(double price, int count)
    {
        Cash *cash(nullptr);
        double result(0.0);
        switch (mode)
        {
        case 1:
            cash = new CashNormal();
            result = cash->payCash(price, count);
            break;
        case 2:
            cash = new CashDiscount(0.8);
            result = cash->payCash(price, count);
            break;
        case 3:
            cash = new CashDiscount(0.7);
            result = cash->payCash(price, count);
            break;
        case 4:
            cash = new CashRebate(300, 100);
            result = cash->payCash(price, count);
            break;
        default:
            throw std::invalid_argument("选择的模式无效");
            break;
        }

        if (cash != nullptr)
        {
            delete cash;
            cash = nullptr;
        }

        return result;
    }

private:
    int mode;
};

#endif

修改main.cpp

// main.cpp
#include "cashcontext.h"

#include <iostream>

using namespace std;

int main()
{
    double total(0.0);
    string exit;
    do
    {
        try
        {
            cout << "请输入商品单价:" << endl;
          	double price(0);
            cin >> price;
            cout << "请输入商品数量:" << endl;
          	int count(0);
            cin >> count;
            if (price <= 0 || count <= 0)
            {
                cout << "商品单价或者商品数量不能小于或等于零" << endl;
                continue;
            }

            cout << "请选择以下数字,确认商品的销售模式:" << endl;
            cout << "1.原价 2.八折 3.七折 4.满300返100" << endl;
          	int mode(0);
            cin >> mode;
            CashContext *cashContext = new CashContext(mode);
            double totalSomeGoods = cashContext->getResult(price, count);
            delete cashContext;
            cashContext = nullptr;
            total += totalSomeGoods;
            cout << "单价:" << price << "元 数量:"
                 << count << " 合计:" << totalSomeGoods << "元" << endl;
            cout << "总计:" << total << "元" << endl;
            cout << "是否退出系统?(y/n)" << endl;
            cin >> exit;
        }
        catch (const exception &e)
        {
            cerr << e.what() << '\n';
        }
    } while (exit.compare("y") != 0);

    return 0;
}

最后,我们可以和之前使用简单工厂模式的main.cpp代码进行对比,使用简单工厂模式时我们要使用两个类:Cash和CashFactory,而使用策略模式只需要使用一个类CashContext类就可以了,这样耦合度进一步降低。

我们还可以使用简单工厂和策略模式相结合的方法进一步优化程序,这里只需要修改CashContext.h

#ifndef CASHCONTEXT_H
#define CASHCONTEXT_H

#include "cashfactory.h"

class CashContext
{
public:
    CashContext(int mode)
    : mode(mode)
    {}

    double getResult(double price, int count)
    {
        Cash *cash = CashFactory::createCashMode(mode);
        double result = cash->payCash(price, count);

        if (cash != nullptr)
        {
            delete cash;
            cash = nullptr;
        }

        return result;
    }

private:
    int mode;
};

#endif

设计模式之策略模式

程序运行效果示例

设计模式之策略模式

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/55027.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信