首先我们了解一下策略模式的定义:策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。通俗来说就是定义了一堆算法族,客户需要什么算法直接使用相应的算法即可。
接下来,通过举个例子来加深对策略模式的理解。举的例子是商场打折扣的例子,一般逛商场都会看到好多种折扣,七五折、八八折什么的。那么如果将它们放在一个折扣类实现的话,等到有新的折扣的时候,便会需要更改折扣类的代码,耦合程度过高。所以我们可以考虑将每个折扣分别当作一个类,即每个类都具体到哪种折扣,并且实现折扣接口;这样的话,如果需要添加什么折扣,只需要添加一个具体折扣类即可。而客户端与折扣类并不直接调用,而是通过一个策略类,详尽各种策略。这样的话客户端与折扣之间的关系,只需要在客户端切换相应的折扣即可,做到了客户端与折扣的完全分离。
1.首先建立一个折扣接口,这个接口只有一个getDiscount方法用来供策略类获取折扣的:
public interface DiscountStrategy
{
// 定义一个用于计算打折价的方法
double getDiscount(double originPrice);
}
2.两个折扣实现类:
// 实现DiscountStrategy接口,实现对VIP打折的算法
public class VipDiscount
implements DiscountStrategy
{
// 重写getDiscount()方法,提供VIP打折算法
public double getDiscount(double originPrice)
{
System.out.println("使用VIP折扣...");
return originPrice * 0.5;
}
}
public class OldDiscount
implements DiscountStrategy
{
// 重写getDiscount()方法,提供旧书打折算法
public double getDiscount(double originPrice)
{
System.out.println("使用旧书折扣...");
return originPrice * 0.7;
}
}
3.编写一个策略类,作为客户端对折扣的一个选择策略,以下提供了一个changeDiscount()方法就是为了提供客户端进行折扣策略的切换的。另外这里使用的是一个DiscountStrategy对象,针对接口编程,利用了组合对象。
public class DiscountContext
{
// 组合一个DiscountStrategy对象
private DiscountStrategy strategy;
// 构造器,传入一个DiscountStrategy对象
public DiscountContext(DiscountStrategy strategy)
{
this.strategy = strategy;
}
// 根据实际所使用的DiscountStrategy对象得到折扣价
public double getDiscountPrice(double price)
{
// 如果strategy为null,系统自动选择OldDiscount类
if (strategy == null)
{
strategy = new OldDiscount();
}
return this.strategy.getDiscount(price);
}
// 提供切换算法的方法
public void changeDiscount(DiscountStrategy strategy)
{
this.strategy = strategy;
}
}
4.客户端编程
public class StrategyTest
{
public static void main(String[] args)
{
// 客户端没有选择打折策略类
DiscountContext dc = new DiscountContext(null);
double price1 = 79;
// 使用默认的打折策略
System.out.println("79元的书默认打折后的价格是:"
+ dc.getDiscountPrice(price1));
// 客户端选择合适的VIP打折策略
dc.changeDiscount(new VipDiscount());
double price2 = 89;
// 使用VIP打折得到打折价格
System.out.println("89元的书对VIP用户的价格是:"
+ dc.getDiscountPrice(price2));
}
}
以上例子可以看出,策略模式,使算法族是独立存在的,而客户端需要采用什么样的策略,只需要通过策略类选取相应的算法即可。虽然策略模式使得客户端与相应的算法类分离,使客户端与不同折扣策略中自如切换,但是客户端与不同的策略类耦合。
Spring中的Resource接口就是一种典型的策略模式,它通过配置文件的形式,将Resource和访问资源完全分离。