策略模式代码示例(二)

一、定义

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

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

策略模式,可以避免大量的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
相关推荐
魔道不误砍柴功1 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity3 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天3 小时前
java的threadlocal为何内存泄漏
java
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^4 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花4 小时前
【JAVA基础】Java集合基础
java·开发语言·windows