C#之策略模式

该文章很清晰的描述了策略,转载地址:https://blog.csdn.net/weixin_42341986/article/details/94736312
策略模式定义为:定义算法家族,封装每一个算法,并使它们可以替换。策略可以让算法独立于使用它的客户端。
这个模式涉及到三个角色:

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

案例展示:
在商场收银系统中,可以正常收费,即按照单价*数量得出价格,遇到活动时可以打折收费和返利收费,从而计算价格。
运用策略模式,案例大概可以分为几个部分:
环境角色:环境类(CashContext)
抽象策略角色:收费父类(CashSuper)
具体策略角色:正常收费类(CashNormal),打折收费类(CashRebate),返利收费类(CashReturn)
客户端程序
类图为
在这里插入图片描述
设计了类图之后,便可以根据类图写具体的实现代码了~

CashSuper类:接收现金,作为一个父类,acceptCash方法为正常收费,打折收费,返利收费都需用到的方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cash_System
{
    abstract class CashSuper
    {
        //收取现金,参数为当前价格
        public abstract double acceptCash(double money);
    }
}

CashNormal类:继承父类,重载父类方法,计算价格。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cash_System
{
    //正常收费,继承父类,重载父类的方法,计算出价格,返回计算后的价格
    class CashNormal:CashSuper
    {
        public override double acceptCash(double money)
        {
            return money;
        }
    }
}

CashReturn类:需要定义自己的返利方法CashReturn,为自己独有,并且重载父类方法计算价格。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cash_System
{
    class CashReturn:CashSuper
    {
        private double moneyCondition = 0.0d; //定义达到返利条件的价格
        private double moneyReturn = 0.0d; //定义返利额度
        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;
        }
    }
}

CashRebate类:同CashReturn类类似。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cash_System
{
    class CashRebate:CashSuper
    {
        private double moneyRebate = 0.0d; //定义折扣
        public CashRebate(string moneyRebate)
        {
            this.moneyRebate = double.Parse(moneyRebate);
        }
        public override double acceptCash(double money)
        {
            return money*moneyRebate;
        }
    }
}

CashContext类:提供接口,与客户端交互。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cash_System
{
    class CashContext
    {
        //声明父类对象
        private CashSuper cs;
        //设置策略行为,参数为收费子类
        public void setBehavior(CashSuper csuper)
        {
            this.cs = csuper;
        }
        //得到收费计算的结果
        public double GetResult(double money)
        {
            return cs.acceptCash(money);
        }
    }
}

客户端代码为:

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;
using System.Reflection; //运用反射实例化
using System.Xml;

namespace Cash_System
{
    public partial class Form1 : Form
    {
        private double total = 0.0d;
        private DataSet ds;
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            ds = new DataSet();
            ds.ReadXml(Application.StartupPath + "\\CashAcceptType.xml"); //Xml的路径  /debug/bin/CashAcceptType.xml
            //从配置文件中读取的记录绑定到下拉列表
            foreach (DataRowView dr in ds.Tables[0].DefaultView)
            {
                cbxType.Items.Add(dr["name"].ToString());
            }
            cbxType.SelectedIndex = 0;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CashContext cc = new CashContext();
            DataRow dr = ((DataRow[])ds.Tables[0].Select("name='" + cbxType.SelectedItem.ToString() + "'"))[0];
            object[] args = null;
            if (dr["para"].ToString() != "")
                args = dr["para"].ToString().Split(',');
            cc.setBehavior((CashSuper)Assembly.Load("Cash_System").CreateInstance("Cash_System."+dr["class"].ToString(), false, BindingFlags.Default, null, args, null, null));
            double totalPrice = 0.0d;
            totalPrice = cc.GetResult(Convert.ToDouble(txtPrice.Text)*Convert.ToDouble(txtNum.Text));
            total = total + totalPrice;
            lbxList.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtNum.Text + " 类型:" + cbxType.SelectedItem + " 合计:" + totalPrice.ToString());
            lblResult.Text = total.ToString();
        }

        private void clear_Click(object sender, EventArgs e)
        {
            total = 0d;
            txtPrice.Text = "0.00";
            txtNum.Text = "1";
            lbxList.Items.Clear();
            lblResult.Text = "0.00";
        }
    }
}

**反射:**利用程序集的元数据信息。 反射可以有很多方法,编写程序时先导入 System.Reflection 命名空间。
CashAcceptType.xml 内容为:

<?xml version="1.0" encoding="utf-8" ?>
<CashAcceptType>
  <type>
    <name>正常收费</name>
    <class>CashNormal</class>
    <para></para>
  </type>
  <type>
    <name>300100</name>
    <class>CashReturn</class>
    <para>300,100</para>
  </type>
  <type>
    <name>20050</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>
</CashAcceptType>

假如需要增加新的收银方式,只需要在CashSuper下建立新的子类,并在xml文件中增加相应的名称,便不会影响其他子类,也不会影响客户端程序的使用,这便是策略模式的最大优点了。

执行程序的结果为:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值