在博客文章中,我们提到的简单工厂模式。然而,GoF摘要23设计模式,而不是她的影子,严厉格感,简单工厂模式是不是一种设计模式,合设计模式的开放—封闭原则,即软件实体如类、模块等应该能够扩展,可是不可改动。对于设计模式的设计原则,将在下一篇博文中介绍。这里我们先来看一个样例:
周所周知,超市收银系统都具有计费功能,那么要你做一个可以依据输入的商品单位价格和数量,以及计费方式进行计算的模块,你怎样做?计费方式也就是打不打折,有没有返利优惠等等。那么我们先用简单工厂模式去实现一下。
简单工厂实现
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; namespace 商场收银软件 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } double total = 0.0d; private void textBox1_TextChanged(object sender, EventArgs e) { } private void label5_Click(object sender, EventArgs e) { } private void Form1_Load(object sender, EventArgs e) { cbxType.Items.AddRange(new object[] { "正常收费", "满300返100", "打8折" }); cbxType .SelectedIndex =0; } private void buttonOK_Click(object sender, EventArgs e) { CashSuper csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString()); double totalPrices = 0d; totalPrices = csuper.acceptCash(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); total = total + totalPrices; lbxList.Items.Add("单位价格:" + txtPrice.Text + "数量:" + txtNum.Text +"计费方式:"+ cbxType.SelectedItem + "合计:" + totalPrices.ToString()); lblResult.Text = total.ToString(); } private void button2_Click(object sender, EventArgs e) { txtNum.Text = ""; txtPrice.Text = ""; lbxList.Items.Clear(); lblResult.Text = "0.00"; } } //现金收费抽象类 abstract class CashSuper { public abstract double acceptCash(double money); } //正常收费子类 class CashNormal : CashSuper { public override double acceptCash(double money) { return money; } } //打折收费子类 class CashRebate : CashSuper { private double moneyRebate = 1d; 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; 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; } } //现金收费工厂类 class CashFactory { public static CashSuper createCashAccept(string type) { CashSuper cs = null; switch (type) { case "正常收费": cs = new CashNormal(); break; case "满300返100": CashReturn cr1 = new CashReturn("300", "100"); cs = cr1; break; case "打8折": CashRebate cr2 = new CashRebate("0.8"); cs = cr2; break; } return cs; } } }
我们看到,这样的方案的特点就是将计费方式的实例化放到了工厂里。从而在须要加入新的计费方式的时候,仅仅需在工厂里加一下条件。完了再设计一个对应的类就可以。
可是这样做相同也破坏了开放—封闭原则,每一次的扩展都要大动干戈,实在是不好,不好。面对算法的时常变动。怎样应对?以下我们用还有一种方式试试:
策略模式实现
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; namespace 商场收银软件 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } double total = 0.0d; private void textBox1_TextChanged(object sender, EventArgs e) { } private void label5_Click(object sender, EventArgs e) { } private void Form1_Load(object sender, EventArgs e) { cbxType.Items.AddRange(new object[] { "正常收费", "满300返100", "打8折" }); cbxType .SelectedIndex =0; } private void buttonOK_Click(object sender, EventArgs e) { //简单工厂模式的client代码 //CashSuper csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString()); //double totalPrices = 0d; //totalPrices = csuper.acceptCash(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); //total = total + totalPrices; //lbxList.Items.Add("单位价格:" + txtPrice.Text + "数量:" + txtNum.Text +"计费方式:"+ cbxType.SelectedItem + "合计:" + totalPrices.ToString()); //lblResult.Text = total.ToString(); //策略模式的client代码 CashContext cc = null; switch (cbxType.SelectedItem.ToString()) { case "正常收费": cc = new CashContext(new CashNormal()); break; case "满300返100": cc = new CashContext(new CashReturn("300", "100")); break; case "打8折": cc = new CashContext(new CashRebate("0.8")); break; } double totalPrices = 0d; totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text)); total = total + totalPrices; lbxList.Items.Add("单位价格:" + txtPrice.Text + "数量:" + txtNum.Text + "计费方式:" + cbxType.SelectedItem + "合计:" + totalPrices.ToString()); lblResult.Text = total.ToString(); } private void button2_Click(object sender, EventArgs e) { txtNum.Text = ""; txtPrice.Text = ""; lbxList.Items.Clear(); lblResult.Text = "0.00"; } } //现金收费抽象类 abstract class CashSuper { public abstract double acceptCash(double money); } //正常收费子类 class CashNormal : CashSuper { public override double acceptCash(double money) { return money; } } //打折收费子类 class CashRebate : CashSuper { private double moneyRebate = 1d; 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; 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; } } //现金收费工厂类 //class CashFactory //{ // public static CashSuper createCashAccept(string type) // { // CashSuper cs = null; // switch (type) // { // case "正常收费": // cs = new CashNormal(); // break; // case "满300返100": // CashReturn cr1 = new CashReturn("300", "100"); // cs = cr1; // break; // case "打8折": // CashRebate cr2 = new CashRebate("0.8"); // cs = cr2; // break; // } // return cs; // } //} //CashContext类 class CashContext { private CashSuper cs; public CashContext(CashSuper csuper) { this.cs = csuper; } public double GetResult(double money) { return cs.acceptCash(money); } } }
对照两个方案,我们能够看到不同之处就是策略模式将工厂类撤了。取而代之的是CashContext类,然而又将实现哪一个算法的推断交给了client,这样client承担的责任又大了,不好。不好……
怎么办?要不将简单工厂和策略模式混搭?试试看。对于他们的结合。仅仅需将CashContext类改造一下就可以,例如以下:
//改造后的CashContext类 class CashContext { CashSuper cs = null ; public CashContext(string type) { switch (type) { case "正常收费": CashNormal cs0 = new CashNormal(); cs = cs0; break; case "满300返100": CashReturn cr1 = new CashReturn("300", "100"); cs = cr1; break; case "打8折": CashRebate cr2 = new CashRebate("0.8"); cs = cr2; break; } } public double GetResult(double money) { return cs.acceptCash(money); } }这样一来,client的代码就要简单的多了,简单工厂模式须要让client和两个类CashSuper和CashFactory打交道,而策略模式与简单工厂结合后的使用方法,client就仅仅需和CashContext打交道就可完毕对应的功能,减少了耦合性。
我们再回过头去看策略模式的定义:
策略模式:定义了算法家族,分别封装起来,让它们之间能够相互替代,此模式让算法的变化,不会影响到使用此算法的客户。
版权声明:本文博主原创文章。博客,未经同意不得转载。
本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4912388.html,如需转载请自行联系原作者