Java设计模式中的策略模式

1:策略模式图解

在这里插入图片描述

2:例如重构如下:取代if-else

public Double commonMethod(Integer type, Double amount) {
    if (3 == type) {
        // 计算费用
        if (true) {
            // 此处省略200行代码,包含n个if-else,下同。。。
        }
        return 0.00;
    } else if (2 == type) {
        // 计算费用
        return 6.66;
    }else if (1 == type) {
        // 计算费用
        return 8.88;
    }else if (0 == type){
        return 9.99;
    }
    throw new IllegalArgumentException("please input right value");
}

3、通用部分

普通会员、初级会员、中级会员和高级会员,会员级别不同计费规则不同。该模块负责计算会员所需的缴纳的服务费。
3.1:会员枚举

public enum MemberEnum {

    ORDINARY_MEMBER(0, "普通会员"),
    JUNIOR_MEMBER(1, "初级会员"),
    INTERMEDIATE_MEMBER(2, "中级会员"),
    SENIOR_MEMBER(3, "高级会员"),

    ;

    int code;
    String desc;

    MemberEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }


    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

}

3.2:定义一个策略接口

该接口包含两个方法:
compute(Double amount):各计费规则的抽象
getType():获取枚举中维护的会员级别

public interface FeeService {

    /**
     * 计费规则
     * @param amount 会员的交易金额
     * @return
     */
    Double compute(Double amount);

    /**
     * 获取会员级别
     * @return
     */
    Integer getType();
}

3.3:不同计费规则的实现-把策略的实现类得是交给Spring 容器管理

  • 普通会员计费规则
@Component
public class OrdinaryMember implements FeeService {

    /**
     * 计算普通会员所需缴费的金额
     * @param amount 会员的交易金额
     * @return
     */
    @Override
    public Double compute(Double amount) {
        // 具体的实现根据业务需求修改
        return 9.99;
    }

    @Override
    public Integer getType() {
        return MemberEnum.ORDINARY_MEMBER.getCode();
    }
}
  • 初级会员计费规则
@Component
public class JuniorMember implements FeeService {

    /**
     * 计算初级会员所需缴费的金额
     * @param amount 会员的交易金额
     * @return
     */
    @Override
    public Double compute(Double amount) {
        // 具体的实现根据业务需求修改
        return 8.88;
    }

    @Override
    public Integer getType() {
        return MemberEnum.JUNIOR_MEMBER.getCode();
    }
}
  • 中级会员计费规则
@Component
public class IntermediateMember implements FeeService {

    /**
     * 计算中级会员所需缴费的金额
     * @param amount 会员的交易金额
     * @return
     */
    @Override
    public Double compute(Double amount) {
        // 具体的实现根据业务需求修改
        return 6.66;
    }

    @Override
    public Integer getType() {
        return MemberEnum.INTERMEDIATE_MEMBER.getCode();
    }
}
  • 高级会员计费规则
@Component
public class SeniorMember implements FeeService {

    /**
     * 计算高级会员所需缴费的金额
     * @param amount 会员的交易金额
     * @return
     */
    @Override
    public Double compute(Double amount) {
        // 具体的实现根据业务需求修改
        return 0.01;
    }

    @Override
    public Integer getType() {
        return MemberEnum.SENIOR_MEMBER.getCode();
    }
}

3.4:策略工厂

@Component
public class ServiceFeeHolder {

    /**
     * 将 Spring 中所有实现 ServiceFee 的接口类注入到这个Map中
     */
    @Resource
    private Map<String, FeeService> serviceFeeMap;

    @Resource
    private AliasEntity aliasEntity;

    /**
     * 获取该会员应当缴纳的费用
     * @param desc 会员标志
     * @param money 交易金额
     * @return
     * @throws IllegalArgumentException 会员级别输入错误
     */
    public Double getFee(String desc, Double money) {
        return getBean(desc).compute(money);
    }

    /**
     * 获取会员标志(枚举中的数字)
     * @param desc 会员标志
     * @return
     * @throws IllegalArgumentException 会员级别输入错误
     */
    public Integer getType(String desc) {
        return getBean(desc).getType();
    }

    private FeeService getBean(String type) {
        // 根据配置中的别名获取该策略的实现类
        FeeService entStrategy = serviceFeeMap.get(aliasEntity.getEntity(type));
        if (entStrategy == null) {
            // 找不到对应的策略的实现类,抛出异常
            throw new IllegalArgumentException("please input right value");
        }
        return entStrategy;
    }
}

亮点

1:将 Spring中所有 ServiceFee.java 的实现类注入到Map中,不同策略通过其不同的key获取其实现类;
:2:找不到对应的策略的实现类,抛出IllegalArgumentException异常。

测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class DemoTest {

    @Resource
    ServiceFeeHolder serviceFeeHolder;

    @Test
    public void test() {
         // 计算应缴纳费用
        System.out.println(serviceFeeHolder.getFee("second", 1.333));
        // 获取会员标志
        System.out.println(serviceFeeHolder.getType("second"));
        // 会员描述错误,抛 IllegalArgumentException
        System.out.println(serviceFeeHolder.getType("zero"));
    }
}

结果

8.88
1
java.lang.IllegalArgumentException: please input right value

总结

Context: 环境类
Context叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化,对应本文的ServiceFeeFactory.java。

Strategy: 抽象策略类
定义算法的接口,对应本文的FeeService.java。

ConcreteStrategy: 具体策略类

备注:依赖

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

参考

https://juejin.im/post/5e5dbe36f265da57455b4a67
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值