定义:定义一组算法,将每个算法封装起来,并且使他们之间可以互换。
UML类图:
策略模式中的三个角色:
- Context上下文角色,持有对Strategy策略方法的引用和访问
-
- Strategy策略抽象角色,为具体算法提供了抽象方法或属性,在java中可以是接口或者抽象类。
-
- ConcreteStrategy具体策略角色,实现了抽象策略角色中的具体操作算法。
相关代码:
public class Context {
//持有一个具体策略的对象
private Strategy strategy;
/**
* 构造函数,传入一个具体策略对象
*/
public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 调用策略方法
*/
public void contextInterface(){
strategy.strategyInterface();
}
}
public interface Strategy {
/**
* 策略方法
*/
public void strategyInterface();
}
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
//do something
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyInterface() {
//do something
}
}
public class ConcreteStrategyC implements Strategy {
@Override
public void strategyInterface() {
//do something
}
}
public class Client {
public static void main(String[] args) {
//创建一个具体策略
Strategy strategy = new ConcreteStrategyA();
//创建上下文对象
Context context = Context(strategy);
//调用策略方法
context.contextInterface();
}
}
例子:
假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。本网站可能对所有的高级会员提供每本20%的促销折扣;对中级会员提供每本10%的促销折扣;对初级会员没有折扣。
根据描述,折扣是根据以下的几个算法中的一个进行的:
算法一:对初级会员没有折扣。
算法二:对中级会员提供10%的促销折扣。
算法三:对高级会员提供20%的促销折扣。
使用策略模式来实现的结构图如下:
//抽象折扣类
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);
}
//初级会员折扣类
public class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于初级会员的没有折扣");
return booksPrice;
}
}
//中级会员折扣类
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
}
}
//高级会员折扣类
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于高级会员的折扣为20%");
return booksPrice * 0.8;
}
}
//价格类
public class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
//客户端
public class Client {
public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}
}
策略模式的优点:
- 可以自由切换算法,具体算法类只要实现了抽象策略,就可以动态的进行切换使用。
-
- 避免使用多重条件判断,再也不用写一大堆if-else判语句了,提高了可维护性和可读性。
策略模式的缺点:
- 策略类数量增多,每一个策略都是一个类,复用的可能性小,类数量增多。
-
- 客户端必须知道所有的策略类,才能决定使用哪一个策略类。违反迪米特法则,但是可以用其他模式如工厂方法模式来修复缺陷。
策略模式遵循的OO设计原则:依赖倒置原则。
策略枚举:
public enum Calculator {
ADD("+"){
public int exec(int a, int b){
return a+b;
}
},
SUB("-"){
public int exec(int a, int b){
return a-b;
}
String value="";
private Calculator(String value){
this.value = value;
public abstract int exec(int a, int b);
public String getValue(){
return this.value;
}
}
public class Client {
public static void main(String[] args) {
int a = 2;
int b = 3;
Calculator.ADD.exec(a, b);
Calculator.SUB.exec(a, b);
}
}
策略枚举代码更加简洁,可读性更高。
参考: