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

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

相关文章

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

redis过期key的删除策略介绍

《redis过期key的删除策略介绍》:本文主要介绍redis过期key的删除策略,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录第一种策略:被动删除第二种策略:定期删除第三种策略:强制删除关于big key的清理UNLINK命令FLUSHALL/FLUSHDB命

SpringRetry重试机制之@Retryable注解与重试策略详解

《SpringRetry重试机制之@Retryable注解与重试策略详解》本文将详细介绍SpringRetry的重试机制,特别是@Retryable注解的使用及各种重试策略的配置,帮助开发者构建更加健... 目录引言一、SpringRetry基础知识二、启用SpringRetry三、@Retryable注解

MySQL 分区与分库分表策略应用小结

《MySQL分区与分库分表策略应用小结》在大数据量、复杂查询和高并发的应用场景下,单一数据库往往难以满足性能和扩展性的要求,本文将详细介绍这两种策略的基本概念、实现方法及优缺点,并通过实际案例展示如... 目录mysql 分区与分库分表策略1. 数据库水平拆分的背景2. MySQL 分区策略2.1 分区概念

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR