简述:定义一系列的算法,并将每个算法单独封装起来,使得各个算法可以相互替换。策略模式通常包含以下几种角色:
-
抽象策略(Strategy)类:定义一个公共接口,各个策略类实现这个接口做自定义的实现逻辑,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现
-
具体策略(Concrete Strategy)类:实现抽象策略定义的接口,提供具体的算法实现
-
环境(Context)类:持有一个策略类的引用,最终给客户端调用
优缺点?
优点:
-
可扩展:需要扩展功能的时候增加新的策略类即可,无需修改现有代码,符合开闭原则
-
易维护:不同的策略实现逻辑封装在各个策略类中,代码结构清晰,易于理解维护
-
可替换:客户端可以根据需要选择不同策略进行调用,灵活性搞
-
避免多重条件判断:简单来说是对复杂if-else语句的优化,使得代码结构更清晰,可读性更好
缺点:
-
类数量:每个策略需要一个单独的类,策略较多时,或导致类的膨胀
-
复杂性:客户端必须知道所有的策略类,才能选择合适的策略使用,增加了客户端的复杂性,不过该问题在使用多重条件判断时同样存在
-
额外开销:动态的切换策略类,会带来一定的额外开销
实战
话不多说,我们来看一下实战效果,以下代码以购物积分为例
首先来看一下没有使用策略模式的代码
/**
* 根据不同消费类型,定义不用的积分机制
* @param type
*/
private static void purchase(String type) {
if ("furniture".equals(type)){
System.out.println("家具");
} else if ("clothing".equals(type)){
System.out.println("服饰");
} else if ("food".equals(type)){
System.out.println("食品");
} else {
System.out.println("其他");
}
}
如果说需要新增策略,或者某个策略的代码需要修改,则会动到这一段if-else的代码,不满足代码的开闭原则,可读性也很差。
然后我们来看一下策略模式的代码:
首先定义抽象策略类和具体策略类
public interface Strategy {
/**
* score方法
* @param params
*/
void score(Object ... params);
}
public class FurnitureStrategy implements Strategy{
@Override
public void score(Object... params) {
System.out.println("家具策略");
}
}
到这里基本已经实现了策略模式的核心思想了,接下来我们再接着做优化,使用单例模式+注册的方式使得代码更加的优雅
定义一个抽象类,实现注册方法:
public abstract class AbstractStrategy implements Strategy{
public void register(){
Context.registerStrategy(getClass().getSimpleName(),this);
}
}
public class FurnitureStrategy extends AbstractStrategy implements Strategy{
private static final FurnitureStrategy instance = new FurnitureStrategy();
private FurnitureStrategy(){
register();
}
public static FirstStrategy getInstance() {
return instance;
}
@Override
public void score(Object... params) {
System.out.println("家具策略");
}
}
使用:
public static void main(String[] args) {
//注册
Context.registerStrategy("furniture",FirstStrategy.getInstance());
//使用
Context.getStrategy("furniture").score();
}
实际使用时,需要先将所有策略注册到Context中,然后使用的时候通过Context去调用即可。鉴于我们通常使用Spring框架进行开发,可以直接利用Spring的Bean机制来实现上面的部分设计,可以通过@Component和@PostConstruct注解完成单例的创建和注册。
实现代码如下,为了便于阅读,将抽象策略类和具体策略类放到一起
public interface Strategy {
/**
* score方法
* @param params
*/
void score(Object ... params);
}
@Component
class FurnitureStrategy implements Strategy{
@Override
public void score(Object... params) {
System.out.println("家具策略");
}
}
@Component
class ClothingStrategy implements Strategy{
@Override
public void score(Object... params) {
System.out.println("服饰策略");
}
}
@Component
class FoodStrategy implements Strategy{
@Override
public void score(Object... params) {
System.out.println("食品策略");
}
}
@Component
class OtherStrategy implements Strategy{
@Override
public void score(Object... params) {
System.out.println("其他策略");
}
}
将所有的策略注册到spring容器中:
@Component
public class StrategyRegistry {
private Map<String, Strategy> strategies;
@Autowired
public StrategyRegistry(List<Strategy> strategyList) {
strategies = new HashMap<>();
for (Strategy strategy : strategyList) {
String strategyName = strategy.getClass().getSimpleName();
strategies.put(strategyName, strategy);
}
}
public Strategy getStrategy(String strategyName) {
return strategies.get(strategyName);
}
}
使用:
public void strategyTest(String type){
Strategy strategy = strategyRegistry.getStrategy(type);
strategy.score();
}
总结
通过设计模式,能够提高代码质量,提高代码的可读性、拓展性、可维护性等等,还能装X,可以说是程序员必备技能之一。以上内容是鄙人薄见,欢迎大家一起探讨,共同进步。