概述
策略模式(Strategy)(对象行为型):
是定义了一组算法或策略,将每个算法/策略封装起来,可以相互替换,实现一个功能有个多个算法或策略,然后根据不同的环境和条件选择不同的算法或者策略来实现某功能。
本质:分离算法,选择实现,简单说就是解决一类问题,用户可以根据情况任选某一种算法解决,同时可以很方便的增加或者去除某个算法。
模式解析
此模式涉及到三个角色:
(1)抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
(2)具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
(3)环境(Context)角色:持有一个Strategy的引用。
应用场景:出行选择交通策略、用户支付选择、商品针对不同情况的打折方式
Sring中的应用:springboot启动加载时实例化对象
应用示例
以超市针对不同的会员,计算出每件商品的折扣价。
1. 传统方式
传统方式是,根据不同策略写if()else{}代码,如下:
public Double calculatePrice(int cardLevel, Double price){
if(cardLevel == 1){
return price*0.9;
}else if(cardLevel == 2){
return price*0.85;
}else if(cardLevel == 2){
return price*0.8;
}else{
....
}
return price;
}
2. 应用策略模式
2.1 定义一个折扣策略接口
/**
* 定义折扣策略
*/
public interface DiscountStrategy {
public Double doCalculatePrice(double price);
}
2.2 创建具体折扣的实现类
以下设计两种方式,银卡会员和金卡会员的折扣
/**
* 折扣策略具体实现-银卡折扣价计算:9折
*/
public class SilverCardDiscountPrice implements DiscountStrategy{
@Override
public Double doCalculatePrice(double price) {
return price*0.9;
}
}
/**
* 折扣策略具体实现-金卡折扣价结算:85折
*/
public class GoldenCardDiscountPrice implements DiscountStrategy{
@Override
public Double doCalculatePrice(double price) {
return price*0.85;
}
}
2.3 创建持有策略的具体对象
public class Context {
private DiscountStrategy strategy;
//通过构造函数注入,此外可通过注解方式等其他方式
public Context(DiscountStrategy strategy){
this.strategy = strategy;
}
public Double calculatePriceSum(double price){
return strategy.doCalculatePrice(price);
}
}
2.4 调用实现
public class StrategyTest {
public static void main(String[] args) {
//具体策略
DiscountStrategy goldenStrategy = new GoldenCardDiscountPrice();
DiscountStrategy silverStrategy = new SilverCardDiscountPrice();
//打印出不同会员里某商品折扣价格
int price = 300;
Context context1 = new Context(goldenStrategy);
System.out.println("原价"+ price +",金卡会员折扣价:" + context1.calculatePriceSum(price));
Context context2 = new Context(silverStrategy);
System.out.println("原价"+ price +",银卡会员折扣价:" + context2.calculatePriceSum(price));
}
}
2.5 返回结果
原价300,金卡会员折扣价:255.0
原价300,银卡会员折扣价:270.0
总结
以上为一个折扣价的简单实现,常规项目中,除了定义并实现一个个策略很重要,其根据不同的场景选择不同的策略也值得思考。以上例子简单通过构造函数注入,也可通过setter方式注入,也可以通过注解方式,也可以同先做项目一样通过定义一个匹配器,根据数据匹配到不同的策略等其他多种方式,通常项目中会结合其他设计模式混合使用。
优点
1. 策略模式中其算法可以自由切换,减少ifelse,避免臃肿,及避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
2. 扩展性良好,增加一个策略只需实现接口即可
3. 符合设计的开闭原则,对客户隐藏具体策略 (算法) 的实现细节,彼此完全独立。
缺点
1. 策略类数量会增多,每个策略都是一个类,复用的可能性很小
2. 策略类都需要对外暴露,用户端必须知道所有的策略类,并自行决定使用哪一个策略类。
3. context在使用这些策略类的时候,这些具体实现策略类由于继承了策略接口,所以有些数据可能用不到,但是依然被初始化。
author:yana