策略模式,枚举的应用和区别

 

在阅读前需要对策略模式、状态模式、枚举有所了解。

例子:

文件分享,分享表需要记录分享期限,简化表结构如下

表share
idtime_limitcreate_time

id为主键,time_limit为分享期限,有1,2,3三个值,其中1代表永久,2代表一周,3代表一天,create_time分享创建时间。

表share_resource
idshare_idresource_id

id为主键,share_id为分享表的id,resource_id为文件的id,分享和文件为多对多的关系。

查询到一条share记录后,需要计算当前的分享是否过期。

如果需要测试以下代码将所有的Share share = shareService.getByUserId(userId);替换为Share share = new Share();

根据share表结构新建一个class Share自定义属性即可。

通过if else的解决办法:

@Controller
public Share getShare(String userId) {
    Share share = shareService.getByUserId(userId);
    if(isValidShare(share)) {
        return share;
    }
    return null;
}

// 判断是否分享是否过期
private boolean isValidShare(Share Share){
    Integer timeLimit = share.getTimeLimit();
    int day = 0;

    // 将数据库数据转化为实际计算的天数
    if(timeLimit.equals(1)) {
        day = 1;
    }else if(timeLimit.equals(2)) {
        day = 7;
    }
    
    // 计算天数
    if(day == 0){
        return true;
    }
    if(System.currentTimeMillis() < createTime.getTime() + day * 24 * 60 * 60 * 1000) {
        return true;
    }
    return false;
}

通过以上代码,如果我想增加一个时间限制类型,如分享期限为一个月,那么我就需要在原来的if else中再添加一个if else。

    // 将数据库数据转化为实际计算的天数
    if(timeLimit.equals(1)) {
        day = 1;
    }else if(timeLimit.equals(2)) {
        day = 7;
    }else if(timeLimit.equals(4)) {
        day = 30;
    }

设计模式原则之一——开闭原则:对扩展开放,对修改关闭。

显然,在原来的代码上增加一个if else这不符合上面的原则。

策略模式:

策略类

/**
 *抽象父类
 */
public abstract class CountTimeStrategy{
    protect abstract getDay(); // 获取实现类的天数

    public boolean isValid(Share share){
        Date createTime = share.getCreateTime();
        if(getDay() == 0){
            return true;
        }
        return System.currentTimeMillis() < createTime.getTime() + getDay() * 24 * 60 * 60 * 1000;
    }
}

/*
 * “一天”的实现类
 */
public class OneDayStrategy extends CountTimeStrategy{
    
    @Override
    int getDay(){
        return 1;
    }

}

/*
 * “一周”的实现类
 */
public class WeekStrategy extends CountTimeStrategy{
    
    @Override
    int getDay(){
        return 7;
    }

}

/*
 * “永远”的实现类
 */
public class ForeverStrategy extends CountTimeStrategy{
    
    @Override
    int getDay(){
        return 0;
    }

}

controller

@Controller
public Share getShare(String userId) {
    Share share = shareService.getByUserId(userId);
    if(isValidShare(share)) {
        return share;
    }
    return null;
}

// 判断是否分享是否过期
private boolean isValidShare(Share Share){
    Integer timeLimit = share.getTimeLimit();

    // 判断使用哪个策略
    CountTimeStrategy countTimeStrategy;
    if(timeLimit.equals(1)) {
        countTimeStrategy = new OneDayStrategy();
    }else if(timeLimit.equals(2)) {
        countTimeStrategy = new WeekStrategy();
    }else if(timeLimit.equals(3)) {
        countTimeStrategy = new ForeverStrategy();
    }
    return countTimeStrategy.isValid(timeLimit)
}

虽然策略模式已经把实现抽离了主方法,但还是免不了使用if else,免不了if else,就无法很好的对修改关闭,究其原因是因为程序无法自动判断使用哪个实现类。

如何自动判断使用哪个策略实现类呢?不妨自己思考一下,有好的办法欢迎分享留言。

我的解决办法是使用map,在CountTimeStrategy中添加一个key为判断条件,value为实现类的map,修改后代码如下

使用map代替if else

/**
 *抽象父类
 */
public abstract class CountTimeStrategy{
    // key-判断条件 value-实现类的map
    Map<Integer, CountTimeStrategy> strategyMap = new HashMap<>;

    protect abstract getDay(); // 获取实现类的天数

    public boolean isValid(Share share){
        Date createTime = share.getCreateTime();
        if(getDay() == 0){
            return true;
        }
        return System.currentTimeMillis() < createTime.getTime() + getDay() * 24 * 60 * 60 * 1000;
    }
}

/*
 * “一天”的实现类
 */
public class OneDayStrategy extends CountTimeStrategy{

    static {
        OneDayStrategy oneDayStrategy = new OneDayStrategy();
        strategyMap.put(1, oneDayStrategy);
    }
    
    @Override
    int getDay(){
        return 1;
    }

}

