策略模式:定义了算法家族,分别封装起来,让其之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
下边使用例子来具体分析:
制作一个商场收银的软件,营业员根据客户购买的单价和数量,向客户收费。并附带打折的选项。效果如下图所示:
主要部分代码:
using System; using System.Windows.Forms; namespace strategy { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { comboBox1.Items.Add("8折"); comboBox1.Items.Add("6折"); comboBox1.Items.Add("4折"); } /// <summary> /// 单价 /// </summary> public double price; /// <summary> /// 数量 /// </summary> public double number; /// <summary> /// 总价钱 /// </summary> public double total; /// <summary> /// 确定按钮点击事件 /// </summary> private void button1_Click(object sender, EventArgs e) { Console.WriteLine(comboBox1); price = Convert.ToDouble(textBox1.Text); number = Convert.ToDouble(textBox2.Text); switch (comboBox1.SelectedIndex) { case 0: total = price * number * 0.8; break; case 1: total = price * number * 0.6; break; case 2: total = price * number * 0.4; break; default: total = price * number; break; } richTextBox1.Text = Convert.ToString(total); label5.Text = Convert.ToString(total); } /// <summary> /// 重置按钮点击事件 /// </summary> private void button2_Click(object sender, EventArgs e) { textBox1.Clear(); textBox2.Clear(); richTextBox1.Clear(); label5.Text = ""; } } }
这样就可以实现上边所描述的功能。
这个例子我们也可以使用简单工厂模式来实现。刚好也复习一下“简单工厂模式”。
简单工厂模式的精髓就是在基类(abstract,interface ,class)中定义一个方法,由其子类来实现或者重写他。将逻辑计算部分封装成一个工厂类,工厂类只返回对应的子类的对象。再有这个对象调用其下的方法。
Form1.cs:
using System; using System.Windows.Forms; namespace strategy { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { comboBox1.Items.Add("8折"); comboBox1.Items.Add("6折"); comboBox1.Items.Add("4折"); } /// <summary> /// 单价 /// </summary> public double price; /// <summary> /// 数量 /// </summary> public double number; /// <summary> /// 总价钱 /// </summary> public double total; /// <summary> /// 确定按钮点击事件 /// </summary> private void button1_Click(object sender, EventArgs e) { Total tooo = null; price = Convert.ToDouble(textBox1.Text); number = Convert.ToDouble(textBox2.Text); int count = comboBox1.SelectedIndex; Reckon reckon = new Reckon(); tooo = reckon.PutOut(count); total = tooo.getResult(price, number); richTextBox1.Text = Convert.ToString(total); label5.Text = Convert.ToString(total); } /// <summary> /// 重置按钮点击事件 /// </summary> private void button2_Click(object sender, EventArgs e) { textBox1.Clear(); textBox2.Clear(); richTextBox1.Clear(); label5.Text = ""; } } }
抽象类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public abstract class Total { public abstract double getResult(double price, double number); } }
工厂类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace strategy { /// <summary> /// 计算类 /// </summary> public class Reckon { public Total tooo = null; /// <summary> /// 总价钱 /// </summary> public double total; public Total PutOut(int count) { switch (count) { case 2: tooo = new Four(); break; case 1: tooo = new Six() ; break; case 0: tooo = new Eight(); break; default: tooo = new Normal(); break; } return tooo; } } }
子类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Four:Total { public override double getResult(double price, double number) { double total; total = price * number * 0.8; return total; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Six:Total { public override double getResult(double price, double number) { double total; total = price * number * 0.6; return total; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Eight:Total { public override double getResult(double price, double number) { double total; total = price * number * 0.8; return total; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Normal:Total { public override double getResult(double price, double number) { double total; total = price * number; return total; } } }
以上是用简单工厂模式来实现的这个例子。
这里介绍的是策略模式,所以使用简单工厂模式实现的不是我们想要的,因为每一次我修改结构,添加新的打折策略都需要修改工厂类和添加新的算法类。
策略模式:定义了算法家族,分别封装起来。让其之间可以互相替换,此模式让算法的变化,不会影响到使用这个算法的用户。以上是官方给的说法。
策略模式和简单工厂模式区别:
简单工厂模式是直接返回你需要的算法的对象。再使用对象进行操作
策略模式加了一层,调用策略类,传你需要的算法类对象,直接返回你需要的到的数值。
上代码:
Form1.cs
using System; using System.Windows.Forms; namespace strategy { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { comboBox1.Items.Add("8折"); comboBox1.Items.Add("6折"); comboBox1.Items.Add("4折"); } /// <summary> /// 单价 /// </summary> public double price; /// <summary> /// 数量 /// </summary> public double number; /// <summary> /// 总价钱 /// </summary> public double total; public CeLue celue; /// <summary> /// 确定按钮点击事件 /// </summary> private void button1_Click(object sender, EventArgs e) { Total tooo = null; if (textBox1.Text == "") { return; } price = Convert.ToDouble(textBox1.Text); number = Convert.ToDouble(textBox2.Text); int count = comboBox1.SelectedIndex; switch (count) { case 2: celue = new CeLue(new Four(),price,number); break; case 1: celue = new CeLue(new Six(),price,number); break; case 0: celue = new CeLue(new Eight(), price, number); break; default: celue = new CeLue(new Normal(), price, number); break; } // 调用 total = celue.getCeLue(); //Reckon reckon = new Reckon(); //tooo = reckon.PutOut(count); //total = tooo.getResult(price, number); richTextBox1.Text = Convert.ToString(total); label5.Text = Convert.ToString(total); } /// <summary> /// 重置按钮点击事件 /// </summary> private void button2_Click(object sender, EventArgs e) { textBox1.Clear(); textBox2.Clear(); richTextBox1.Clear(); label5.Text = ""; } } }
CeLue.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { /// <summary> /// 策略类 /// </summary> public class CeLue { public Total total; public double pri; public double num; public double to; public CeLue(Total tooo,double price,double number) { total = tooo; pri = price; num = number; } public double getCeLue() { to = total.getResult(pri, num); return to; } } }
基类:Total.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public abstract class Total { public abstract double getResult(double price, double number); } }
算法类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Six:Total { public override double getResult(double price, double number) { double total; total = price * number * 0.6; return total; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Four:Total { public override double getResult(double price, double number) { double total; total = price * number * 0.8; return total; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Eight:Total { public override double getResult(double price, double number) { double total; total = price * number * 0.8; return total; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { public class Normal:Total { public override double getResult(double price, double number) { double total; total = price * number; return total; } } }
对比一下简单工厂模式和策略模式发现,单纯的使用策略模式,对算法的封装确实更科学了一些。但是在调用的时候,我们又回到了之前的模样,在客户端判断到底是哪一个算法,这个时候,我们可以将策略模式与简单工厂模式结合使用。
将判断算法部分放到策略类的构造函数中。代码如下所示:
Form1.cs
using System; using System.Windows.Forms; namespace strategy { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { comboBox1.Items.Add("8折"); comboBox1.Items.Add("6折"); comboBox1.Items.Add("4折"); } /// <summary> /// 单价 /// </summary> public double price; /// <summary> /// 数量 /// </summary> public double number; /// <summary> /// 总价钱 /// </summary> public double total; public CeLue celue; /// <summary> /// 确定按钮点击事件 /// </summary> private void button1_Click(object sender, EventArgs e) { Total tooo = null; if (textBox1.Text == "") { return; } price = Convert.ToDouble(textBox1.Text); number = Convert.ToDouble(textBox2.Text); int count = comboBox1.SelectedIndex; CeLue celue = new CeLue(price, number, count); // 调用 total = celue.getCeLue(); //Reckon reckon = new Reckon(); //tooo = reckon.PutOut(count); //total = tooo.getResult(price, number); richTextBox1.Text = Convert.ToString(total); label5.Text = Convert.ToString(total); } /// <summary> /// 重置按钮点击事件 /// </summary> private void button2_Click(object sender, EventArgs e) { textBox1.Clear(); textBox2.Clear(); richTextBox1.Clear(); label5.Text = ""; } } }
策略模式和简单工厂模式结合:
CeLue.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace strategy { /// <summary> /// 策略类 /// </summary> public class CeLue { public Total total; public double pri; public double num; public double to; public CeLue(double price,double number,int count) { pri = price; num = number; switch (count) { case 2: total = new Four(); break; case 1: total = new Six(); break; case 0: total = new Eight(); break; default: total = new Normal(); break; } } public double getCeLue() { to = total.getResult(pri, num); return to; } } }
其余代码没有改变。
这个就是策略模式,按照官方的说法就是算法的家族。让算法的变化,不会影响到使用算法的用户。

