Reading the big talk design pattern - "WinForm" of shopping malls applying the strategic pattern

Structure of policy pattern

This pattern involves three roles:

Context role: holds a reference to a Strategy class.
Abstract Strategy role: This is an abstract role, usually implemented by an interface or abstract class. This role gives the interfaces required for all specific policy classes.
ConcreteStrategy role: encapsulates related algorithms or behaviors.

 

 

CashSuper written in the previous blog post is an abstract strategy, while CashNormal, CashRebate and CashReturn are three specific strategies, that is, the specific algorithm in the strategy mode.

Some codes of the previous blog post are attached

//Normal consumption, inheritance CashSuper
    class CashNormal:CashSuper
    {
        public override double acceptCash(double money)
        {
            return money;
        }
    }
//Discount charge consumption, inheritance CashSuper
    class CashRebate:CashSuper
    {
        private double moneyRebate = 1d;
        //During initialization, you must enter a discount rate, such as 20% discount, which is 0,8
        public CashRebate(string moneyRebate)
        {
            //Interface transferring values to classes
            this.moneyRebate = double.Parse(moneyRebate);
        }
        public override double acceptCash(double money)
        {
            return money * moneyRebate;
        }
    }
//Rebate charge
    class CashReturn:CashSuper
    {
        private double moneyCondition = 0.0d;
        private double moneyReturn = 0.0d;
        //Rebate conditions and rebate values must be entered during initialization. For example, 100 will be returned after 300
        //be moneyCondition 300,moneyReturn Is 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 it is greater than the rebate condition, the rebate value needs to be subtracted
            if (money >= moneyCondition)
            {
                result = money - Math.Floor(money / moneyCondition) * moneyReturn;
            }
            return result;
        }
    }
//Cash collection parent
    abstract class CashSuper
    {
        //Abstract method:Receive cash, the parameter is original price, and the return is current price
        public abstract double acceptCash(double money);
    }

Added policy mode (factory mode can be discarded here)

 1 namespace ExtendDiscountOfStrategyPattern
 2 {
 3     class CashContext
 4     {
 5         //Declare a cash charge parent class object
 6         private CashSuper cs;
 7 
 8         //Set policy behavior,The parameter is a specific cash charge subcategory(normal,Discount or rebate)
 9         public void setBehavior(CashSuper csuper)
10         {
11             this.cs = csuper;
12         }
13 
14         //Get the calculation results of cash promotion (using the polymorphic mechanism, different strategic behaviors lead to different results)
15         public double GetResult(double money)
16         {
17             return cs.acceptCash(money);
18         }
19     }
20 }

But the program still needs switch Case statement,

Core code (v1.3)

 1 //Declare a double variable total To calculate the total
 2         double total = 0.0d;
 3         private void btnConfirm_Click(object sender, EventArgs e)
 4         {
 5             //Declare a double variable totalPrices
 6             double totalPrices = 0d;
 7            //Policy mode
 8             CashContext cc = new CashContext();
 9             switch (cbxType.SelectedItem.ToString())
10             {
11                 case "Normal consumption":
12                     cc.setBehavior(new CashNormal());
13                     break;
14                 case "Return 100 after 300":
15                     cc.setBehavior(new CashReturn("300", "100"));
16                     break;
17                 case "20% off":
18                     cc.setBehavior(new CashRebate("0.8"));
19                     break;
20                 case "20% off":
21                     cc.setBehavior(new CashRebate("0.7"));
22                     break;
23                 case "50% off":
24                     cc.setBehavior(new CashRebate("0.5"));
25                     break;
26             }
27             totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
28             //Total each item to total
29             total = total + totalPrices;
30             //Show information in list box
31             lbxList.Items.Add("unit price:" + txtPrice.Text + "  quantity:" + txtNum.Text + "  total:" + totalPrices.ToString());
32             //stay lblTotalShow Show total count on label
33             lblTotalShow.Text = total.ToString();
34         }

 

The original policy pattern has its drawbacks. The client must know all the policy classes and decide which policy class to use. This means that the client must understand the differences between these algorithms in order to select the appropriate algorithm class in time. In other words, the policy model applies only to customers
If the client knows all the algorithms or behaviors, the initial policy pattern has shortcomings. The client must know all the policy classes and decide which policy class to use. This means that the client must understand the differences between these algorithms in order to select the appropriate algorithm class in time. In other words, the policy pattern only applies when the client knows all the algorithms or behaviors.

 

Remove switch Case statement—— (this case uses a simple.net Technology: reflection)

  

The key operation code is assembly Load ("assembly name") CreateInstance("namespace. Class name");

 

  

 

  

