Xamarin开发:商场促销(策略设计模式)

Xamarin开发:商场促销(策略设计模式)

  • 一、介绍
  • 二、需求分析
  • 三、实现
  • 四、需求分析
    • 问题1解决方案
    • 问题2解决方案
  • 五、增加新需求
  • 六、代码优化与分析
  • 总结

一、介绍

本文引用《大话设计模式》第二章节的内容进行学习分析,仅供学习使用

这里接着我上一篇 Xamarin开发:基础 继续编写
这里采用策略设计模式进行编写,所谓的代码设计并不是单单指某一种的设计模式而已,比如我们接下来要介绍的策略设计模式实际上是基于简单工厂设计模式的改造而来的,所以在设计代码逻辑的时候不要忠于代码一定要使用某一种设计模式来实现,而应该是应该将需求细化,具体分析适合哪一种设计模式,我所认为的设计模式实际上就是将我们平时比较复杂的代码规范化、降低代码的重复性、冗余性的表现,让我们的代码更加的简单,让其他程序看到感觉之后感觉逻辑简单,代码清晰,这也是作为一名程序员应该具有的能力。

二、需求分析

先看一下需求,如下图
在这里插入图片描述

这里我们先抛开 计算方式 这一问题
仅仅实现简单的 输入单价输入数量,点击确认按钮计算出在 总计,并在TextView中显示,单价: xx 数量: xx 总计: xx
并且点击重置,有重置功能即可

这里对于刚开始接触编程的人来说可能分析并不会透彻,只为来实现功能而去实现,但是不要紧我们可以一步步的优化将我们的代码进行规范化,让别人看着思路清晰。

三、实现

这里就不在讲述我的点击时间和Label属性是如何注册和调用的了,如果不知道的可以看我上一篇文章

打开Vs 中的 ViewController.cs脚本

这是没有编写逻辑的脚本

namespace ShoppingMall{public partial class ViewController : NSViewController{public ViewController(IntPtr handle) : base(handle){}public override void ViewDidLoad(){base.ViewDidLoad();// Do any additional setup after loading the view.}public override NSObject RepresentedObject{get{return base.RepresentedObject;}set{base.RepresentedObject = value;// Update the view, if already loaded.}}}

这里将 确认点击 按钮的事件注册一下

 /// <summary>/// Makes the sure.确认按钮/// </summary>/// <param name="sender">Sender.</param>partial void MakeSure(NSButton sender){throw new NotImplementedException();}/// <summary>/// Resert the specified sender.重置按钮/// </summary>/// <param name="sender">Sender.</param>partial void Resert(NSButton sender){throw new NotImplementedException();}

编写逻辑如下

	/// <summary>/// The m price.单价/// </summary>private double m_price = 0d;/// <summary>/// The m amount.数量/// </summary>private double m_amount = 0d;/// <summary>/// The m totalmoney.未折扣价格/// </summary>private double m_totalmoney = 0d;/// <summary>/// Makes the sure.确认按钮/// </summary>/// <param name="sender">Sender.</param>partial void MakeSure(NSButton sender){if (string.IsNullOrEmpty(PriceField.StringValue) || string.IsNullOrEmpty(AmountField.StringValue))return;m_price = double.Parse(PriceField.StringValue);m_amount = double.Parse(AmountField.StringValue);m_totalmoney = m_price * m_amount;TotalPrice.StringValue = m_totalmoney.ToString();TextView.Value = "单价:" + m_price + " 数量:" + m_amount + " 正常收费 合计:" + m_totalmoney;}/// <summary>/// Resert the specified sender.重置按钮/// </summary>/// <param name="sender">Sender.</param>partial void Resert(NSButton sender){PriceField.StringValue = string.Empty;AmountField.StringValue = string.Empty;TextView.Value = string.Empty;TotalPrice.StringValue = "0.00";}

功能如下
在这里插入图片描述

四、需求分析

这里我们来分析一下上述代码:
问题1:代码中用到了很多double.Parse() 怎么解决?
问题2:这时候上面又提出新的需求,我们要采用一个打折处理,如何处理比较妥当?

问题1解决方案

这里编写一个工具类,直接string.ToDouble()即可

public static class Tools{public static double ToDouble(this string str) {double dbl = 0d;double.TryParse(str,out dbl);return dbl;}}

问题2解决方案

这里我们添加一个下拉菜单即可(Pop Up Button)
这里需要初始化一下下拉菜单的选项

这里在编写一个Const类,里面存放下拉列表选项:

public class Const{public static string[] PullDown = { "请选择计费方式", "正常收费", "八折" };}

注册下拉列表事件并写一个初始化的方法:

