设计模式中常常会提到一个设计原则,那就是开放-封闭原则,《大话设计模式》中设计了六种原则,分别为单一职责原则、开放-封闭原则、依赖倒转原则、里氏代换原则、迪米特法则、合成/聚合复用原则。以后的博客中会一一涉及,现在就不一一介绍了。
本次原则开放-封闭。
所谓开放封闭原则就是软件实体应该对扩展开发,而对修改封闭。开放封闭原则是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化,降低耦合,而开放封闭原则正是对这一目标的最直接体现。
我们说什么样的代码是好的,很多人都会认为增加功能或者别的什么,代码的修改量越少,这样的代码越是优秀。所以关闭修改,开放扩展在设计模式中几乎每一个模式都在贯穿着。看下面讲的这个就有。
我们以现实生活的例子为例,商场促销,手段各部相同,比如打折销售、买一赠一、捆绑销售、还有就是量多减价等等。这称之为商场销售之道,也是一种策略。
先提出这个概念,我们在慢慢讲解:
Ø 详解策略模式
策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
u 结构如图:
u 角色
三个角色:
l Context(环境类)
l Strategy(抽象策略类)
l ConcreteStrategy(具体策略类)
u 实现
abstract class AbstractStrategy
{
public abstract void Algorithm(); //声明抽象算法
}
class ConcreteStrategyA : AbstractStrategy
{
//算法的具体实现
public override void Algorithm()
{
//算法A
}
}
class ConcreteStrategyB : AbstractStrategy
{
//算法的具体实现
public override void Algorithm()
{
//算法B
}
}
……
class Context
{
Strategy strategy;
Public Context (Strategy strategy) //初始化时,传入具体的策略对象
{
this.strategy = strategy;
}
//根据具体的策略对象,调用策略类中的算法
public void ContextInterface()
{
strategy.AlgorithmInterface();
}
}
u 对比
客户端中策略模式(含简单工厂)与简单工厂模式的不同点在于:
² 简单工厂模式:
CashSuper csuper=CashFactory.createCashAccept(cbxType.SelectedItem.ToString());
…=csuper.GetResult(…)
² 策略模式(含简单工厂):
CashContext csuper=new CashContext(cbxTye.SelectedItem.ToString());
…=csuper.GetResult(…);
简单工厂:可以看出简单工厂的缺点非常明显,那就是其客户端的某个改动直接影响的就是工厂类,这样使得程序的修改太大,同时也违背了开放-封闭原则。
优点就是可以将实例化具体策略过程由客户端转移到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 "打八折":
CashRebate cr2 = new CashRebate("0.8");
cs = cr2;
break;
}
}
public double GetResult(double money)
{
return cs.acceptCash(money);
}
策略模式与简单工厂的集合使得开放-封闭原则得到很好的应用和实现。
客户端程序
double total = 0.0d;
private void button1_Click(object sender, EventArgs e)
{
CashContextcsuper = new CashContext(cbxtype.SelectedItem.ToString());
double totalPrices = 0d;
totalPrices =csuper .GetResult (Convert.ToDouble (txtPrice.Text ))* (Convert.ToDouble(txtNum .Text));
total=total+totalPrices ;
}
可以看出此时的客户端只需要认识CashContext类即可,只需要在客户端实例化其CashContext的对象即可。
此时不免想起了工厂方法,工厂方法里为了避免大部分代码的修改,采用是把简单工厂的内部逻辑判断移到了客户端代码,使得只需要更改相应的客户端就可以了。
计算器实现客户端的一句代码。
IFactory operFactory=new AddFactory();
这样只需修改AddFactory便可以实现不同的运算。减少了代码的修改,开放了扩展。