前言:短暂的春节过去了,我又要开始新的学习了。虽然寒假短暂,但说实话在家里呆着不知道干什么的滋味的确有些不适应:每天只能抽出不到一个小时的时间背单词,背完之后又没有其他学习资料(计算机类学习)来换换思维。
长话短说,既然开始了学习,那么我们就步入正题吧:今天要总结的是自己假期前看到的设计模式:1-2章。
说到设计模式之前,我们不可避免的还是要提到面向对象。为什么我们在编写代码时,要使用面向对象呢?换而言之,面向对象的优点是什么呢?面向对象的优点:降低程序的耦合度,使程序更加灵活、易于修改与复用。而如何体现这种优点呢:通过设计模式来体现。
第一章:简单工厂模式
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
1.简单工厂模式包含如下三种结构:
-工厂类:负责实现具体产品类中的实例。工厂类可以被外界直接调用,创建所需的产品对象。
-抽象产品类:是所有具体产品类的父类,负责描述所有实例所共有的接口
-具体产品类:继承于抽象产品类
---以上概念摘自Bobby0322的博客,感谢巨人
简单来讲,就是工厂类实例化抽象工厂类中的具体产品类。整个过程大致可以由三部分组成:第一部分是工厂类,工厂类实例化各个具体产品类,可以使用他们的计算方法,并方便主程序对其直接调用;第二部分是抽象产品类,通过抽象方法定义,以方便其下的子类重写方法;第三部分就是具体产品类,这些类使用override重写父类方法。
2.简单工厂模式结构图:
第二章:策略模式
策略模式所体现的思想是具有类似功能的算法可以进行相互替换。
1.策略模式(Strategy)结构图:
2.策略模式的优点:策略模式可以灵活的添加或改变新的策略,对于代码的封装性、复用性都有很大的体现。
以上两种设计模式都充分使用到了继承与封装这两个概念。
例子:超市会不定期举行促销活动,假设超市一共有三种结算方式:正常收费、满300减100、打8折这三种,如何用简单工厂与策略模式设计一个结算界面呢?
主界面:
父类:收费
//抽象收费父类
abstract class CashSuper
{
public abstract double acceptCash(double money);//抽象父类方法
}
子类:正常收费
//正常收费子类
class CashNormal:CashSuper
{
public override double acceptCash(double money)//重写父类方法
{
return money;
}
}
子类:满减
//满减
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 CashRebate : CashSuper
{
public double moneyRebate = 1d;
public CashRebate(string moneyRebate)//构造方法
{
this.moneyRebate = Convert.ToDouble(moneyRebate);
}
public override double acceptCash(double money)//重写父类方法
{
return money * moneyRebate;
}
}
简单工厂+Context上下文(关键点)
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 GerResult(double money)//输出结果到主程序
{
return cs.acceptCash(money);
}
}
主程序:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
double total = 0.0d;//定义初始总价为0
private void btnOK_Click(object sender, EventArgs e)
{
CashContext csuper = new CashContext(cmbType.SelectedItem.ToString());//实例化context上下文类
double totalPrices = 0d;//定义购物总价
totalPrices = csuper.GerResult(Convert.ToDouble(txtPrice.Text)*Convert.ToDouble(txtNum.Text));//计算价格,此步骤需要跳转至context类得到金钱的值
total = total + totalPrices;
cbxType.Items.Add("单价:" + txtPrice.Text + "数量:" + txtNum.Text + "" + cmbType.SelectedItem + "合计:" + totalPrices.ToString());//显示
lblResult.Text = total.ToString();
}
private void Form1_Load(object sender, EventArgs e)
{
cmbType.Items.Add("正常收费");
cmbType.Items.Add("满300减100");
cmbType.Items.Add("打8折");
}
}
代码运行步骤:(蓝色代表类,红色代表变量,绿色代表方法)
-运行,输入单价为100、数量为1、计算方式为8折,之后点击确定。
-首先实例化CashContext类,在CashContext中实例化收费父类cs。(在之后对收费类的调用其实都是通过父类调用)
-判断计算方式为打8折,之后通过构造函数的方式将“0.8”赋值给CashRebate子类中的moneyRebate
-然后回到主程序,变量totalPrices计算,并通过构造函数将输入的“100”赋值给CashContext类中的money变量,CashContext再通过CashSuper父类调用Rebate子类,重写父类方法acceptCash,进行money*moneyRebate的运算,并通过GerResult方法返回结果给主程序
-主程序输出
输出结果:
这个例子所体现的简单工厂策略不用多说,我们来讲一下这个例子有关策略模式的内容:
每当超市不定期举行活动,如从正常收费变为打八折,这时我们只需要更改相应的策略即可;而若是超市增加了“打75折”这样的促销活动时,也不必担心,我们只需要新写一个子类,在Context中增加新选项,并在主程序中的下拉框中写入一个新的即可,而不需要修改任何计算公式。因为数值类的计算公式没有被写死,而是通过传值的方式进行计算。这种策咯模式减少了对代码的修改,也提高了代码的复用性。