[大话设计模式C++版] 第2章 商场促销 —— 策略模式

阅读: 评论:0

[大话设计模式C++版] 第2章 商场促销 —— 策略模式

[大话设计模式C++版] 第2章 商场促销 —— 策略模式

源码可以在这里找到 大话设计模式C++版

大鸟给小菜布置了一个作业,做一个商场收银软件

需求1 收银系统

营业员根据客户所购买商品的单价和数量,向客户收费。

UI设计

代码设计

//Widget.cpp
#pragma execution_character_set("utf-8")
#include "Widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->priceEdit->setValidator(new QDoubleValidator(0, 10000, 10, this));  //限制只能输入浮点数ui->numEdit->setValidator(new QIntValidator(0, 100, this));  //限制只能输入整数
}void Widget::on_okBtn_clicked()
{QString txtPrice = ui->priceEdit->text();QString txtNum = ui->numEdit->text();double totalPrice = Double() * Double();m_total += totalPrice;ui->listWidget->addItem(QString("单价:%1    数量:%2    合计:%3").arg(txtPrice).arg(txtNum).arg(totalPrice));ui->totalPriceLabel->setText(QString::number(m_total));
}void Widget::on_resetBtn_clicked()
{ui->priceEdit->clear();ui->numEdit->clear();ui->listWidget->clear();ui->totalPriceLabel->setText("0.00");m_total = 0;
}Widget::~Widget()
{delete ui;
}

需求2 增加打折

增加打折优惠功能

UI设计

代码设计

//Widget.cpp
#pragma execution_character_set("utf-8")
#include "Widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->priceEdit->setValidator(new QDoubleValidator(0, 10000, 10, this));ui->numEdit->setValidator(new QIntValidator(0, 100, this));QStringList sl;sl << "正常收费" << "打八折" << "打七折" << "打五折";ui->calcCombox->addItems(sl);
}void Widget::on_okBtn_clicked()
{QString txtPrice = ui->priceEdit->text();QString txtNum = ui->numEdit->text();double totalPrice = 0;int calcType = ui->calcCombox->currentIndex();switch (calcType) {case 0:totalPrice = Double() * Double();break;case 1:totalPrice = Double() * Double() * 0.8;break;case 2:totalPrice = Double() * Double() * 0.7;break;case 3:totalPrice = Double() * Double() * 0.5;break;default:break;}m_total += totalPrice;QString calcText = ui->calcCombox->currentText();ui->listWidget->addItem(QString("单价:%1  数量:%2  %3  合计:%4").arg(txtPrice).arg(txtNum).arg(calcText).arg(totalPrice));ui->totalPriceLabel->setText(QString::number(m_total));
}void Widget::on_resetBtn_clicked()
{ui->priceEdit->clear();ui->numEdit->clear();ui->listWidget->clear();ui->totalPriceLabel->setText("0.00");m_total = 0;
}Widget::~Widget()
{delete ui;
}

问题1switch case 里打折的部分除了折扣率不同,其他基本都是重复代码

问题2:如果要增加满减的计算方式,是否要在 on_okBtn_clicked函数 里增加更多的 case条件

优化方案:利用简单工厂模式把计算方法抽离出来,且打折的话需要接收折扣率,满减的话需要接收满多少,减多少

需求3 增加满减

增加满300减100功能

代码设计

