策略模式


策略模式

1.基础知识:

定义∶

定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。

可以干掉if...else...

适用场景

系统有很多类,而他们的区别仅仅在于他们的行为不同

一个系统需要动态地在几种算法中选择一种

比如支付方式的选择

优点

开闭原则

避免使用多重条件转移语句

提高算法的保密性和安全性

缺点

客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

产生很多策略类


2.实战

创建学习策略接口

/**
 * 学习策略
 * @Author LYS
 * @Date 2022/1/16 9:25
 * @Version 1.0
 */
public interface LearnStrategy {
    void doStudy();
}

创建不同的学习实现类

/**
 * 语文学习策略
 * @Author LYS
 * @Date 2022/1/16 9:27
 * @Version 1.0
 */
public class ChineseLearnStrategy implements LearnStrategy{
    @Override
    public void doStudy() {
        System.out.println("语文学习策略");
    }
}
/**
 * 空学习策略
 * @Author LYS
 * @Date 2022/1/16 9:28
 * @Version 1.0
 */
public class EmptyLearnStrategy implements LearnStrategy{

    @Override
    public void doStudy() {
        System.out.println("空学习策略");
    }
}
/**
 * 英语学习策略
 * @Author LYS
 * @Date 2022/1/16 9:27
 * @Version 1.0
 */
public class EnglishLearnStrategy implements LearnStrategy{
    @Override
    public void doStudy() {
        System.out.println("英语学习策略");
    }
}
/**
 * 数学学习策略
 * @Author LYS
 * @Date 2022/1/16 9:26
 * @Version 1.0
 */
public class MathLearnStrategy implements LearnStrategy{
    @Override
    public void doStudy() {
        System.out.println("数学学习策略");
    }
}
/**
 * 执行策略
 * @Author LYS
 * @Date 2022/1/16 9:33
 * @Version 1.0
 */
public class LearnActivity {
    private LearnStrategy learnStrategy;

    public LearnActivity(LearnStrategy learnStrategy) {
        this.learnStrategy = learnStrategy;
    }

    public void executeLearnStrategy(){
        learnStrategy.doStudy();
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        LearnActivity learnActivity = null;
        String key = "ENGLISH";
        if("ENGLISH".equals(key)){
            learnActivity = new LearnActivity(new EnglishLearnStrategy());
        }else if("MATH".equals(key)){
            learnActivity = new LearnActivity(new MathLearnStrategy());
        }else if("CHINESE".equals(key)){
            learnActivity = new LearnActivity(new ChineseLearnStrategy());
        }else{
            learnActivity = new LearnActivity(new EmptyLearnStrategy());
        }
        learnActivity.executeLearnStrategy();
    }

控制台输出

image-20220116103140415

但是这样的代码编写,还是有ifelse,感觉并没有什么软用,只是比原来逻辑清晰了一点,相当于独立抽离代码块,接下来结合工厂模式和单例模式,打出一套必杀组合拳去掉ifelse。


创建工厂

package DesignPattern.strategy;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author LYS
 * @Date 2022/1/16 9:29
 * @Version 1.0
 */
public class LearnStrategyFactory {
    private static Map LEARN_STRATEGY_MAP = new HashMap();

    //类加载的时候就执行了静态代码片,类似饿汉模式,空间换时间   使不同的策略是单例的
    static {
        LEARN_STRATEGY_MAP.put(LearnKey.MATH, new MathLearnStrategy());
        LEARN_STRATEGY_MAP.put(LearnKey.CHINESE, new ChineseLearnStrategy());
        LEARN_STRATEGY_MAP.put(LearnKey.ENGLISH, new EnglishLearnStrategy());
    }

    private static final LearnStrategy NON_PROMOTION = new EmptyLearnStrategy();

    private LearnStrategyFactory() {

    }

    public static LearnStrategy getPromotionStrategy(String promotionKey) {
        LearnStrategy promotionStrategy = LEARN_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }

    private interface LearnKey {
        String MATH = "MATH";
        String CHINESE = "CHINESE";
        String ENGLISH = "ENGLISH";
    }
}

测试类

    public static void main(String[] args) {
//        String learnKey = "ENGLISH";
//        String learnKey = "CHINESE";
        String learnKey = "MATH";
        LearnActivity promotionActivity = new LearnActivity(LearnStrategyFactory.getPromotionStrategy(learnKey));
        promotionActivity.executeLearnStrategy();
    }

执行结果:

image-20220116103454497

一行代码搞定所有,简介明了,又使用了单例,相比原来一个执行一个策略就new bean的情况,节省了大量空间,简直是艺术!


3.源码调用:

观察AbstractAutowireCapableBeanFactory类代码,其使用了懒汉式的方法加载策略,这里是用的时cglib动态代理的加载策略

也就是使用单例+策略模式

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
      implements AutowireCapableBeanFactory {

   /** Strategy for creating bean instances. */
   private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
   
   	/**
	 * Set the instantiation strategy to use for creating bean instances.
	 * Default is CglibSubclassingInstantiationStrategy.
	 * @see CglibSubclassingInstantiationStrategy
	 */
	public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
		this.instantiationStrategy = instantiationStrategy;
	}

resource接口策略的抽象
不同的接口就是对不同策略的实现,比如classpathresource


comparator.compare比较器,就是对不同的情况有不同策略的实现


bean的初始化也使用饿了
image-20220116092224485

相关