策略模式的定义:定义一系列的算法,将他们一个个的封装起来,并是他们可以相互替换,让算法独立于客户端而独立变化。
UML类图:在这个类图包含三个类别:①抽象策略类:通常由接口或抽象类实现,定义所有支持算法的公共接口。②具体策略类:实现抽象策略类,在重写方法中写入算法或行为。③环境类(上下文):决定用哪一个具体抽象类的算法。
案例:商场收银系统
输入商品单价和数量,返回总金额,当商场加入打折、满减活动时,系统执行不同的算法,但是相同的都是输入单价和数量,返回总金额,所以可以在抽象类或接口中写一个公共方法。
抽象策略类:
public interface CalPriceSuper {
public double calPrice(double money);
}
具体策略类:①正常收费。②打折。③满减
/**
* 正常收费
*/
public class NormalPrice implements CalPriceSuper{
@Override
public double calPrice(double money) {
return money;
}
}
/**
* 打折
*/
public class DiscountPrice implements CalPriceSuper{
public double discount;
public DiscountPrice(double discount) {
this.discount = discount;
}
@Override
public double calPrice(double money) {
return money * discount;
}
}
/**
* 满减
*/
public class PlusPirce implements CalPriceSuper{
public double mPrice;
public double jPrice;
public PlusPirce(double mPrice, double jPrice) {
super();
this.mPrice = mPrice;
this.jPrice = jPrice;
}
@Override
public double calPrice(double money) {
if(money >= mPrice){
return money-(money/mPrice)*jPrice;
}
return money;
}
}
上下文(环境)类:
/**
* 上下文:决定用哪一个具体实现类,将具体实现类与客户隔离
*/
public class CashContext {
CalPriceSuper calPriceSuper;
public CashContext(CalPriceSuper calPriceSuper){
this.calPriceSuper = calPriceSuper;
}
public double getResult(double money){
return calPriceSuper.calPrice(money);
}
}
客户端调用方法:在客户端判断使用哪一个算法。
/**
* 客户端调用策略类方法
*/
public static void main(String[] args) {
CashContext context = new CashContext(new DiscountPrice(0.6));
double result = context.getResult(100.0);
}
策略类和简单工厂的融合:
/**
* 借鉴简单工厂的思想,在上下文中,通过传入类型来创建具体策略类
*/
public class CashContext {
CalPriceSuper calPriceSuper;
public CashContext(String type){
if("正常收费".equals(type)){
this.calPriceSuper = new NormalPrice();
}else if("0.6折".equals(type)){
this.calPriceSuper = new DiscountPrice(0.6);
}else if("满300减150".equals(type)){
this.calPriceSuper = new PlusPirce(300.0, 150.0);
}else if("满100得10点积分".equals(type)){
this.calPriceSuper = new PlusPirce(100, 10);
}
}
public double getResult(double money){
return calPriceSuper.calPrice(money);
}
}
客户端调用方法:将具体策略类与客户完全隔离,只需要用到CashContext类就可以实现,耦合度降低。
/**
* 客户端调用策略类方法
*/
public static void main(String[] args) {
CashContext context = new CashContext("0.6折");
double result = context.getResult(100.0);
}
策略模式的优点:
①可以随意切换算法。②减少算法类和使用算法类之间的耦合度。③简化单元测试。④可扩展
策略模式的缺点:
①在context对象中还是会有if-else或switch-case判断,如果需要修改策略类的type,每次都需要修改type代码。②客户端必须知道所有的策略类并需要判断用哪个策略类(简单工厂模式可以解决此问题)。③每个策略类都单独封装成类,策略类数量太多。
抽象工厂模式可以解决switch或if判断的问题。
JDK类库中的策略模式
java.util.Comparator#compare(T o1,T o2)
传递传入不同的参数可以实现不同的算法:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1>o2?1:o1==o2?0:-1;
}
};
System.out.println(comparator.compare(2, 1));
javax.servlet.http.HttpServlet
HttpServlet中的doGet、doPost、service方法都可以通过传递不同的request和response来实现不同的业务逻辑。
javax.servlet.Filter#doFilter
Filter可以通过传递request、response、chain来实现不同的业务逻辑。