C# 设计模式一一策略模式

一、定义

       它定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。

二、结构图

       策略模式是对算法的包装,是把使用算法的责任和算法本身分割开,委派给不同的对象负责。策略模式通常把一系列的算法包装到一系列的策略类里面。用一句话慨括策略模式就是——“将每个算法封装到不同的策略类中,使得它们可以互换”。

下面是策略模式的结构图:

该模式涉及到三个角色:

  • 环境角色(Context):持有一个Strategy类的引用
  • 抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类来实现。此角色给出所有具体策略类所需实现的接口。
  • 具体策略角色(ConcreteStrategy):包装了相关算法或行为。

三、实现

实现如下收费应用:

(1) 简单工厂模式实现

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 = 0;

	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;
	private double moneyReturn = 0;
	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;
	}
}

构造简单工厂模式:负责生产对象的一个类,本例负责生产收费方式的一个类

/// <summary>
/// 简单工厂模式:负责生产对象的一个类,本例负责生产收费方式的一个类
/// </summary>
class CashFactory
{
	public static CashSuper createCashAccept( string type )
	{
		CashSuper cs = null;
		switch( type )
		{
			case "正常收费":
				cs = new CashNormal( );
				break;
			case "满300返100":
				cs = new CashReturn( "300","100" );
				break;
			case "打8折":
				cs = new CashRebate( "0.8" );
				break;
		}
		return cs;
	}
}

界面显示及调用:

private void Form1_Load( object sender, EventArgs e )
{
	cbxType.Items.AddRange( new object[] {"正常收费","打八折","打九折","满300返100"});
	cbxType.SelectedIndex = 0;
}
double total = 0;
private void btnOk_Click( object sender, EventArgs e )
{
    //简单工厂模式需要让客户端认识CashSuper类和CashFactory类
	CashSuper csuper = CashFactory.createCashAccept( cbxType.SelectedItem.ToString());
	double totalPrice = 0;
	totalPrice = csuper.acceptCash( Convert.ToDouble(textPrice.Text) * Convert.ToDouble(textNum.Text));
	total += totalPrice;
	lbxList.Items.Add( "单价:" + textPrice.Text + "数量:" + textNum.Text + " "
		+ cbxType.SelectedItem + "合计:" + totalPrice.ToString());
	lblResult.Text = total.ToString( );
}

(2) 策略模式实现

  • 上述CashSuper:这是一个抽象角色,通常由一个接口或抽象类来实现。此角色给出所有具体策略类所需实现的接口。
  • 如下CashContext类:环境角色(Context):持有一个Strategy类的引用
/// <summary>
/// 策略模式
/// </summary>
class CashContext
{
	//声明一个CashSuper对象
	private CashSuper cs;
	public CashContext( CashSuper csuper ) //通过构造方法,传入具体的收费策略
	{
		this.cs = csuper;
	}

	public double GetResult( double money )
	{
		return cs.acceptCash( money ); //根据收费策略的不同获取收费结果
	}
}
  • 上述CashSuper的子类:具体策略角色(ConcreteStrategy):包装了相关算法或行为。

策略模式调用:

double total = 0;
private void btnOk_Click( object sender, EventArgs e )
{
       //策略模式需要传入引用Strategy类的引用(此处引用的是各CashSuper对象,由各子类传入)
	CashContext cc = null;
	string type = cbxType.SelectedItem.ToString( );
	switch( type )
	{
		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 totalPrice = 0;
	//
	totalPrice = cc.GetResult( Convert.ToDouble( textPrice.Text ) * Convert.ToDouble( textNum.Text ) );
	total += totalPrice;
	lbxList.Items.Add( "单价:" + textPrice.Text + "数量:" + textNum.Text + " "
		+ cbxType.SelectedItem + "合计:" + totalPrice.ToString( ) );
	lblResult.Text = total.ToString( );
}

(3) 策略模式+简单工厂模式实现

       为了把策略模式中的判断过程从客户端移走(即从btnOk_Click函数中移走),需要利用简单工厂模式将负责生产收费对象整合到CashContext类中去,如下所示:

/// <summary>
/// 策略模式+简单工厂模式
/// </summary>
class CashContext
{
	//声明一个CashSuper对象
	private CashSuper cs;
	public CashContext( string type ) //傳入收費類型
	{
		switch( type )
		{
			case "正常收费":
				cs = new CashNormal( );
				break;
			case "满300返100":
				cs = new CashReturn( "300", "100" );
				break;
			case "打8折":
				cs = new CashRebate( "0.8" );
				break;
		}
	}

	public double GetResult( double money )
	{
		return cs.acceptCash( money ); //根据收费策略的不同获取收费结果
	}
}

       这样,客户端调用只要认识CashContext类就可以了,耦合度相比简单工厂模式就大大降低了。(简单工厂模式需要让客户端认识CashSuper类和CashFactory类)。

double total = 0;
private void btnOk_Click( object sender, EventArgs e )
{
	double totalPrice = 0;
	//客户端调用只要认识CashContext类就可以了,耦合度相比简单工厂模式就大大降低了
	CashContext csuper = new CashContext(cbxType.SelectedItem.ToString());
	totalPrice = csuper.GetResult( Convert.ToDouble( textPrice.Text ) * Convert.ToDouble( textNum.Text ) );
	total += totalPrice;
	lbxList.Items.Add( "单价:" + textPrice.Text + "数量:" + textNum.Text + " "
		+ cbxType.SelectedItem + "合计:" + totalPrice.ToString( ) );
	lblResult.Text = total.ToString( );
}

四、策略者模式的优缺点

优点:

  • 策略类之间可以自由切换。由于策略类都实现同一个接口,所以使它们之间可以自由切换。
  • 易于扩展。增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码。

缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

五、策略者模式的适用场景

 在下面的情况下可以考虑使用策略模式:

       一个系统需要动态地在几种算法中选择一种的情况下。那么这些算法可以包装到一个个具体的算法类里面,并为这些具体的算法类提供一个统一的接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值