【设计模式】商场促销 -- 策略模式

2024-04-05 01:38

本文主要是介绍【设计模式】商场促销 -- 策略模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一,概念

        策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

二,策略模式的组成

   1)抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
   2)具体策略角色:包装了相关的算法和行为。

   3)环境角色:持有一个策略类的引用,最终给客户端调用。

三,补充C++知识

类对象的构造顺序是这样的:
  1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员
  2.进入构造函数后在构造函数中执行一般计算
       1)类里面的任何成员变量在定义时是不能初始化的。
       2)一般的数据成员可以在构造函数中初始化。
       3)const数据成员必须在构造函数的初始化列表中初始化。
       4)static要在类的定义外面初始化。  
       5)数组成员是不能在初始化列表里初始化的。
       6)不能给数组指定明显的初始化。 
这6条一起,说明了一个问题:C++里面是不能定义常量数组的!因为3和5的矛盾。这个事情似乎说不过去啊?没有办法,我只好转而求助于静态数据成员。
到此,我的问题解决。但是我还想趁机复习一下C++类的初始化:
  1.初始化列表:CSomeClass::CSomeClass() : x(0), y(1){}
  2.类外初始化:int CSomeClass::myVar=3;
  3.const常量定义必须初始化,C++类里面使用初始化列表;
  4.C++类不能定义常量数组。

在C++类中,必须做如下事情:

1.必须对任何const或引用类型成员以及没有默认构造函数的 类 类型 的任何成员 显示地使用初始化列表进行初始化

2.类成员在定义时是不能被初始化的

3.类的成员初始化顺序与成员变量在构造函数中的位置选后顺序无关,至于成员变量在类中定义的先后顺序有关

C++默认继承方式为private

C++ new 生成的对象为指针,所以new 前面的对象要声明为指针类型

四,实例

        计算器简单工厂模式的精简实现

#include <iostream>
using namespace std;class COperation//基类
{
public:int m_nFirst;int m_nSecond;virtual double GetResult(){double dResult=0;return dResult;}
};class AddOperation : public COperation//加法
{
public:virtual double GetResult(){return m_nFirst+m_nSecond;}
};class SubOperation : public COperation//减法
{
public:virtual double GetResult(){return m_nFirst-m_nSecond;}
};class CCalculatorFactory//工厂类
{public://静态方法属于类本身,不属于哪个对象 static COperation* Create(char cOperator);};COperation* CCalculatorFactory::Create(char cOperator)//工厂类的实现
{COperation *oper;//在C#中可以用反射来取消判断时用的switch,在C++中用什么呢?RTTI??switch (cOperator){case '+':oper=new AddOperation();break;case '-':oper=new SubOperation();break;default:oper=new AddOperation();break;}return oper;
}int main()
{int a,b;cin>>a>>b;/*静态方法为类所有,可以通过对象来使用,也可以通过类来使用。但一般提倡通过类名来使用,因为静态方法只要定义了类,不必建立类的实例就可使用*/COperation * op = CCalculatorFactory::Create('-');//静态方法调用方式 op->m_nFirst=a;op->m_nSecond=b;cout<<op->GetResult()<<endl;return 0;
}

将简单工厂模式优化为策略模式后的代码如下:

#include <iostream>
using namespace std; //策略基类
class COperation
{
public:int m_nFirst;int m_nSecond;virtual double GetResult(){double dResult=0;return dResult;}
};//策略具体类-加法类
class AddOperation : public COperation
{
public:AddOperation(int a,int b){m_nFirst=a;m_nSecond=b;}virtual double GetResult(){return m_nFirst+m_nSecond;}
};class Context//策略类 
{
private:COperation* op;
public:Context(COperation* temp)//参数为策略基类(传递的时候被初始化为子类) {op=temp;}double GetResult(){return op->GetResult();}
};//客户端
int main()
{int a,b;char c;cin>>a>>b;cout<<"请输入运算符:";cin>>c;switch(c){case '+':Context *context=new Context(new AddOperation(a,b));cout<<context->GetResult()<<endl;break;default:break;}return 0;
}

这里将策略(操作符)封装成一个Context类,通过传递操作符子对象来返回相应子对象下操作结果。

菜鸟实现工厂模式和策略模式

        客户端只需访问Context类,而不用知道其它任何类信息,实现了低耦合。在上例基础上,修改下面内容

#include <iostream>
using namespace std;//策略基类
class COperation
{
public:int m_nFirst;int m_nSecond;virtual double GetResult(){double dResult=0;return dResult;}
};//策略具体类-加法类
class AddOperation : public COperation
{
public:AddOperation(int a,int b){m_nFirst=a;m_nSecond=b;}AddOperation(){m_nFirst=0;m_nSecond=0;}virtual double GetResult(){return m_nFirst+m_nSecond;}
};
class Context
{
private:COperation* op;
public:Context(char cType){switch (cType){case '+':op=new AddOperation(3,8);break;default:op=new AddOperation();break;}}double GetResult(){return op->GetResult();}
};
//客户端
int main()
{Context *test=new Context('+');cout<<test->GetResult()<<endl;return 0;
}

五,商场促销例子

        这里想说的是,abstract 关键字是微软为C#定义的,抽象类关键字。C++中没有抽象类,如果想成为抽象类在类中定义纯虚函数就可以了。只要拥有纯虚函数的类就是抽象类,由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。

         商场促销的简单工厂实现:

#include <iostream>using namespace std;class CashSuper //现金收费抽象类
{
public:virtual double acceptCash(double money)//不能设置为纯虚函数,后面还要生成对象用呢!!!! (不能只定义,而不实现){}
};class CashNormal : public CashSuper //收费子类,正常收费
{
public:double acceptCash(double money){return money;}};class CashRebate : public CashSuper //打折收费子类
{
private:double moneyRebate;//不允许初始化
public:CashRebate(double moneyRebate){this->moneyRebate=moneyRebate;}double acceptCash(double money){return money*moneyRebate;}
};class CashReturn :public CashSuper //返利收费子类(默认继承为私有继承)
{
private:double moneyCondition ;//返利购买额度double moneyReturn ;//返利多少
public:CashReturn(double moneyCondition,double moneyReturn){this->moneyCondition=moneyCondition;this->moneyReturn=moneyReturn;}double acceptCash(double money){double result = money;if(money >= moneyCondition )result = money-(money/moneyCondition)*moneyReturn;return result;}
};class CashFactory
{
public:static CashSuper* creatCashAccept(string type)//根据子类type来生成相应收费子类{CashSuper *cs;if(type=="CashNormal")cs=new CashNormal();else if(type == "CashRebate")cs=new CashRebate(0.8);else if(type == "CashReturn")cs=new CashReturn(300,100);return cs;}
};int main(int argc, char** argv) {CashSuper *csuper = CashFactory::creatCashAccept("CashRebate");double result=csuper->acceptCash(500);//500打八折,应该输出 400cout<<"CashRebate 500 is:"<<result<<endl;return 0;
}策略模式:定义了算法家族,分别封装起来,让它们之间可以相互替换,算法的变化不会影响使用算法的客户。
        主要升级就是,将算法封装到Context中,然后通过传递对象生成相应子类对象,然后得到结果。

#include <iostream>using namespace std;class CashSuper //现金收费抽象类
{
public:virtual double acceptCash(double money)//不能设置为纯虚函数,后面还要生成对象用呢!!!! {}
};class CashNormal : public CashSuper //收费子类,正常收费
{
public:double acceptCash(double money){return money;}};class CashRebate : public CashSuper //打折收费子类
{
private:double moneyRebate;//不允许初始化
public:CashRebate(double moneyRebate){this->moneyRebate=moneyRebate;}double acceptCash(double money){return money*moneyRebate;}
};class CashReturn :public CashSuper //返利收费子类(默认继承为私有继承)
{
private:double moneyCondition ;//返利购买额度double moneyReturn ;//返利多少
public:CashReturn(double moneyCondition,double moneyReturn){this->moneyCondition=moneyCondition;this->moneyReturn=moneyReturn;}double acceptCash(double money){double result = money;if(money >= moneyCondition )result = money-(money/moneyCondition)*moneyReturn;return result;}
};/*class CashFactory
{
public:static CashSuper* creatCashAccept(string type)//根据子类type来生成相应收费子类{CashSuper *cs;if(type=="CashNormal")cs=new CashNormal();else if(type == "CashRebate")cs=new CashRebate(0.8);else if(type == "CashReturn")cs=new CashReturn(300,100);return cs;}
};*/class CashContext
{
private:CashSuper cs;
public:CashContext(CashSuper csuper){this->cs=csuper;}double GetResult(double money){return cs.acceptCash(money);}
};int main(int argc, char** argv) {//CashSuper *csuper = CashFactory::creatCashAccept("CashRebate");//double result=csuper->acceptCash(500);//500打八折,应该输出 400CashContext *cs;string type="CashRebate";if(type=="CashNormal")cs=CashContext(new CashNormal());else if(type == "CashRebate")cs=CashContext(new CashRebate(0.8));else if(type == "CashReturn")cs=CashContext(new CashReturn(300,100));cout<<"CashRebate 500 is"<<cs->GetResult(500)<<endl;return 0;
}

这样仍然存在缺点:就是让客户端来判断生成哪个子类。

改进策略是,让策略模式和工厂模式结合

#include <iostream>using namespace std;class CashSuper //现金收费抽象类
{
public:virtual double acceptCash(double money)//不能设置为纯虚函数,后面还要生成对象用呢!!!! {}
};class CashNormal : public CashSuper //收费子类,正常收费
{
public:double acceptCash(double money){return money;}};class CashRebate : public CashSuper //打折收费子类
{
private:double moneyRebate;//不允许初始化
public:CashRebate(double moneyRebate){this->moneyRebate=moneyRebate;}double acceptCash(double money){return money*moneyRebate;}
};class CashReturn :public CashSuper //返利收费子类(默认继承为私有继承)
{
private:double moneyCondition ;//返利购买额度double moneyReturn ;//返利多少
public:CashReturn(double moneyCondition,double moneyReturn){this->moneyCondition=moneyCondition;this->moneyReturn=moneyReturn;}double acceptCash(double money){double result = money;if(money >= moneyCondition )result = money-(money/moneyCondition)*moneyReturn;return result;}
};/*class CashFactory
{
public:static CashSuper* creatCashAccept(string type)//根据子类type来生成相应收费子类{CashSuper *cs;if(type=="CashNormal")cs=new CashNormal();else if(type == "CashRebate")cs=new CashRebate(0.8);else if(type == "CashReturn")cs=new CashReturn(300,100);return cs;}
};*/class CashContext
{
private:CashSuper cs;
public:CashContext(string type){if(type=="CashNormal")this->cs=new CashNormal();else if(type == "CashRebate")this->cs=new CashRebate(0.8);else if(type == "CashReturn")this->cs=new CashReturn(300,100);}double GetResult(double money){return cs.acceptCash(money);}
};int main(int argc, char** argv) {CashContext *cs=new CashContext("CashRebate");cout<<"CashRebate 500 is"<<cs->GetResult(500)<<endl;return 0;
}

这样客户端只需要更改金额和打折手段就可以了。相对简单工厂的提升为:简单工厂需要让客户调用两个类SuperCash和CashFactory。而结合之后仅仅需要调用CashContext就可以了

相对与策略模式的提升为:客户端需要承担的判断更少了,更简洁了


这篇关于【设计模式】商场促销 -- 策略模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/877352

相关文章

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

Redis过期键删除策略解读

《Redis过期键删除策略解读》Redis通过惰性删除策略和定期删除策略来管理过期键,惰性删除策略在键被访问时检查是否过期并删除,节省CPU开销但可能导致过期键滞留,定期删除策略定期扫描并删除过期键,... 目录1.Redis使用两种不同的策略来删除过期键,分别是惰性删除策略和定期删除策略1.1惰性删除策略

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停