策略模式代码示例(二)

一、定义

策略模式,针对每一个不同的类型,调用具有共同接口的不同实现类,从而使得它们可以相互替换。

策略模式 ,针对实现同一接口的不同的类,采用不同的策略。比如,面对高级会员、初级会员会采用不同的折扣。

策略模式,可以避免大量的if和else。

二、角色

策略模式涉及到三个角色:

●  环境(Context)角色:调用策略

●  抽象策略(Strategy)角色:抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

●  具体策略(ConcreteStrategy)角色:实现抽象策略接口,包装了相关的算法或行为。

三、代码示例

type 枚举

public enum TypeEnum {

    /**
     * 类型一
     */
    FIRST_TYPE(1, "类型一"),

    /**
     * 类型二
     */
    SECOND_TYPE(2, "类型二"),

    /**
     * 类型三
     */
    THIRD_TYPE(3, "类型三"),
    ;

    /**
     * 类型
     */
    private final Integer type;
    private final String typeName;

    TypeEnum(Integer type, String text) {
        this.type = type;
        this.typeName = text;
    }


    public Integer getType() {
        return type;
    }

    public String getTypeName() {
        return typeName;
    }


    /**
     * 根据 type 获取枚举
     *
     * @param type
     * @return
     */
    public static TypeEnum getByType(Integer type) {
        for (TypeEnum typeEnum : TypeEnum.values()) {
            if (typeEnum.getType().equals(type)) {
                return typeEnum;
            }
        }
        return null;
    }

    public static TypeEnum getByName(String name) {
        for (TypeEnum typeEnum : TypeEnum.values()) {
            if (typeEnum.getTypeName().equals(name)) {
                return typeEnum;
            }
        }
        return null;
    }

}

基础类:

/**
 * 基础类,写不同策略的公共的代码,避免代码重复
 */
@Service
public class TypeStrategyBaseService {

    /**
     * 公共代码,避免重复
     */
    public void doCommon() {
        System.out.println("execute common method.");
    }
}

策略模式接口:

/**
 * 策略模式接口
 *
 */
public interface TypeStrategy {

    /**
     * 做某事
     * @param param
     * @return
     */
    String doSth(String param) ;

    /**
     * 获取类型
     * @return
     */
    Integer getType();
}

第一种策略:

/**
 * 第一种策略
 */
@Service
public class FirstTypeStrategyServerImpl extends TypeStrategyBaseService implements TypeStrategy {

    /**
     * 业务逻辑
     */
    @Override
    public String doSth(String param) {
        doCommon();
        return "FirstStrategy doSth " + param;
    }

    @Override
    public Integer getType() {
        return TypeEnum.FIRST_TYPE.getType();
    }

}

第二种策略:

/**
 * 第二种策略
 */
@Service
public class SecondTypeStrategyServiceImpl extends TypeStrategyBaseService implements TypeStrategy {

    /**
     * 业务逻辑
     */
    @Override
    public String doSth(String param) {
        doCommon();
        return "SecondStrategy doSth " + param;
    }

    @Override
    public Integer getType() {
        return TypeEnum.SECOND_TYPE.getType();
    }

}

配置 策略对应的 map:

@Component
public class SpringApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        applicationContext = ctx;
    }

    /**
     * 获取类型为 key,策略作为value 的 map
     *
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> classType) {
        if (applicationContext == null) {
            log.warn("ApplicationContext is null.classType:{}", JSON.toJSONString(classType));
            throw new IllegalStateException("getBeansOfType failed.ApplicationContext is null");
        }
        return applicationContext.getBeansOfType(classType);
    }


}

策略 Context

/**
 * 策略 Context,获取策略
 */
@Component
public class TypeStrategyContext {
    /**
     *  存在多个容器的时候会被加载多次
     */
    private static volatile Map<Integer, TypeStrategy> strategyMap;

    @PostConstruct
    public static void init() {
        if (strategyMap == null) {
            Map<String, TypeStrategy> subBeanMap = SpringApplicationContextHolder.getBeansOfType(TypeStrategy.class);
            strategyMap = subBeanMap.values().stream().collect(Collectors.toMap(TypeStrategy::getType, typeStrategy -> typeStrategy));
        }
    }

    /**
     * 根据 type 获取不同的策略,再执行业务逻辑。
     */
    public static TypeStrategy getStrategyByType(int type) {
        return strategyMap.get(type);
    }

}

调用策略的类:

/**
 * 调用类
 *
 */
@Service
public class TypeStrategyClientService {


    /**
     * 根据 type 获取不同的策略,再执行业务逻辑。
     */
    public String doSthByType(Integer type, String param) {
        TypeStrategy typeStrategy = TypeStrategyContext.getStrategyByType(type);
        if (typeStrategy == null) {
            throw new IllegalStateException("类型"+ type + "不存在策略");
        }
        return typeStrategy.doSth(param);
    }


}

测试:

@Test
public void testDoSthByType2()  {
    String result = typeStrategyClientService.doSthByType(1, "12345");
    System.out.println("==============> typeStrategyClientService result: " + result);
}

输出结果:

type 为1时,结果为:

execute common method.
==============> result: FirstStrategy doSth 12345

type为2时,结果为:

execute common method.
==============> result: SecondStrategy doSth 12345
相关推荐
计算机徐师兄25 分钟前
Java基于SSM框架的无中介租房系统小程序【附源码、文档】
java·微信小程序·小程序·无中介租房系统小程序·java无中介租房系统小程序·无中介租房微信小程序
源码哥_博纳软云26 分钟前
JAVA智慧养老养老护理帮忙代办陪诊陪护小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
忒可君1 小时前
C# winform 报错:类型“System.Int32”的对象无法转换为类型“System.Int16”。
java·开发语言
斌斌_____2 小时前
Spring Boot 配置文件的加载顺序
java·spring boot·后端
路在脚下@2 小时前
Spring如何处理循环依赖
java·后端·spring
一个不秃头的 程序员2 小时前
代码加入SFTP JAVA ---(小白篇3)
java·python·github
丁总学Java2 小时前
--spring.profiles.active=prod
java·spring
上等猿3 小时前
集合stream
java
java1234_小锋3 小时前
MyBatis如何处理延迟加载?
java·开发语言
菠萝咕噜肉i3 小时前
MyBatis是什么?为什么有全自动ORM框架还是MyBatis比较受欢迎?
java·mybatis·框架·半自动