读《大话设计模式》——应用策略模式的"商场收银系统"(WinForm)
策略模式的结构

这个模式涉及到三个角色:
环境(Context)角色:持有一个 Strategy 类的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

上篇博文写的CashSuper 就是抽象策略,而正常收费 CashNormal、打折收费 CashRebate 和返利收费 CashReturn 就是三个具体策略,也就是策略模式中说的具体算法。
附上上篇博文的部分代码

//正常消费,继承CashSuper
class CashNormal:CashSuper
{
public override double acceptCash(double money)
{
return money;
}
}

//打折收费消费,继承CashSuper
class CashRebate:CashSuper
{
private double moneyRebate = 1d;
//初始化时,必需要输入折扣率,如八折,就是0,8
public CashRebate(string moneyRebate)
{
//界面向类传值
this.moneyRebate = double.Parse(moneyRebate);
}
public override double acceptCash(double money)
{
return money * moneyRebate;
}
}

//返利收费
class CashReturn:CashSuper
{
private double moneyCondition = 0.0d;
private double moneyReturn = 0.0d;
//初始化时必须要输入返利条件和返利值,比如满300返100
//则moneyCondition为300,moneyReturn为100
public CashReturn(string moneyCondition, string moneyReturn)
{
this.moneyCondition =double.Parse(moneyCondition);
this.moneyReturn = double.Parse(moneyReturn);
} public override double acceptCash(double money)
{
double result = money;
//若大于返利条件,则需要减去返利值
if (money >= moneyCondition)
{
result = money - Math.Floor(money / moneyCondition) * moneyReturn;
}
return result;
}
}

//现金收取父类
abstract class CashSuper
{
//抽象方法:收取现金,参数为原价,返回为当前价
public abstract double acceptCash(double money);
}
加入的策略模式(这里可以弃用工厂模式了)
namespace ExtendDiscountOfStrategyPattern
{
class CashContext
{
//声明一个现金收费父类对象
private CashSuper cs; //设置策略行为,参数为具体的现金收费子类(正常,打折或返利)
public void setBehavior(CashSuper csuper)
{
this.cs = csuper;
} //得到现金促销计算结果(利用了多态机制,不同的策略行为导致不同的结果)
public double GetResult(double money)
{
return cs.acceptCash(money);
}
}
}
但是程序还是少不了switch...case语句,
核心代码(v1.3)
//声明一个double变量total来计算总计
double total = 0.0d;
private void btnConfirm_Click(object sender, EventArgs e)
{
//声明一个double变量totalPrices
double totalPrices = 0d;
//策略模式
CashContext cc = new CashContext();
switch (cbxType.SelectedItem.ToString())
{
case "正常消费":
cc.setBehavior(new CashNormal());
break;
case "满300返100":
cc.setBehavior(new CashReturn("", ""));
break;
case "打8折":
cc.setBehavior(new CashRebate("0.8"));
break;
case "打7折":
cc.setBehavior(new CashRebate("0.7"));
break;
case "打5折":
cc.setBehavior(new CashRebate("0.5"));
break;
}
totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
//将每个商品合计计入总计
total = total + totalPrices;
//在列表框中显示信息
lbxList.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtNum.Text + " 合计:" + totalPrices.ToString());
//在lblTotalShow标签上显示总计数
lblTotalShow.Text = total.ToString();
}

最初的策略模式是有缺点的,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户
端知道所有的算法或行为的情况最初的策略模式是有缺点的,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
去掉switch...case语句!!!——(本案例采用简单的.net技术:反射)
关键的操作代码为:Assembly.Load(" 程序集名称").CreateInstance(" 名称空间.类名称");

