C++设计模式实践——线上购物系统

news2024/11/24 22:39:07

一、系统的主要目标与功能

在本次设计中,考虑到目前疫情反复不断,为了方便群众,超市都推出在线购物并有配送员送货,于是我设计了一个超市在线网上购物送货的系统,这个系统的主要目标是帮助人们在家里购买自己需要的套餐,充值账户,同时该系统能查看自己的历史金额变动记录,也能够撤销前一次操作,这样能够帮助疫情期间的人们快速购物,也能够减少疫情期间出门购物的可能带来的危害。本超市目前功能如下:
1:查看超市套餐
2:购买超市套餐
3:给账户充值
4:查看历史余额记录
5:撤回上次操作
6:系统自动提示配送员
7:退出本超市在线购物系
系统运行比较简单,且每一步完成后都会有提示信息,按照提示信息一步一步运行即可。

二、系统运行截图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

三、系统中使用的设计模式(UML类图、详细描述场景、解决的问题、模式的效果及意义)

在这里插入图片描述

•1.状态模式

:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。在一个对象内在状态改变时也改变了其行为,这个对象看起来像改变了其类,因此选择使用状态模式。
在这里插入图片描述

•设计思路:在本系统中,状态模式在购物时提供用户信息和余额的信息,分别为正常状态GreenState,欠款状态RedState与会员VIP状态。在进入程序时便初始化账户Account,通过这个账户记录余额balance信息,同时考虑到余额不足时不能购物,考虑到特殊情况,设计余额不足购买时允许赊欠,但当前余额小于0时不能购物,这样是考虑到实际,余额小于0时是不能购买的;此外若充值后余额超过1000元,则当前状态变为VIP模式,之后购买商品可以有8折优惠。

程序设计:Account中有属性state来聚合AccountState记录当前Account的状态,且有RedState,GreenState,VIP三个子状态继承AccountState,AccountState中有balance余额属性,在每个子状态里面有stateCheck()函数,可以在调用该函数后判断balance的数值,来改变当前Account所处的状态,并在改变状态后改变消费的行为。Accout有函数deposit和withdraw,分别是存款和取款来对balance进行操作,并会根据属性state的不同有不同的行为。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Account中有属性msStrategy,这是与策略模式结合的属性,在代码中设计的为若状态为GreenState或RedState,即初试化为MessageStrategy2直接在窗口输出,若为VIP状态,则初试化为MessageStrategy1,产生MessageBox弹窗通知。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

•2.建造者模式

:建筑者模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示。
在这里插入图片描述

设计思路:在本系统中建造者模式可用于构建不同的套餐1,套餐2,套餐3,由超市Supermarket作为指挥者,将套餐的内部表象与生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象Product,并且使客户便于查看各个套餐的内容与价格便于购买。

程序设计:首先Supermarket是系统中建造者模式的Director指导者,拥有Construct()函数,且拥有Builder类的bld属性,使用Construct()即可调佣bld中的BuildPartA,B,C函数,来构建出Product产品类,从而返回Product完成建造,将Product的复杂构造在ConcreteBuilder内实现,而Supermarket只需要设置不同的bld属性和调用Construct()函数,即可创建不同的产品,实现产品构建的封装。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

•3.观察者模式

:观察者模式建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

在这里插入图片描述

设计思路:在本系统中,观察者模式的观察目标为商家系统Supermarket,具体观察者为配送员DeliveryObserver,多个配送员DeliveryObserver观察对应的商家系统Supermarket,当有客户在商家购买套餐时,商家系统会发出通知提醒观察了自己的配送员。

程序设计:在Supermarket中有Attach()和Detach()两个函数与list<DeliveryObserver*>accs即 DeliveryObserver的一个列表,Attach()来增加配送员Observer为观察者,Detach()删除观察者Observer,然后在消费者进行购物后,通过调用notify()函数来进行通知,且Observer中具体的notify()函数与策略模式相结合,对于list中的单数采用MessageStrategy1通知,list采用MessageStrategy2来通知。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

•4.单例模式

:单例类只有一个实例对象,且该单例对象必须由单例类自行创建,单例类对外提供一个访问该单例的全局访问点。
在这里插入图片描述

设计思路:在本系统中,单例类为商家类,只允许创建一个商家类,且该商家类是建造者模式的指挥者,指挥套餐的建立。

程序设计:在Supermarket里面,有私有静态的Supermarket类属性_instance,然后将构造函数定义为保护函数防止外界调用,在调用构造函数时判断_instance是否为空,若为空则可初始化,否则返回_instance。
在这里插入图片描述

