策略模式及简单Java案例代码实现

说明本文是《大话设计模式》的学习记录及结合网上相关信息编写,原书代码例子采用C#编写,本文采用Java稍加改写。如有不当,欢迎指正,共同进步。


1.策略模式概述:

     策略模式(Pattern:Strategy)属于行为型模型,是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。


2.策略模式包含的角色及其职责:

(1)抽象策略角色[Strategy]:策略类,定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,
Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
(2)具体策略类[ConcreteStrategy]:实现了Strategy定义的接口,包装了相关的算法和行为,提供具体的算法实现。
(3)上下文角色[Context]:持有一个策略类的引用,最终给客户端调用。
①需要使用ConcreteStrategy提供的算法。
②内部维护一个Strategy的实例。
③负责动态设置运行时Strategy具体的实现算法。
④负责跟Strategy之间的交互和数据传递。



3.策略模式的设计原则及UML类图:

(1)设计原则:变化的抽象成接口,面向接口编程而不是面向实现编程。

(2)UML类图:



4.Java案例代码:

(1)抽象策略角色:

package StrategyPattern;

/**
 * 现金收费抽象类
 */
public abstract class CashSuper {
	//现金收取超类的抽象方法,收取现金,参数为原价,返回为当前价
	public abstract double acceptCash(double money);
}

(2)具体策略类:

package StrategyPattern;

/**
 * 正常收费子类,继承现金收费抽象类
 */
public class CashNormal extends CashSuper {

	@Override
	public double acceptCash(double money) {
		//正常收费,返回原价
		return money;
	}

}

package StrategyPattern;

/**
 * 打折收费子类,继承现金收费抽象类
 */
public class CashRebate extends CashSuper {
	private double moneyRebate = 1;

	public CashRebate(String moneyRebate) {
		//打折收费,初始化时,必须输入折扣率,如八折,就是0.8
		this.moneyRebate = Double.valueOf(moneyRebate);
	}

	@Override
	public double acceptCash(double money) {
		return money*moneyRebate;
	}

}

package StrategyPattern;

/**
 * 返利收费子类,继承现金收费抽象类
 */
public class CashReturn extends CashSuper {
	private double moneyCondition = 0; //返利条件
	private double moneyReturn = 0; //返利值
	//返利收费,初始化时必须要输入返利条件和返利值,比如满300返100
	public CashReturn(String moneyCondition, String  moneyReturn) {
		this.moneyCondition = Double.valueOf(moneyCondition);
		this.moneyReturn = Double.valueOf(moneyReturn);
	}

	@Override
	public double acceptCash(double money) {
		if (money>=moneyCondition) {
			//若大于返利条件,则需要减去返利值
			return money-Math.floor(money/moneyCondition)*moneyReturn;
		}
		return money;
	}
	
	
}

(3)上下文角色:策略与简单工厂结合

package StrategyPattern;
/**
 * CashContext类
 * 策略与简单工厂结合
 */
public class CashContext {
	private CashSuper cs; //声明一个CashSuper对象
	
	//通过构造方法,传入收费策略再生产具体的收费策略类
	public CashContext(String rates) {
		switch (rates) {
		case "正常收费":
			cs = new CashNormal();
			break;
			
		case "满1000减100":
			cs = new CashReturn("1000", "100");
			break;
			
		case "打8折":
			cs = new CashRebate("0.8");
			break;

		default:
			break;
		}
	}
	//根据收费策略的不同,获得计算结果
	public double getResult(double money) {
		return cs.acceptCash(money);
	}
	
}

(4)客户端测试代码:

package StrategyPattern;

/**
 * 客户端代码
 */
public class Test1 {
	public static void main(String[] args) {
		int number = 300; //商品数量
		int price = 10; //商品单价
		Normal(number, price); //正常收费
		Rebate(number, price); //打折收费
		Return(number, price); //满减收费
	}
	public static void Normal(int number, int price) {
		CashContext ccNormal = new CashContext("正常收费");
		double result = ccNormal.getResult(number*price);
		System.out.println("正常收费:商品单价为:" + price + "元,商品数量为:" + number + "件,应付款:" + result + "元。");
	}
	
	public static void Rebate(int number, int price) {
		CashContext ccRebate = new CashContext("打8折");
		double result = ccRebate.getResult(number*price);
		System.out.println("打折收费:商品单价为:" + price + "元,商品数量为:" + number + "件,应付款:" + result + "元。");
	}
	
	public static void Return(int number, int price) {
		CashContext ccReturn = new CashContext("满1000减100");
		double result = ccReturn.getResult(number*price);
		System.out.println("打折收费:商品单价为:" + price + "元,商品数量为:" + number + "件,应付款:" + result + "元。");
	}

}

(5)客户端测试代码打印结果:



5.策略模式的优缺点及使用场景:

(1)优点:

       ①策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。

       ②策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。

      ③使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。


(2)缺点:

      ①客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。

       ②策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。


(3)应用场景:

       ①多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
       ②需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
       ③对客户隐藏具体策略(算法)的实现细节,彼此完全独立。

发布了17 篇原创文章 · 获赞 27 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览