客户端代码(v1.4)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
//add
using CCWin;
using System.Data.SqlClient; namespace ExtendDiscountOfStrategyPatternWithReflection
{
using System.Reflection; public partial class frmMain :Skin_Metro
{ DataSet ds; //用于存放配置文件信息 public frmMain()
{
InitializeComponent();
} //声明一个double变量total来计算总计
double total = 0.0d;
private void btnConfirm_Click(object sender, EventArgs e)
{
//声明一个double变量totalPrices
double totalPrices = 0d;
//策略模式
CashContext cc = new CashContext();
//根据用户的选项,查询用户选择项的相关行
DataRow dr = ((DataRow[])ds.Tables[].Select("name='" + cbxType.SelectedItem.ToString() + "'"))[];
//声明一个参数的对象数组
object[] args = null;
//若有参数,则将其分割成字符串数组,用于实例化时所用的参数
if (dr["para"].ToString() != "")
{
args = dr["para"].ToString().Split(',');
}
//通过反射实例化出相应的算法对象
cc.setBehavior((CashSuper)Assembly.Load("ExtendDiscountOfStrategyPatternWithReflection").
CreateInstance("ExtendDiscountOfStrategyPatternWithReflection." + dr["class"].ToString(), false,
BindingFlags.Default, null, args, null, null)); totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
//将每个商品合计计入总计
total = total + totalPrices;
//在列表框中显示信息
lbxList.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtNum.Text + " 合计:" + totalPrices.ToString());
//在lblTotalShow标签上显示总计数
lblTotalShow.Text = total.ToString();
} private void btnReset_Click(object sender, EventArgs e)
{
total = 0.0;
txtPrice.Text = "";
txtNum.Text = "";
lblTotalShow.Text = "";
lbxList.Items.Clear();
cbxType.SelectedIndex = ;
} private void txtNum_KeyPress(object sender, KeyPressEventArgs e)
{
//数字0~9所对应的keychar为48~57
e.Handled = true;
//输入0-9
if ((e.KeyChar >= && e.KeyChar <= ) || e.KeyChar == )
{
e.Handled = false;
}
} private void txtPrice_KeyPress(object sender, KeyPressEventArgs e)
{
//数字0~9所对应的keychar为48~57
e.Handled = true;
//输入0-9
if ((e.KeyChar >= && e.KeyChar <= ) || (e.KeyChar == || e.KeyChar==))
{
e.Handled = false;
}
} private void frmMain_Load(object sender, EventArgs e)
{
//读取配置文件
ds = new DataSet();
ds.ReadXml(Application.StartupPath + "\\CashAcceptType.xml");
//将读取到的记录绑定到下拉列表框中
foreach(DataRowView dr in ds.Tables[].DefaultView)
{
cbxType.Items.Add(dr["name"].ToString());
} //要下拉选择框在加载的时候,就选择索引为0的元素"正常消费"
cbxType.SelectedIndex = ;
}
}
}
通过程序去读XML的配置文件,来生成这个下拉列表框,然后再根据用户的选择,通过反射实时的实例化出相应的算法对象,最终利用策略模式计算最终的结果。
XML文件——CashAcceptType.xml代码如下
<?xml version="1.0" encoding="utf-8" ?>
<CashAcceptType>
<type>
<name>正常消费</name>
<class>CashNormal</class>
<para></para>
</type>
<type>
<name>满300返100</name>
<class>CashReturn</class>
<para>300,100</para>
</type>
<type>
<name>满200返50</name>
<class>CashReturn</class>
<para>200,50</para>
</type>
<type>
<name>打8折</name>
<class>CashRebate</class>
<para>0.8</para>
</type>
<type>
<name>打7折</name>
<class>CashRebate</class>
<para>0.7</para>
</type>
<type>
<name>打5折</name>
<class>CashRebate</class>
<para>0.5</para>
</type>
</CashAcceptType>
现在无论需求是什么,用现在的程序,只需要改改XML文件就全部摆平了。比如现在老板觉得现在满300送100太多了,要改成送80,我只需要去XML文件里改就行了。
注:如要添加新的算法,那么该算法类继承CashSuper,再去改一下XML文件就可以了。
读《大话设计模式》——应用策略模式的"商场收银系统"(WinForm)的更多相关文章
- 读《大话设计模式》——应用工厂模式的"商场收银系统"(WinForm)
要做的是一个商场收银软件,营业员根据客户购买商品单价和数量,向客户收费.两个文本框,输入单价和数量,再用个列表框来记录商品的合计,最终用一个按钮来算出总额就可以了,还需要一个重置按钮来重新开始. 核心 ...
- javascript 写策略模式,商场收银打折优惠策略
[Decode error - output not utf-8] ----------------------------- 购物清单 方便面 : 100 x 50 = 5000 | 4000 菊花 ...
- 大话设计模式之策略模式(strategy)
策略模式:它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响使用算法的用户. 针对商城收银模式,打折,返现促销等的例子: 打折还是促销其实都是一些算法,可以用工厂模式来 ...
- JavaScript设计模式之策略模式(学习笔记)
在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...
- 设计模式:策略模式(Strategy)
定 义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...
- swift设计模式学习 - 策略模式
移动端访问不佳,请访问我的个人博客 设计模式学习的demo地址,欢迎大家学习交流 策略模式 策略模式定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户. ...
- php 商场收银收费系统,使用的策略模式
<?php//策略模式就是你有很多的方法,选择一种适合自己的,// 单例模式就是只有一个实例对象,不需要每个文件都要加载,比如连接数据库,// 工厂模式就是 //策略模式 优惠系统.工资计算系统 ...
- [Python设计模式] 第2章 商场收银软件——策略模式
github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...
- 从零开始单排学设计模式「策略模式」黑铁 II
阅读本文大概需要 1.7 分钟. 本篇是设计模式系列的第三篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统.所以现在打算重写,加上距离现在也有一段时间了, ...
随机推荐
- jar 反编译工具
luyten windows版本的 链接:https://pan.baidu.com/s/1hp6gyvJSj_4h60dk5AZejA 密码:c4u7 之所以推荐它,是因为它能避免普通的编译工具jd ...
- php 加反斜杠的原因与处理办法
php程序加反斜杠的原因就是要进行特殊字符的转义. 默认PHP 指令 magic_quotes_gpc是on的,这时候就可以用stripslashes() 函数删除自动添加的反斜杠. 用法就是:str ...
- 深入理解PHP原理之Opcodes
Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL. 举个例子,比如你写下了如下的PHP代码: <?php echo "Hello Wo ...
- php 常用的redis操作语法
String 类型操作 string是redis最基本的类型,而且string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 $redis-> ...
- 【JMeter_16】JMeter逻辑控制器__随机控制器<Random Controller>
随机控制器<Random Controller> 业务逻辑: 当每次执行到该逻辑控制器时,随机挑选控制器下的任意一个子节点<取样器.逻辑控制器> Ignore sub-cont ...
- cc28c_demo.cpp,派生类的构造函数和析构函数-代码示范3
cc28c_demo.cpp,派生类的构造函数和析构函数-代码示范3 //派生类的构造函数和析构函数//派生类的构造函数(执行步骤)//--执行基类的构造函数//--执行成员对象的构造函数//--执行 ...
- vulstack红队评估(三)
一.环境搭建: ①根据作者公开的靶机信息整理 没有虚拟机密码,纯黑盒测试...一共是5台机器,目标是拿下域控获取flag文件 ②虚拟机网卡设置 centos双网卡模拟内外网: 外网:192.168 ...
- CODING DevOps 系列第五课:微服务测试——微服务下展开体系化的微服务测试
微服务测试的痛点与挑战 这张图可以形象地展示单体服务和微服务的对比,单体应用就像左边巨大的集装箱,软件模块和应用都包括其中:而微服务就像是由一个小集装箱组成,微小的服务组成一个庞大.完整的系统.单体服 ...
- 手把手教你基于SqlSugar4编写一个可视化代码生成器(生成实体,以SqlServer为例,文末附源码)
在开发过程中免不了创建实体类,字段少的表可以手动编写,但是字段多还用手动创建的话不免有些浪费时间,假如一张表有100多个字段,手写有些不现实. 这时我们会借助一些工具,如:动软代码生成器.各种ORM框 ...
- ImageLoader在Gridview中的使用
原理和ImageLoader在Listview中的使用一样,只有下面的几点变化 主页面的布局 <?xml version="1.0" encoding="utf-8 ...