•5.策略模式

:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式的主要目的是将算法的定义与使用分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。
在这里插入图片描述

设计思路:本系统中,策略模式在观察者模式的基础上使用,在观察者模式通知Observer时,通知方式可选择不同的策略,如短信通知或软件信息通知等,在本系统中选择弹窗通知MessageStrategy1与直接输出通知MessageStrategy2来模拟这两种不同的通知方式。

此外,策略模式与状态模式也有在一起联合使用,若Account目前状态为GreenState或RedState,即初试化为MessageStrategy2直接在命令行窗口输出,若为VIP状态,则初试化为MessageStrategy1,产生MessageBox弹窗通知。
在这里插入图片描述

程序设计:MessageStrategy有两个子类,分别为MessageStrategy1与MessageStrategy2,MessageStrategy1即采用MessageBox进行弹窗输出,而MessageStrategy2即为cout直接输出,使用时可具体不同的策略类来实现不同的通知方式

在这里插入图片描述

在这里插入图片描述

•6.备忘录模式

:在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

在这里插入图片描述

设计思路:在本系统中,备忘录模式记录在系统中的余额变动,并可查看所有的历史变动记录,并可以撤销上一次余额变动的操作,在现实中大部分购物应用都可以查看历史记录与撤销,因此利用备忘录模式实现该操作,便于观察余额变化。

程序设计:首先通过UserInfoDTO来在主函数中将每次余额改变时的balance即state记入Memento,然后利用Caretaker中的mementoList来记录每次余额改变后的Memento值。在查看历史记录时,即调用UserInfoDTO的getStateFromMemento()函数来遍历mementoList所有记录的历史余额;在想要进行撤销操作时,即首先调用user.getStateFromMemento()获取最近一次操作后的余额值,之后调用p->setbalance(user.getState())将余额记录到Account账户中,且对于第一次操作与第0次操作有不同的撤销行为。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

四、设计模式总结

本次实践作业我使用了一些比较常见的设计模式,包括状态模式,单例模式,建造者模式,观察者模式,策略模式,备忘录模式。我个人认为在设计模式的使用有两个亮点。
第一个亮点就是策略模式与观察者模式与状态模式联合使用,而不是将策略模式进行单一的使用。这个想法是我在进行观察者模式设计时,发现观察者模式的通知功能可以有不同的策略实现后做出的模式设计。我将策略模式与观察者模式与状态模式联合使用,对于不同的观察者,不同的状态时会有不同的行为,因此我将策略模式融合到这两种模式中,这也是对于设计模式的一种深入使用,而不仅仅是生硬的套用。在本次实践中,。
第二个亮点是备忘录模式的使用,我个人认为备忘录模式的理解和代码设计都有一定的难度,在实践过程中也确实遇到了一些困难如Caretaker和Memento的区别,以及如何存和取历史数据,但经过认真学习进行了解决。
通过使用这些设计模式,代码对修改有了封闭性,在客户端没有具体实现,难以修改,而在进行扩展时更加容易,如对于策略模式,如果想要添加一个新的策略实现不同的通知方式,只需要增加一个策略实现的子类MessageStrategy3即可实现策略添加。

五、个人的模式学习心得

在本次面向对象与系统建模的课程学习中,我个人认为收获良多,与本科学习过的设计模式相比学到了更多与更加深入,首先是因为研一与本科学习时相比自己做过的项目与见过的代码更多,更加理解了为什么要运用设计模式来进行代码封装与复用,如何使用设计模式来更好的扩展代码,为什么设计代码时要满足开闭原则等多项原则。(而不像是本科学习时觉得进行这些设计模式的使用没有用处,反而让人看不懂代码具体逻辑)。
此外,也正是提前了解到了设计模式的重要性,我学习的兴趣也更加浓厚,因此我除了在上课时的学习,还购买了《大话设计模式》进行课外学习,同时参加了软件设计师的考试,于是我对设计模式的复用性有了更深入的了解,对于重要的模式如观察者模式、状态模式、工厂模式,适配器模式等理论方面有了更加深入的理解,对于每种设计模式的UML类图也更加理解,对于该在哪种应用场景来使用某种设计模式、如何用代码实现这些模式也更加明确,对一些不太常见的模式如原型模式,访问者模式也了解更多,更加理解了设计模式对于修改封闭,扩展开放的好处,对于迪米特法则、单一职责原则等更加理解。