    /// <summary>/// Init this instance.初始化/// </summary>public void Init(){PullDown.RemoveAllItems();PullDown.AddItems(Const.PullDown);}/// <summary>/// Drops down.下拉列表选择/// </summary>/// <param name="sender">Sender.</param>partial void DropDown(NSPopUpButton sender){PullDown.Title = sender.TitleOfSelectedItem;}
这里的Init方法放在加载窗口之后直接执行public override void ViewDidLoad(){base.ViewDidLoad();Init();// Do any additional setup after loading the view.}

这里分析一下打折处理,我们可以把打折 正常收费作为一个对象处理,然后写一个抽象类让我们创建的对象去继承,最后写一个简单工厂去实例化对象,从而降低了代码的耦合性,使其后续的修改不会影响到其他类;

修改一下点击事件最后代码如下:

	/// <summary>/// Cash super.抽象类/// </summary>public abstract class CashSuper{public abstract double AcceptCash(double money);}/// <summary>/// Cash normal.正常/// </summary>public class CashNormal : CashSuper{public override double AcceptCash(double money){return money;}}/// <summary>/// Cash rebate.打折/// </summary>public class CashRebate : CashSuper{private double moneyRebate = 1d;public CashRebate(string moneyRebate) {this.moneyRebate = double.Parse(moneyRebate);}public override double AcceptCash(double money){return money * moneyRebate;}}

简单工厂:

	public class CashFactory{public static CashSuper CreateCashAccept(string type) {CashSuper super = null;switch (type){case "正常收费":super = new CashNormal();break;case "八折":super = new CashRebate("0.8");break;default:break;}return super;}}

点击事件修改

      /// <summary>/// The discount.折扣价/// </summary>private double m_discount = 0d;/// <summary>/// Makes the sure.确认按钮/// </summary>/// <param name="sender">Sender.</param>partial void MakeSure(NSButton sender){if (string.IsNullOrEmpty(PriceField.StringValue) || string.IsNullOrEmpty(AmountField.StringValue))return;m_price = PriceField.StringValue.ToDouble();m_amount = AmountField.StringValue.ToDouble();m_totalmoney = m_price * m_amount;//简单工厂模式CashSuper super = CashFactory.CreateCashAccept(PullDown.Title);m_discount = super.AcceptCash(m_totalmoney);TotalPrice.StringValue = m_discount.ToString();TextView.Value = "单价:" + m_price + " 数量:" + m_amount + " 合计:" + m_discount;}

在这里插入图片描述

五、增加新需求

这时候我们增加了一个满减的活动 满300减100

这时候我们分析,只需要在增加一个满减类即可,并且修改一下简单工厂就可以完美解决

新增类:

/// <summary>/// Cash return.返利/// </summary>public class CashReturn : CashSuper{private double moneyCondition = 0d;private double moneyReturn = 0d;public CashReturn(string moneyCondition,string moneyReturn) {this.moneyCondition = double.Parse(moneyCondition);this.moneyReturn = double.Parse(moneyReturn);}public override double AcceptCash(double money){if (money >= moneyCondition)return money - Math.Floor(money / moneyCondition) * moneyReturn;return money;}}

简单工厂类修改:

public class CashFactory{public static CashSuper CreateCashAccept(string type) {CashSuper super = null;switch (type){case "正常收费":super = new CashNormal();break;case "八折":super = new CashRebate("0.8");break;case "满300减100":super = new CashReturn("300","100");break;default:break;}return super;}}

功能如下:
在这里插入图片描述

六、代码优化与分析

这里我们看一下 确认按钮 的点击事件中的逻辑
现在我们获取结果的时候我们需要调用两个类一个是抽象类,另一个是工厂类,这样不利于代码的清晰度,这时候我们需要将简单工厂与策略模式结合一下,让我们的代码更加简洁。

如下:

public class CashContext{private CashSuper m_cashsuper = null;public CashContext(string type){switch (type){case "正常收费":m_cashsuper = new CashNormal();break;case "八折":m_cashsuper = new CashRebate("0.8");break;case "满300减100":m_cashsuper = new CashReturn("300", "100");break;default:m_cashsuper = null;break;}}public double GetResult(double money){return m_cashsuper.AcceptCash(money);}}

点击事件修改:

/// <summary>/// Makes the sure.确认按钮/// </summary>/// <param name="sender">Sender.</param>partial void MakeSure(NSButton sender){if (string.IsNullOrEmpty(PriceField.StringValue) || string.IsNullOrEmpty(AmountField.StringValue))return;m_price = PriceField.StringValue.ToDouble();m_amount = AmountField.StringValue.ToDouble();m_totalmoney = m_price * m_amount;简单工厂模式//CashSuper super = CashFactory.CreateCashAccept(PullDown.Title);//m_discount = super.AcceptCash(m_totalmoney);//简单工厂与策略模式结合CashContext cc = new CashContext(PullDown.Title);m_discount = cc.GetResult(m_totalmoney);TotalPrice.StringValue = m_discount.ToString();TextView.Value = "单价:" + m_price + " 数量:" + m_amount + " 合计:" + m_discount;}

这样使得我们的代码更加的简洁,对一个类进行操作即可

UML类图:在这里插入图片描述

总结

实际上策略模式实际上是一种定义一系列算法的方法,概念来讲所有的算法都是实现相同的工作,只是实现不一样,它可以以相同的方式调用所有算法,减少了各种算法类与算法类之间的耦合度。

好处:简化了单元测试,每个算法都有自己的类,可以通过自身的接口进行单独测试,不影响其他类。

注意:策略模式是封装各种算法,所以避免不了很多的判断,那么这个时候不管是ifswitch其实都不是最好的选择,我们那可以选择使用反射来进行,反射在之后的博客中讲解。

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

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

相关文章

css 设置鼠标覆盖显示菜单

鼠标覆盖到“全部分类”效果如下 鼠标放到“精品推荐”效果如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&g…

elasticsearch列一:索引模板的使用

概述 近期一直在负责es这块&#xff0c;就想着和大家分享一些使用经验&#xff0c;我们从存储、查询、优化、备份、运维等几个方面来做分享。今天咱们先看下如何更加合理的存储数据。 初见索引模板 记得刚接触es还是18年那会&#xff0c;项目上线后因一些原因导致日志这部分的…

网易有道词典不能截屏翻译,不能联网解决办法

对应版本&#xff1a; win10系统&#xff0c;联想拯救者笔记本&#xff0c;网易有道词典8.10.2.0。 网易有道词典免费下载链接&#xff1a;https://download.csdn.net/download/qq_42755734/88684985 修改代理&#xff1a; youdao.com 0 取消勾选---不更新 效果&#xff1a…

自然语言处理2——轻松入门情感分析 - Python实战指南

目录 写在开头1.了解情感分析的概念及其在实际应用中的重要性1.1 情感分析的核心概念1.1.1 情感极性1.1.2 词汇和上下文1.1.3 情感强度1.2 实际应用中的重要性 2. 使用情感分析库进行简单的情感分析2.1 TextBlob库的基本使用和优势2.1.1 安装TextBlob库2.1.2 文本情感分析示例2…

【MySQL】数据库中为什么使用B+树不用B树

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 数 据 库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 B树的特点和应用场景&#xff1a; B树相对于B树的优势&#xff1a; 结论&#xff1a; 结语 我的其他博客 前言 在数据…

穿越时光的镜头:2023回顾与2024展望

前言 2023 年就像一本充满着惊喜和挑战的书籍&#xff0c;它的每一页都留下了我生活中不同的痕迹。回顾过去&#xff0c;我发现了许多意想不到的成长和启示&#xff0c;也体验了生活的起起伏伏。 这篇文章是对 2023 年的一个小小总结&#xff0c;也是对未来的一点期许。在这里…

【微服务】springboot整合skywalking使用详解

目录 一、前言 二、SkyWalking介绍 2.1 SkyWalking是什么 2.2 SkyWalking核心功能 2.3 SkyWalking整体架构 2.4 SkyWalking主要工作流程 三、为什么选择SkyWalking 3.1 业务背景 3.2 常见监控工具对比 3.3 为什么选择SkyWalking 3.3.1 代码侵入性极低 3.3.2 功能丰…

最优化方法Python计算:无约束优化应用——神经网络回归模型

人类大脑有数百亿个相互连接的神经元&#xff08;如下图(a)所示&#xff09;&#xff0c;这些神经元通过树突从其他神经元接收信息&#xff0c;在细胞体内综合、并变换信息&#xff0c;通过轴突上的突触向其他神经元传递信息。我们在博文《最优化方法Python计算&#xff1a;无约…

从实际工作情况,介绍嵌入式(MCU)软件开发常用(通用)工具

目录 前言 1、代码阅读及编辑工具&#xff08;VSCode、Understand&#xff09; 2、代码对比工具&#xff08;Beyond Compare&#xff09; 3、代码仓库相关工具&#xff08;Git、SVN、Tortoise&#xff09; 4、文本编辑器&#xff08;Notepad&#xff09; 5、电脑文件搜索工…

【LeetCode:2660. 保龄球游戏的获胜者 | 模拟】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

PAT 乙级 1046 划拳

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为&#xff1a;每人口中喊出一个数字&#xff0c;同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和&#xff0c;谁就赢了&#xff0c;输家罚一杯酒。两人同赢或两人同输则继续下一轮&…

Python序列之集合

系列文章目录 Python序列之列表Python序列之元组Python序列之字典Python序列之集合&#xff08;本篇文章&#xff09; Python序列之集合 系列文章目录前言一、集合是什么&#xff1f;二、集合的操作1.集合的创建&#xff08;1&#xff09;使用{}创建&#xff08;2&#xff09;…

SpringBoot定时监听RocketMQ的NameServer

问题分析 自己在测试环境部署了RocketMQ&#xff0c;发现namesrv很容易挂掉&#xff0c;于是就想着监控&#xff0c;挂了就发邮件通知。查看了rocketmq-dashboard项目&#xff0c;发现只能监控Broker&#xff0c;遂放弃这一路径。于是就从报错的日志入手&#xff0c;发现最终可…

【MATLAB第87期】#源码分享 | 基于MATLAB的增量神经系统网络SFAM多输入单输出多分类预测模型

【MATLAB第87期】#源码分享 | 基于MATLAB的增量神经系统网络SFAM多输入单输出多分类预测模型 前言 SFAM是一种增量神经网络分类器。它是模糊ARTMAP&#xff08;FAM&#xff09;的一个简单而快速的版本。如果输入相同,FAM和SFAM的产出相同。 参考文献: [1] Kasuba, T. (1993)…

【MMdetection】MMdetection从入门到进阶

基础环境安装 步骤 0. 从官方网站下载并安装 Miniconda。 步骤 1. 创建并激活一个 conda 环境。 conda create --name openmmlab python3.8 -y conda activate openmmlab步骤 2. 基于 PyTorch 官方说明安装 PyTorch。 pip install torch2.0.1 torchvision0.15.2 torchaudio…

【MySQL表的增删查改】

文章目录 前言1 Create1.1 单行数据 全列插入1.2 多行数据 指定列插入1.3 插入否则更新1.4 替换 2 Retrieve2.1 SELECT 列2.1.1 全列查询2.1.2 指定列查询2.1.3 查询字段为表达式2.1.4 为查询结果指定别名2.1.5 结果去重 2.2 WHERE 条件2.2.1 英语不及格的同学及英语成绩 ( &…

C++基础:指针数组和数组指针(大白话讲解)

指针数组&#xff1a;本质上是一个数组&#xff0c;数组中的每一个元素都是一个指针&#xff1b; 数组指针&#xff1a;本质上是一个指针&#xff0c;数组指针是一个指向数组的指针。 为了更直观的分析他们的区别&#xff0c;我举个例子&#xff1a; #include<iostream&g…

操作系统:可变分区管理

有作业序列&#xff1a;作业A要求42K&#xff1b;作业B要求27K&#xff0c;作业C要求22K&#xff0c;作业和空闲内存区如下图所示&#xff0c;请画出最佳适应算法空闲队列图&#xff0c;并分析最佳适应算法是否适合该作业系列。 答&#xff1a;最佳适应算法是按照空闲块由小到大…

【辐射场】3D Gaussian Splatting

三维高斯…喷喷 \, 3D Gaussian Splatting&#xff0c;下文简称3DGS&#xff0c;是好一段时间以来在三维内容创作和三维重建领域比较有热度的一项技术。 它属于基于图像的三维重建方法&#xff0c;意思就是你对现实物体或者场景拍照片&#xff0c;就能给你训练成一个场景模型&a…

C语言之整型提升

文章目录 1 有可能出现的问题2 产生以上问题的原因&#xff08;整型提升&#xff09;3 整型提升的过程4 整型提升示例5 总结 1 有可能出现的问题 代码如下 #include <stdio.h>int main () {int a -1;unsigned int b 1;if (a < b) {printf("a < b");}…