Application scenario: now the supermarket needs a set of supermarket cashier system. We need to make a set of cashier system. The demand will be very simple. When we think about it, it's just a matter of several text boxes. Enter the unit price and quantity, and then calculate it. However, if supermarkets launch discount activities in the later stage, can our text boxes still meet the demand? At this time, some friends must say that it's OK to add a drop-down list. What if there are other activities in the future? Don't you want to change the code around?
At this time, the strategy mode is used.
I use the winform program.
1: We propose that there are three settlement methods: no discount, 20% discount or 100% off for 300.
After analysis, these three discount methods must be implemented by three classes (basic policy class). Then let's think about it further. Since the functions of the three classes are to meet different discount operations, can we find a common ground among the three classes? At this time, abstract policy classes appear (because the three basic policy classes are only used to realize the activity requirements, but supermarkets often have various activities, so these classes will be changed from one to another. This is the change point, and encapsulating the change point is a very important way of thinking of our object-oriented).
2: Define an abstract policy class
An abstract class is like a mold. If you instantiate it with Class A, it is an entity a, and if you instantiate it with class B, it is an entity B, but only if both classes a or B inherit this abstract class and implement it in code.
//What are abstract classes? In fact, it is like a mold. What material (class) you inject into it will become what material (class). public abstract class CashSuper//Abstract class, which is the abstract policy class. All discount specific policy classes will inherit (implement) this class { /// <summary> ///The input parameter is the total amount before discount, and the output parameter is the amount after discount /// </summary> /// <param name="Total"></param> /// <returns></returns> public abstract double CashFuncInterFace(double total);//Abstract method, which will be implemented after the concrete policy class inherits (implements) the abstract class. }
3: Now that there are abstract classes, let's create different discount classes (basic policy classes) to implement this abstract class.
public class CashFullPay : CashSuper//Full payment specific category { public override double CashFuncInterFace(double total) { return total; } }
public class CashEightDiscount : CashSuper//Basic strategies with 20% discount { public override double CashFuncInterFace(double total) { return total * 0.8; } }
class CashThreeMinusOne : CashSuper//Over 300 minus 100 basic policies { public override double CashFuncInterFace(double total) { return total - Math.Floor(total / 300) * 100; } }
4: At this point, the abstract policy class and the three basic policy classes have been built respectively, but where can we instantiate the abstract policy class? Never in the background code? The code written like that is too messy, so we give him a unified entry (context class: Context)
public class Context//Context class is used to instantiate the abstract policy class (model) into various basic policy classes to meet the needs of the scenario through the passed in parameters { CashSuper cashSuper;//Abstract policy class public Context(CashSuper cashSuper)//Instantiate our abstract policy class through the constructor { this.cashSuper = cashSuper;//Instantiate the abstract policy class through the underlying policy class in the constructor. It's like pouring different materials into the mold } //What basic policy class is instantiated, and what is returned here is the method implemented by the basic policy class public double CashFuncInterFace(double total) { return cashSuper.CashFuncInterFace(total); } }
5: There are also entry classes for instantiating policy classes. Let's instantiate different policy classes according to different discounts in the background code.
private void btn_Confirm_Click(object sender, EventArgs e) { Context = null; double total = 0; switch (comBox_Mode.SelectedValue) { case "1": Context = new Context(new CashFullPay());//No discount break; case "0.8": Context = new Context(new CashEightDiscount());//20% off break; case "300-100": Context = new Context(new CashThreeMinusOne());//One hundred minus three hundred break; default://Default no discount Context = new Context(new CashFullPay());//No discount break; } total = Context.CashFuncInterFace(double.Parse(txt_Num.Text) * double.Parse(txt_Price.Text));//Calculate the amount after different discounts txt_TotalInfo.Text += $"{txt_Name.Text}Bought{txt_Num.Text}One, each{txt_Price.Text}RMB, Discount:{comBox_Mode.Text},common{total.ToString()}element\r\n"; lab_TotalMoney.Text = (double.Parse(lab_TotalMoney.Text) + total).ToString(); }
6: Finally, the renderings
At this point, the strategic model is finished. However, careful partners must have found a problem, that is, if there are new activities in the mall, we must modify the drop-down list and add branches in the switch of the back-end code to meet the requirements, so in essence, we still have to modify the code to recompile, which does not solve the substantive problem. Therefore, one of the design patterns mentioned in the previous section: simple factory pattern is used again. Here, if you use the simple factory mode + policy mode, you can perfectly solve the problem of modifying the code and recompiling.
See the next section for the specific implementation method.