设计模式之策略模式
定义
1.在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
2.在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
策略模式的三大要素
1.环境(Context)角色:持有一个Strategy的引用,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
策略模式的应用
- 何时使用
一个系统有许多类,而区分它们的只是他们直接的行为时 - 方法
将这些算法封装成一个一个的类,任意的替换 - 优点
算法可以自由切换
避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
扩展性良好,增加一个策略只需实现接口即可 - 缺点
策略类数量会增多,每个策略都是一个类,复用的可能性很小
所有的策略类都需要对外暴露 - 使用场景
多个类只有算法或行为上稍有不同的场景
算法需要自由切换的场景
需要屏蔽算法规则的场景 - 应用实例
出行方式,自行车、汽车等,每一种出行方式都是一个策略
商场促销方式,打折、满减等
Java AWT中的LayoutManager,即布局管理器 - 注意事项
如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题
spring 中的策略模式
Spring 中在实例化对象的时候用到 Strategy 模式, 在SimpleInstantiationStrategy 有使用
策略模式的实现
以某商城买书为例,比如普通会员不打折,黄金会员打8折,白金会员打7折,钻石会员打6折等
根据以上的需求,按照传统的写法,需要多个if,else或者其他逻辑判断语句来完成,但是这样的可维护性太差,不利于扩展。这个时候就可以用策略模式解决以上的问题。
按照策略模式,以上的打折方式可分为具体以下几种算法:
算法1:普通会员不打折
算法2:黄金会员打8折
算法3:白金会员打7折
…
这样的话,我们就可以按照如下的代码进行设计实现:
定义抽象类
package Strategydemo.strategy;
/**
* 折扣接口
* @author yyl
*/
public interface DiscountStrategy {
/**
* 计算图书的价格
*/
void countPrice();
}
普通会员实现
package Strategydemo.strategy;
/**
* 算法一:普通会员折扣类
* @author yyl
*/
public class CommonMemberDiscountStrategy implements DiscountStrategy {
@Override
public void countPrice() {
// 具体逻辑实现
System.out.println("普通会员,按原价销售.....");
}
}
黄金会员实现
package Strategydemo.strategy;
/**
* 算法二:黄金会员折扣类
* @author yyl
*/
public class GoldMemberDiscountStrategy implements DiscountStrategy {
@Override
public void countPrice() {
// 具体逻辑实现
System.out.println("黄金会员,按8折销售.....");
}
}
白金会员实现
package Strategydemo.strategy;
/**
* 算法三:白金会员折扣类
* @author yyl
*/
public class PlatinumMemberDiscountStrategy implements DiscountStrategy {
@Override
public void countPrice() {
// 具体逻辑实现
System.out.println("白金会员,按7折销售.....");
}
}
定义上下文
package Strategydemo.context;
import Strategydemo.strategy.DiscountStrategy;
/**
* 定义上下文,持有具体的策略对象
*
* @author yyl
*/
public class PriceContext {
//持有一个具体的策略对象
private DiscountStrategy discountStrategy;
/**
* 构造函数,传入一个具体的策略对象
*
* @param strategy 具体的策略对象
*/
public PriceContext(DiscountStrategy strategy) {
this.discountStrategy = strategy;
}
/**
* 计算图书的价格
*/
public void quote() {
this.discountStrategy.countPrice();
}
}
选择具体的策略
package Strategydemo;
import Strategydemo.context.PriceContext;
import Strategydemo.strategy.CommonMemberDiscountStrategy;
import Strategydemo.strategy.GoldMemberDiscountStrategy;
import Strategydemo.strategy.PlatinumMemberDiscountStrategy;
public class TestStrategy {
public static void main(String[] args) {
// 普通会员
CommonMemberDiscountStrategy commonMemberDiscountStrategy = new CommonMemberDiscountStrategy();
PriceContext priceContext = new PriceContext(commonMemberDiscountStrategy);
priceContext.quote();
// 黄金会员
GoldMemberDiscountStrategy goldMemberDiscountStrategy = new GoldMemberDiscountStrategy();
priceContext = new PriceContext(goldMemberDiscountStrategy);
priceContext.quote();
// 白金会员
PlatinumMemberDiscountStrategy platinumMemberDiscountStrategy = new PlatinumMemberDiscountStrategy();
priceContext = new PriceContext(platinumMemberDiscountStrategy);
priceContext.quote();
}
}
根据具体选择的策略输出:
正如策略模式的缺点,当会员的模式变得更多后,比如后面增加钻石会员,超级会员等,策略类就会变得更多,这个时候可以考虑使用混合模式来解决。
参考文章
https://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html.
https://www.cnblogs.com/adamjwh/p/11011095.html.
https://www.runoob.com/design-pattern/strategy-pattern.html.