/*
 * “一周”的实现类
 */
public class WeekStrategy extends CountTimeStrategy{
    
    static {
        WeekStrategy weekStrategy = new WeekStrategy ();
        strategyMap.put(2, weekStrategy );
    }

    @Override
    int getDay(){
        return 7;
    }

}

/*
 * “永远”的实现类
 */
public class ForeverStrategy extends CountTimeStrategy{

    static {
        ForeverStrategy foreverStrategy = new ForeverStrategy ();
        strategyMap.put(3, foreverStrategy );
    }

    @Override
    int getDay(){
        return 0;
    }

}

Controller

@Controller
public Share getShare(String userId) {
    Share share = shareService.getByUserId(userId);
    if(isValidShare(share)) {
        return share;
    }
    return null;
}

// 判断是否分享是否过期
private boolean isValidShare(Share share){
    Integer timeLimit = share.getTimeLimit();
    return CountTimeStrategy.strategys.get(timeLimit).isValid(share);
}

使用map后就可以通过key获取对应的实现类了,这时候当我们需要添加一个月的期限时就不需要修改任何代码,只需要新建一个CountTimeStrategy的子类即可,如下

扩展分享期限“一个月”

/*
 * “一月”的实现类
 */
public class MonthStrategy extends CountTimeStrategy{

    static {
        // 将实现类存入父类的map
        MonthStrategy monthStrategy = new MonthStrategy();
        strategyMap.put(4, monthStrategy);
    }
    
    @Override
    int getDay(){
        return 30;
    }

}

看到这里会发现对于不同的timeLimit会有不同的day来对应,使用策略模式有点小题大作了,完全可以使用map<Integer, Integer>{<1, null>, <2, 7>, <3, 1>}来解决,没错,策略模式是适用于方法实现不同的场景,而这里的方法实现相同,唯一的不同就是参数day

那么只有参数变化的情况使用什么方式比较合适呢?

使用枚举enum

使用枚举和使用策略模式非常相似

public enum CountTimeEnum {

    ONEDAY(1), // 相当于OneDayStrategy

    WEEK(7), // 相当于WeekStrategy

    FOREVER(null); // 相当于ForeverStrategy

    public static Map<Integer, TimeLimitEnum> countTimeEnumMap = new HashMap<>();

    static{
        countTimeEnumMap .put(1,FOREVER);
        countTimeEnumMap .put(2,WEEK);
        countTimeEnumMap .put(3,ONEDAY);
    }

    private Integer day;

    TimeLimitEnum(Integer day) {
        this.day= day;
    }

    public boolean isValid(Share share) {
        Date createTime = share.getCreateTime();
        if(day == null){
            return true;
        }
        if(System.currentTimeMillis() < createTime.getTime() + day* 24 * 60 * 60 * 1000){
            return true;
        }else{
            return false;
        }
    }
}
@Controller
public Share getShare(String userId) {
    Share share = shareService.getByUserId(userId);
    if(isValidShare(share)) {
        return share;
    }
    return null;
}

// 判断是否分享是否过期
private boolean isValidShare(Share share){
    Integer timeLimit = share.getTimeLimit();
    return TimeLimitEnum.timeLimitEnumMap .get(timeLimit).isValid(share);
}

枚举和策略模式的区别:

枚举类中的各个实例的方法实现是一样的,通过不同的参数得到不同的结果。

策略模式的各个策略方法除了可以输入不同的参数,实现也可以不同,可以将相同的实现放在抽象父类,不同的实现由子类实现,更加灵活。

题外话:

因为方法的参数为share,应用面向对象的思想应该把isValidShare(Share share)方法放入share类中。

public class Share {
    private String id;
    
    private Integer timeLimit;

    private Date createTime;

    // 判断是否分享是否过期

    private boolean isValidShare(){
        return TimeLimitEnum.timeLimitEnumMap .get(timeLimit).isValid(createTime);
    }
}
public enum CountTimeEnum {

    ONEDAY(1), // 相当于OneDayStrategy

    WEEK(7), // 相当于WeekStrategy

    FOREVER(null); // 相当于ForeverStrategy

    public static Map<Integer, TimeLimitEnum> countTimeEnumMap = new HashMap<>();

    static{
        countTimeEnumMap .put(1,FOREVER);
        countTimeEnumMap .put(2,WEEK);
        countTimeEnumMap .put(3,ONEDAY);
    }

    private Integer day;

    TimeLimitEnum(Integer day) {
        this.day= day;
    }

    public boolean isValid(Date createTime) {
        if(day == null){
            return true;
        }
        if(System.currentTimeMillis() < createTime.getTime() + day* 24 * 60 * 60 * 1000){
            return true;
        }else{
            return false;
        }
    }
}
@Controller
public Share getShare(String userId) {
    Share share = shareService.getByUserId(userId);
    // 判断是否分享是否过期
    if(share.isValidShare()) {
        return share;
    }
    return null;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值