六、意见和建议

个人认为对于设计模式的学习不能追求通过上课来速成,要在自己进行代码编写的过程中以及后续代码修改过程中才能深入理解设计模式的重要性。
因此对于学习过程中建议可以不用课本,直接用能够运行的使用了2-3个设计模式的简单项目,并编写2个不同的代码,一个没有使用设计模式的代码,一个使用了设计模式代码,首先演示让同学们了解代码的作用,然后平时作业可以让同学们分别对两种代码进行扩展,如对于状态模式,可以让学生对两种代码都加一种状态,这样可能比对着书本更容易理解设计模式的作用,而在期末作业上也可以要求同学们对于上课时的简单项目进行扩展,如多加几个设计模式。

七、main函数与抽象类代码

Main函数:可以看到在Main函数与抽象类中没有看到具体的实现代码,仅仅只有函数的调用,因此基本满足开闭原则,扩展性良好,想要扩展时仅仅只需要增加子类。
在这里插入图片描述

.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Rust 学习笔记

参考自Rust 程序设计语言 简体中文版 1. Hello world 2. Cargo&#xff08;Rust 的构建系统和包管理器&#xff09; 使用 Cargo 创建项目 Cargo 配置文件 Cargo 目录结构 构建并运行 Cargo 项目 发布&#xff08;release&#xff09;构建 Cargo 常用命令 cargo build&#xf…

【青训营】Go的测试

Go的测试 测试主要包括&#xff1a;回归测试、集成测试、单元测试 一、单元测试 其中测试单元可以是函数&#xff0c;也可以是模块 规则&#xff1a; 1.所有测试文件都以_test.go结尾 2.测试函数命名规范:func TestXxx(*Testing.T) 3.初始化逻辑需要放置在TestMain中 以下是…

django框架【待续】

目录简介MVC与MTV模型MVCMTV创建项目目录生命周期静态文件配置&#xff08;无用&#xff09;启动django[启动](https://www.cnblogs.com/xiaoyuanqujing/articles/11902303.html)路由分组无名分组有名分组路由分发反向解析反向解析结合分组名称空间re_path与path自定义转换器视…

为什么普通人赚钱这么难?普通人的赚钱之路在哪里

前几天听一个老家的朋友说辛辛苦苦一整年&#xff0c;发现并没有赚到什么钱。付出与收入不成正比。首先要知道勤奋、努力并不一定就能够赚到钱像送外卖的&#xff0c;工地上班的&#xff0c;厂里上班的哪个不勤奋但他们即使非常努力工作一个月&#xff0c;扣除基本开支&#xf…

这是一篇知识帖:终于能明白云原生技术的概念和可落地的应用分享

随着云计算的发展和普及&#xff0c;云原生概念的热度也越来越高&#xff0c;到底什么是云原生&#xff1f;和我们日常工作有什么关系&#xff1f;本文是向大家介绍云原生技术的概念和要点&#xff0c;帮助大家快速了解和学习云原生&#xff0c;&#xff0c;便于大家了解工作的…

【PHP了解】PHP脚本语言基础

PHP PHP 文件的默认文件扩展名是 “.php”PHP 文件通常包含 HTML 标签和一些 PHP 脚本代码 例&#xff1a; <!DOCTYPE html> <html> <body><?php xxxxxxxxxxxxxxxxx; ?></body> </html>语法 代码框架 <?php 开始&#xff0c;以 ?…

DW动手学数据分析Task1:数据加载及探索性数据分析

目录1 数据载入1.1 载入数据1.2 read_csv和read_table的区别1.3 逐块读取1.4 修改表头和索引2 数据初步观察2.1 查看数据基本信息2.2 保存数据3 pandas数据结构和列操作3.1 Series 和DataFrame3.2 查看 DataFrame数据每列的名称和值3.3 DataFrame 的列删除和隐藏4 数据筛选4.1 …

如何合并pdf?来看这几个方法!

我们经常在整理文件的时候经常会选择将一些常用文件的格式改为pdf&#xff0c;因为这种文件格式就算发送给了别人&#xff0c;别人也不能随意的修改文件内容&#xff0c;这就保证了我们的文件内容的隐私安全。不过&#xff0c;对于处理pdf文件&#xff0c;我们还是会面临一些不…

c++ dynamic_cast,static_cast,const_cast,reinterpret_cast四种cast用法整理

在C中主要分为四种cast&#xff0c;分别是&#xff1a;static_cast、dynamic_cast、const_cast和reinterpret_cast dynamic_cast动态类型转换 首先&#xff0c;我们明确基类和派生类之间的两个转换术语 向上转换(upcast)&#xff1a;派生类向基类转换 向下站还(downcast)&…

证券服务应用评测系列:海通e海通财发布9.0版本,探索证券APP持续提升用户体验

易观分析&#xff1a;APP作为券商机构线上服务的入口&#xff0c;其活跃用户规模和运营水平在一定程度上能够体现机构战略定位、品牌运营、科技创新、用户竞争等综合实力。易观分析认为&#xff0c;如何围绕用户进行创新&#xff0c;利用技术将壁垒升高&#xff0c;打造具有品牌…

PuTTY installation directory must be on a local hard drive

putty安装问题 问题描述&#xff1a;安装时候报错&#xff0c;installation directory must be on a local hard drive 解决方案&#xff0c;无法解决。 很多人使用了这个方法解决了。但是我解决不了。 1、如果是exe类型的&#xff0c;直接右击以管理员身份运行。 2、如果是…

常用的文件类型大全(建议收藏)

文件格式格式图标格式概况mpg文件mpg是一种常见的视频格式,mpeg标准主要有以下五个,MPEG-1、MPEG-2、MPEG-4、MPEG-7及MPEG-21等。mpg有可能是基于MPEG-1(VCD)或MPEG-2torrent文件torrent文件(扩展名为.torrent)包含了一些BT下载所必须的信息,根据BitTorrent协议,文件发布者…

opencv文字旋转 putText旋转90°

文章目录● opencv文字旋转 putText旋转901. cv::getTextSize获取文字的尺寸textSize2. 设置文字图像textImg尺寸格式3. 将文字绘制在文字图像textImg上4. 对文字图像textImg进行旋转5. 在原图img上设置用来放置文字图像textImg的roi区域5.1 矩形区域roi5.2 行列范围roi6. 将文…

Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation论文解读

Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation 论文&#xff1a;[2105.05537] Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation (arxiv.org) 代码&#xff1a;HuCaoFighting/Swin-Unet: The codes for the work “Swin-Unet:…

LiveNVR监控流媒体Onvif/RTSP功能功能-支持GB35114接入国标流媒体平台接入说明

LiveNVR监控流媒体Onvif/RTSP功能功能-支持GB35114接入国标流媒体平台接入说明1、GB35114注册2、LiveNVR通过GB35114接入LiveGBS2.1、开启LiveGBS 35114功能2.2、 获取设备端证书给平台2.3、LiveGBS白名单中添加需要接入的国密设备2.4、导出LiveGBS平台端证书给设备&#xff08…

管理学实验的设计与实践结课作业

一、不同组织结构类型对组织的沟通效率会带来影响&#xff0c;这也是在组织结构设计过 程需要考虑的重要内容&#xff0c;但对于两者的关系无法准确界定。如在直线职能制的组织结构中&#xff0c;管理幅度和深度是影响是影响沟通效率的主要因素。请设计实验来验证分析直线职能制…

手动部署SQL审计平台Archery(连接mysql8.x)

安装Python和virtualenv从1.9.0版本开始&#xff0c;将不再支持python3.7及以下版本&#xff0c;手动安装也将使用3.9版本作为样例&#xff0c;移除yum安装方式# 安装依赖 yum install libffi-devel wget gcc make zlib-devel openssl openssl-devel ncurses-devel openldap-de…

分享81个PHP源码,总有一款适合您

PHP源码 分享81个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 81个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/18jo0nrQ6tCf-e1PAylItmQ?pwd3rxz 提取码&#xff…

Mysql之多表查询

简单测试 由于我们之前没学过多表查询 我们简单测试一下初学者认为的多表查询 SELECT * FROM emp,dept这是我们的输出结果 其实不难发现 1.返回的结果就是&#xff0c;第一张表一个个数据取出然后和第二张表所有组合 最后返回的是含有两张表的所有列 2.一共返回的记录数第一章…

【ES6篇新语法】(1)ES6介绍及常量声明、对象数组,附实例详解

【写在前面】 应一些粉丝的要求&#xff0c;整理一些ES6相关的文章&#xff0c;因此借这个岁末之际&#xff0c;给大家整理一篇ES6的相关的博客&#xff0c;不管是面试还是在实际的编程上&#xff0c;我们都常提到ES6这个词&#xff0c;可能前几年比较热门&#xff0c;希望大家…