Client code (v1.4)

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows.Forms;
 10 //add
 11 using CCWin;
 12 using System.Data.SqlClient;
 13 
 14 namespace ExtendDiscountOfStrategyPatternWithReflection
 15 {
 16      using System.Reflection;
 17 
 18     public partial class frmMain :Skin_Metro
 19     {
 20 
 21         DataSet ds;             //Used to store configuration file information
 22 
 23         public frmMain()
 24         {
 25             InitializeComponent();
 26         }
 27         
 28         //Declare a double variable total To calculate the total
 29         double total = 0.0d;
 30         private void btnConfirm_Click(object sender, EventArgs e)
 31         {
 32             //Declare a double variable totalPrices
 33             double totalPrices = 0d;
 34            //Policy mode
 35             CashContext cc = new CashContext();
 36             //Query related rows of user selected items according to user options
 37             DataRow dr = ((DataRow[])ds.Tables[0].Select("name='" + cbxType.SelectedItem.ToString() + "'"))[0];
 38             //An array of objects that declare a parameter
 39             object[] args = null;
 40             //If there are parameters, they will be divided into string arrays for the parameters used in instantiation
 41             if (dr["para"].ToString() != "")
 42             {
 43                 args = dr["para"].ToString().Split(',');
 44             }
 45             //Generate corresponding algorithm objects through reflection instantiation
 46             cc.setBehavior((CashSuper)Assembly.Load("ExtendDiscountOfStrategyPatternWithReflection").
 47                 CreateInstance("ExtendDiscountOfStrategyPatternWithReflection." + dr["class"].ToString(), false,
 48                 BindingFlags.Default, null, args, null, null));
 49 
 50             totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
 51             //Total each item to total
 52             total = total + totalPrices;
 53             //Show information in list box
 54             lbxList.Items.Add("unit price:" + txtPrice.Text + "  quantity:" + txtNum.Text + "  total:" + totalPrices.ToString());
 55             //stay lblTotalShow Show total count on label
 56             lblTotalShow.Text = total.ToString();
 57         }
 58 
 59         private void btnReset_Click(object sender, EventArgs e)
 60         {
 61             total = 0.0;
 62             txtPrice.Text = "";
 63             txtNum.Text = "";
 64             lblTotalShow.Text = "";
 65             lbxList.Items.Clear();
 66             cbxType.SelectedIndex = 0;
 67         }
 68 
 69         private void txtNum_KeyPress(object sender, KeyPressEventArgs e)
 70         {
 71             //Number 0~9 Corresponding keychar Is 48~57
 72             e.Handled = true;
 73             //Enter 0-9
 74             if ((e.KeyChar >= 47 && e.KeyChar <= 58) || e.KeyChar == 8)
 75             {
 76                 e.Handled = false;
 77             } 
 78         }
 79 
 80         private void txtPrice_KeyPress(object sender, KeyPressEventArgs e)
 81         {
 82             //Number 0~9 Corresponding keychar Is 48~57
 83             e.Handled = true;
 84             //Enter 0-9
 85             if ((e.KeyChar >= 47 && e.KeyChar <= 58) || (e.KeyChar == 8 || e.KeyChar==46))
 86             {
 87                 e.Handled = false;
 88             } 
 89         }
 90 
 91         private void frmMain_Load(object sender, EventArgs e)
 92         {
 93             //Read configuration file
 94             ds = new DataSet();
 95             ds.ReadXml(Application.StartupPath + "\\CashAcceptType.xml");
 96             //Bind the read record to the drop-down list box
 97             foreach(DataRowView dr in ds.Tables[0].DefaultView)
 98             {
 99                 cbxType.Items.Add(dr["name"].ToString());
100             }
101 
102             //To select the element with index 0 when the drop-down selection box is loaded"Normal consumption"
103             cbxType.SelectedIndex = 0;
104         }
105     }
106 }

The program reads the XML configuration file to generate the drop-down list box. Then, according to the user's choice, the corresponding algorithm object is instantiated through reflection in real time. Finally, the final result is calculated by using the policy mode.

XML file - cashaccepttype The XML code is as follows

  

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <CashAcceptType>
 3   <type>
 4     <name>Normal consumption</name>
 5     <class>CashNormal</class>
 6     <para></para>
 7   </type>
 8   <type>
 9     <name>Return 100 after 300</name>
10     <class>CashReturn</class>
11     <para>300,100</para>
12   </type>
13   <type>
14     <name>Return 50 after 200</name>
15     <class>CashReturn</class>
16     <para>200,50</para>
17   </type>
18   <type>
19     <name>20% off</name>
20     <class>CashRebate</class>
21     <para>0.8</para>
22   </type>
23   <type>
24     <name>20% off</name>
25     <class>CashRebate</class>
26     <para>0.7</para>
27   </type>
28   <type>
29     <name>50% off</name>
30     <class>CashRebate</class>
31     <para>0.5</para>
32   </type>
33 </CashAcceptType>

Now, no matter what the requirements are, with the current program, you just need to change the XML file to settle it all. For example, the boss thinks that it is too much to give 100 free when it is over 300. To change it to 80 free, I just need to change it in the XML file.

Note: if you want to add a new algorithm, the algorithm class inherits CashSuper, and then change the XML file.

Posted by psycovic23 on Wed, 01 Jun 2022 18:12:04 +0530