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

news2024/11/27 23:49:41

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.coloradmin.cn/o/1341655.html

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

相关文章

centos7.9 TCP 加速

BBR是谷歌开发的新的TCP加速算法&#xff0c;在网络状况不好的服务器上开启TCP的bbr&#xff0c;可以在无需增加任何硬件投入的情况下实现网络加速&#xff0c;并且客户端无需做任何配置&#xff0c;因此使用起来非常的方便。TCP加速对网络状况较好的内网环境&#xff0c;或者大…

【数据结构和算法】找出两数组的不同

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 哈希类算法题注意事项 2.2 方法一&#xff1a;哈希法 三、代码 3.1 方法一&#xff1a;哈希法 四…

Oracle(4)

子查询 子查询语法很简单&#xff0c;就是select 语句的嵌套使用。 查询工资比SCOTT高的员工信息 分析&#xff1a;两步即可完成 1. 查出SCOTT的工资 SQL> select ename, sal from emp where enameSCOTT 其工资3000 2. 查询比3000高的员工 SQL> select * from emp…

【零基础入门VUE】VueJS - 环境设置

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;零基础入门VUE专栏https://blog.csdn.net/arthas777/category_12537076.html 直接在 HTML 文件中使用 <script> 标签 <html><head><script type "text/javascript" src "vue.min.j…

Spark 集群搭建

文章目录 搭建前准备安装搭建解压并重命名环境变量配置配置文件yarn-site.xmlspark-env.sh 官网求 π(PI) 案例启动spark-shell通过浏览器查看显示查看 Spark 的网页信息展示 搭建前准备 下载地址&#xff1a;Index of /dist/spark (apache.org) 配置好 hadoop 环境&#xff…

实战 | 使用OpenCV快速去除文档中的表格线条(步骤 + 源码)

导 读 本文主要介绍如何使用OpenCV快速去除文档中的表格线条,并给详细步骤和代码。 背景介绍 测试图如下,目标是去除下面三张图中的表格线条,方便后续图像处理。 实现步骤 下面演示详细步骤,以图1为例: 【1】获取二值图像:加载图像、转为灰度图、OTSU二值化 i…

Awesome Chrome Form UI - 框架设计与基础实现

Money is not evil by itself. Its just paper with perceived value to obtain other things we value in other ways. If not money what is evil you may ask? Evil is the unquenchable, obsessive and moral bending desire for more. Evil is the bottomless,soulless …

多模态大模型-CogVLm 论文阅读笔记

多模态大模型-CogVLm 论文阅读笔记 COGVLM: VISUAL EXPERT FOR LARGE LANGUAGEMODELS 论文地址 :https://arxiv.org/pdf/2311.03079.pdfcode地址 : https://github.com/THUDM/CogVLM时间 : 2023-11机构 : zhipuai,tsinghua关键词: visual language model效果:&#xff08;2023…

C++面向对象(OOP)编程-C++11新特性详解

C11作为一个重要的版本&#xff0c;引入了很多新的特性&#xff0c;解决了C语言本身很多遗留的内存泄露问题&#xff0c;并且提供了很多比较灵活的用法。引入的auto&#xff0c;智能指针、线程机制都使得C语言的灵活性、安全性、并发性有了很大的提升。 本文会比较详细的介绍C1…

医疗行业的信息安全现状

文章目录 前言一、医疗行业相关政策法规二、“互联网+医疗健康”推进信息安全建设三、医疗行业网络安全形势依然严峻1、等级保护工作未全面开展落实2、医疗行业网络安全风险较高医疗行业网络安全隐患普遍存在遭受勒索病毒攻击严重3、安全防护水平相对落后缺乏必要的网络安全防护…

QT应用篇 三、QML自定义显示SpinBox的加减按键图片及显示值效果

QT应用篇 一、QT上位机串口编程 二、QML用Image组件实现Progress Bar 的效果 三、QML自定义显示SpinBox的加减按键图片及显示值效果 文章目录 QT应用篇前言一、qml需求二、使用组件1.SpinBox组件2.SpinBox中QML的使用 总结 前言 记录自己学习QML的一些小技巧方便日后查找 QT的…

rsync备份工具

有了同步源服务器之后&#xff0c;就可以使用rsync工具来执行远程同步了&#xff0c;本节介绍的备份操作均在客 户机&#xff08;发起端&#xff09;执行&#xff0c;实际上&#xff0c;同步源与发起端可以是同一台主机&#xff08;当然这种情况不常见&#xff09;&#xff0c;…

腾讯云轻量服务器和云服务器区别对比(超详细)

腾讯云轻量服务器和云服务器CVM该怎么选&#xff1f;不差钱选云服务器CVM&#xff0c;追求性价比选择轻量应用服务器&#xff0c;轻量真优惠呀&#xff0c;活动 https://curl.qcloud.com/oRMoSucP 轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年&#xff0c;540元三…

【12.28】转行小白历险记-刷算法04

01两两交换链表中的节点 整体思路 1.要修改后一个节点的指向一定要知道前一个节点的指向才可以改变后面一个节点的 2.分情况奇数和偶数节点&#xff0c;终止条件很重要 3.虚拟头节点&#xff0c;是对我们操作的指针是不是头节点进行判断 02删除链表的倒数第N个节点 思路 …

大数据与人工智能|万物皆算法(第三节)

要点一&#xff1a;数据与智能的关系 1. 一切的核心都是数据&#xff0c;数据和智能之间是密切相关的。 数据是对客观现实的描述&#xff0c;而信息是数据转化而来的。 例如&#xff0c;24是数据&#xff0c;但说“今天的气温是24摄氏度”是信息&#xff0c;而说“班可以分成24…

oracle与mysql的分析函数(窗口函数)

分析函数定义 在SQL语句中&#xff0c;很多查询语句需要进行GROUP BY分组汇总&#xff0c;但是一旦经过分组&#xff0c;SELECT返回的记录数就会减少。为了保留所有原始行记录&#xff0c;并且仍可以进行分组数据分析&#xff0c;分析函数应运而生。 Oracle 8i 版本开始支持窗…

java在线票务系统(选座)Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java servlet 在线票务系统&#xff08;选座&#xff09;管理系统是一套完善的java web信息管理系统 系统采用serlvetdaobean&#xff08;mvc模式)&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要…

MongoDB主从复制,一文打尽!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

Hadoop安装笔记2单机/伪分布式配置_Hadoop3.1.3——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2:离线数据处理

紧接着上一篇博客&#xff1a;Hadoop安装笔记1&#xff1a; Hadoop安装笔记1单机/伪分布式配置_Hadoop3.1.3——备赛笔记——2024全国职业院校技能大赛“大数据应用开发”赛项——任务2&#xff1a;离线数据处理-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/135…

K8s实战-基于LivenessProbe健康检查

LivenessProbe探针用于判断容器是否存活&#xff0c;如果探测到容器不健康&#xff0c;则kubelet将杀掉该容器&#xff0c;然后根据重启策略处理。 LivenessProbe的实现方式&#xff1a; ExecAction&#xff1a;在容器内部执行一个命令&#xff0c;如果该命令的返回码为0&…