什么是策略模式
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。
策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有共性,而它们的共性就体现在策略接口的行为上,另外为了达到最后一句话的目的,也就是说让算法独立于使用它的客户而独立变化,我们需要让客户端依赖于策略接口。
一种很简单的解释,在我们的开发过程中,经常会遇到大量的if...else或者switch...case语句,当这些语句在开发中只是为了起到分流作用,这些分流和业务逻辑无关,那么这个时候就可以考虑用策略模式。
策略模式的结构
这个模式涉及到三个角色:
上下文环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为
策略模式的应用场景
举一个例子,商场搞促销--打8折,满200送50,满1000送礼物,这种促销就是策略。
再举一个例子,dota里面的战术,玩命四保一,三伪核体系,推进体系,大招流体系等,这些战术都是一种策略。
应用场景:
- 1、 系统有很多类,而他们的区别仅仅在于他们的行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
- 2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
- 3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
策略模式的优缺点
优点:
- 1、结构清晰,把策略分离成一个个单独的类「替换了传统的 if else」
- 2、代码耦合度降低,安全性提高「各个策略的细节被屏蔽」
- 3、提高算法的保密性和安全性。
缺点:
- 1、客户端必须要知道所有的策略类,否则你不知道该使用那个策略,所以策略模式适用于提前知道所有策略的情况下
- 2、策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
策略模式和简单工厂模式的异同
策略模式和简单工厂模式看起来非常相似,都是通过多态来实现不同子类的选取,这种思想应该是从程序的整体来看得出的。
如果从使用这两种模式的角度来看的话,我们会发现在简单工厂模式中我们只需要传递相应的条件就能得到想要的一个对象,然后通过这个对象实现算法的操作。
而策略模式,使用时必须首先创建一个想使用的类对象,然后将该对象最为参数传递进去,通过该对象调用不同的算法。
在简单工厂模式中实现了通过条件选取一个类去实例化对象,策略模式则将选取相应对象的工作交给模式的使用者,它本身不去做选取工作。
策略模式的实现
Strategy类,定义所有支持的算法的公共接口
public interface PromotionStrategy {
void doPromotion();
}
ConcreteStrategy,封装了具体的算法或行为,实现于Strategy
public class ManJianPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("满减促销,慢200减20");
}
}
public class LiJianPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("立减促销,课程的价格直接减去优惠价格");
}
}
public class FanXianPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("返现促销,返回的金额存放到用户余额中");
}
}
Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用
public class PromotionActivity {
private PromotionStrategy promotionStrategy;
public PromotionActivity(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
public void executePromotionStrategy(){
promotionStrategy.doPromotion();
}
}
客户端代码
public class Test {
public static void main(String[] args) {
PromotionActivity promotionActivity618 = new PromotionActivity(new LiJianPromotionStrategy());
PromotionActivity promotionActivity1111 = new PromotionActivity(new FanXianPromotionStrategy());
promotionActivity618.executePromotionStrategy();
promotionActivity1111.executePromotionStrategy();
}
}
策略模式和简单工厂模式的结合
加入促销策略工厂PromotionStrategyFactory
public class PromotionStrategyFactory {
private static Map<String,PromotionStrategy> promotionStrategyMap = new HashMap<>();
private static final EmptyPromotionStrategy emptyPromotionStrategy = new EmptyPromotionStrategy();
static{
promotionStrategyMap.put(PromotionKey.LIJIAN,new LiJianPromotionStrategy());
promotionStrategyMap.put(PromotionKey.FANXIAN,new FanXianPromotionStrategy());
promotionStrategyMap.put(PromotionKey.MANJIAN,new ManJianPromotionStrategy());
}
private PromotionStrategyFactory(){
}
public static PromotionStrategy getPromotionStrategy(String promotionKey){
PromotionStrategy promotionStrategy = promotionStrategyMap.get(promotionKey);
return promotionStrategy == null ? emptyPromotionStrategy : promotionStrategy;
}
private interface PromotionKey{
String LIJIAN = "LIJIAN";
String FANXIAN = "LIJIAN";
String MANJIAN = "MANJIAN";
}
}
新增空促销实现EmptyPromotionStrategy
public class EmptyPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("无促销活动");
}
}
客户端代码
public class Test {
public static void main(String[] args) {
String promotionKey = "LIJIAN";
PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
promotionActivity.executePromotionStrategy();
}
}
总结
策略模式,实质就是封装了一些算法,让算法可以互相替换,用户可以自由选择这些算法进行操作。策略模式本身理解起来没什么难点,但是在实际应用中其本身主要结合工厂模式一起使用。