//CashSuper.h
class CashSuper
{
public:virtual double acceptCash(double money) = 0;virtual ~CashSuper() {};
};
//CashNormal.h
#include "CashSuper.h"class CashNormal : public CashSuper
{
public:virtual double acceptCash(double money) override {return money;}virtual ~CashNormal() {}
};
//CashRebate.h
#include "CashSuper.h"
#include <QString>class CashRebate : public CashSuper
{
private:double m_moneyRebate = 1.0;
public:CashRebate(QString moneyRebate) {m_moneyRebate = Double();}virtual double acceptCash(double money) override {return money * m_moneyRebate;}virtual ~CashRebate() {}
};
//CashReturn.h
#include "CashSuper.h"
#include <QString>class CashReturn : public CashSuper
{
private:double m_moneyCondition = 0.0;double m_moneyReturn = 0.0;
public:CashReturn(QString moneyCondition, QString moneyReturn) {m_moneyCondition = Double();m_moneyReturn = Double();}virtual double acceptCash(double money) override {double result = money;if (money >= m_moneyCondition) {result = money - int(money/m_moneyCondition) * m_moneyReturn;}return result;}virtual ~CashReturn() {}
};
//CashFactory.h
#include "CashSuper.h"
#include "CashNormal.h"
#include "CashRebate.h"
#include "CashReturn.h"class CashFactory
{
public:static CashSuper* createCashAccept(int type) {CashSuper* ret = nullptr;switch (type) {case 0:ret = new CashNormal();break;case 1:ret = new CashRebate("0.8");break;case 2:ret = new CashReturn("300", "100");break;default:break;}return ret;}
};
//Widget.cpp
#pragma execution_character_set("utf-8")
#include "Widget.h"
#include "ui_widget.h"
#include "CashFactory.h"
#include "CashSuper.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);initUIControl();
}void Widget::on_okBtn_clicked()
{QString txtPrice = ui->priceEdit->text();QString txtNum = ui->numEdit->text();double totalPrice = 0;CashSuper* cash = CashFactory::createCashAccept(ui->calcCombox->currentIndex());totalPrice = cash->Double()*Double());delete cash;m_total += totalPrice;QString calcText = ui->calcCombox->currentText();ui->listWidget->addItem(QString("单价:%1  数量:%2  %3  合计:%4").arg(txtPrice).arg(txtNum).arg(calcText).arg(totalPrice));ui->totalPriceLabel->setText(QString::number(m_total));
}void Widget::on_resetBtn_clicked()
{ui->priceEdit->clear();ui->numEdit->clear();ui->listWidget->clear();ui->totalPriceLabel->setText("0.00");m_total = 0;
}void Widget::initUIControl()
{initValidator();QStringList sl;sl << "正常收费" << "打8折" << "满300减100";ui->calcCombox->addItems(sl);
}void Widget::initValidator()
{ui->priceEdit->setValidator(new QDoubleValidator(0, 10000, 2, this));ui->numEdit->setValidator(new QIntValidator(0, 100, this));
}Widget::~Widget()
{delete ui;
}

大鸟看了后说:”简单工厂模式解决对象创建问题,工厂包括了所有的收费方式,商场是可能经常性地更改打折额度和返利额度,每次维护或扩展收费方式都要改动工厂,以致代码需要重新编译部署,很糟糕的处理方式。面对算法的时常变动,应该考虑使用策略模式。“

引入策略模式

原本的CashSuperCashNormalCashRebateCashReturn都不用更改。

引入 CashContext

//CashContext.h
#include "CashSuper.h"class CashContext
{
private:CashSuper* m_cs;
public:    CashContext(CashSuper* cs) {m_cs = cs;}double GetResult(double money) {return m_cs->acceptCash(money);}
};
//Widget.cpp
#pragma execution_character_set("utf-8")
#include "Widget.h"
#include "ui_widget.h"
#include "CashSuper.h"
#include "CashContext.h"
#include "CashNormal.h"
#include "CashRebate.h"
#include "CashReturn.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);initUIControl();
}void Widget::on_okBtn_clicked()
{QString txtPrice = ui->priceEdit->text();QString txtNum = ui->numEdit->text();double totalPrice = 0;CashContext* cc = nullptr;CashSuper* cs = nullptr;switch (ui->calcCombox->currentIndex()) {case 0:cs = new CashNormal();cc = new CashContext(cs);break;case 1:cs = new CashRebate("0.8");cc = new CashContext(cs);break;case 2:cs = new CashReturn("300", "100");cc = new CashContext(cs);break;default:break;}totalPrice = cc->Double()*Double());delete cs;delete cc;m_total += totalPrice;QString calcText = ui->calcCombox->currentText();ui->listWidget->addItem(QString("单价:%1  数量:%2  %3  合计:%4").arg(txtPrice).arg(txtNum).arg(calcText).arg(totalPrice));ui->totalPriceLabel->setText(QString::number(m_total));
}void Widget::on_resetBtn_clicked()
{ui->priceEdit->clear();ui->numEdit->clear();ui->listWidget->clear();ui->totalPriceLabel->setText("0.00");m_total = 0;
}void Widget::initUIControl()
{initValidator();QStringList sl;sl << "正常收费" << "打8折" << "满300减100";ui->calcCombox->addItems(sl);
}void Widget::initValidator()
{ui->priceEdit->setValidator(new QDoubleValidator(0, 10000, 2, this));ui->numEdit->setValidator(new QIntValidator(0, 100, this));
}Widget::~Widget()
{delete ui;
}

问题:引入了策略模式,但是客户端又需要去判断使用哪一个算法了,看起来像走回老路了。考虑将简单工厂和策略模式结合。

策略与简单工厂结合

//CashContext.h
#include "CashSuper.h"class CashContext
{
private:CashSuper* m_cs;
public:    CashContext(int type);  //不是具体收费策略对象,而是类型,简单工厂的输入double GetResult(double money);virtual ~CashContext();
};
//CashContext.cpp
#include "CashContext.h"
#include "CashNormal.h"
#include "CashRebate.h"
#include "CashReturn.h"CashContext::CashContext(int type)
{switch (type) {case 0:m_cs = new CashNormal();break;case 1:m_cs = new CashRebate("0.8");break;case 2:m_cs = new CashReturn("300", "100");break;default:break;}
}double CashContext::GetResult(double money)
{return m_cs->acceptCash(money);
}CashContext::~CashContext()
{delete m_cs;
}
//Widget.cpp
#pragma execution_character_set("utf-8")
#include "Widget.h"
#include "ui_widget.h"
#include "CashContext.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);initUIControl();
}void Widget::on_okBtn_clicked()
{QString txtPrice = ui->priceEdit->text();QString txtNum = ui->numEdit->text();double totalPrice = 0;//根据Combox的选择初始化CashContext中m_cs的类型CashContext* cc = new CashContext(ui->calcCombox->currentIndex());//其实就是调用cc中m_cs的acceptCash方法totalPrice = cc->Double()*Double());delete cc;m_total += totalPrice;QString calcText = ui->calcCombox->currentText();ui->listWidget->addItem(QString("单价:%1  数量:%2  %3  合计:%4").arg(txtPrice).arg(txtNum).arg(calcText).arg(totalPrice));ui->totalPriceLabel->setText(QString::number(m_total));
}void Widget::on_resetBtn_clicked()
{ui->priceEdit->clear();ui->numEdit->clear();ui->listWidget->clear();ui->totalPriceLabel->setText("0.00");m_total = 0;
}void Widget::initUIControl()
{initValidator();QStringList sl;sl << "正常收费" << "打8折" << "满300减100";ui->calcCombox->addItems(sl);
}void Widget::initValidator()
{ui->priceEdit->setValidator(new QDoubleValidator(0, 10000, 2, this));ui->numEdit->setValidator(new QIntValidator(0, 100, this));
}Widget::~Widget()
{delete ui;
}

策列模式+简单工厂:客户端只需要知道 CashContext类

只是用简单工厂:客户端需要知道 CashSuper类CashFactory类

因此使用策略+简单工厂更加降低了客户端和底层业务代码的耦合度

本文发布于:2024-02-02 04:54:56,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170682089741489.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:模式   大话   商场   策略
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23