我用过的策略模式

设计源于生活

设计源于生活,策略模式在生活中很常见。凡是我们听到这种:如果...就,要是...就,做选择的地方,多数都能提出一个策略模式的实现。比如下面列举的。

我们每天出门上班,如果下雨我就开汽车,如果天气好我就骑电动车。

策略模式在设计模式中属于行为型模式,策略模式表现为一个类的行为实现,可以在运行时根据条件自主选择。本质上也是一种面向接口编程,通用的策略是一个抽象的接口,具体的策略根据实际情况自主选择。

策略框架

通常来说,策略模式在Java里的实现,有三个要素,Context,AbstractStrategy,List,Context代表一个上下文,AbstractStrategy是一个抽象策略,具体的实现在这个List里面,List也代表可以扩展。

项目实现

看一个实际项目例子

该项目是一个知识付费项目,用户可在线下单支付,商品包括会员商品(年月季会员),虚拟资产(资源包)等。此处在支付核销的环节,使用策略模式,处理不同商品的核销逻辑。

分析下此处项目内设计的商品数据。笔者设计中,年会员、季度会员、月会员分别是一条商品记录、虚拟资产是一条商品记录。其中会员商品是一类商品、虚拟资产又是一类商品。会员商品和虚拟正产的核销逻辑不一样,会员需要给对应用户增加天数。对于年会员、季度会员、阅读会员,它们的区别其实在于会员的权益,对应到系统内部,就是3种会员的一个会员天数不一样。所以这里引入商品的两个逻辑处理字段,处理类型(会员、资源)、处理参数(天数、资源ID等)。

不使用策略模式,我们可能会这么写

@Component
public class PayProssor {
    public void process(byte type , Object params , long uid){
        if(type == VIP){
            this.addUser(uid,params);
            return;            
        }
        if(type == RESOURCE_PAC){
            this.addUserResource(uid,params);
            return;            
        }
    }
}

如果增加商品业务,比如此处增加虚拟豆购买,势必在PayProssor增加一个if,久而久之这里的if就会分支比较多。策略模式怎么实现呢?

首先定义一个抽象实现 PayHandler 以及两个具体实现

public interface PayHandler {
    boolean check(byte type);
    void process(Object params , long uid);
}

@Service
public class VipHandler implements PayHandler {

    @Override
    public boolean check(byte type) {
        return VIP == type;
    }
    
    @Override
    public void process(Object params , long uid) {
        UserProcessor.addUserVip(uid, params);
    }
}

@Service
public class ResourcePacHandler implements PayHandler {

    @Override
    public boolean check(byte type) {
        return RESOURCE == type;
    }
    
    @Override
    public void process(Object params , long uid) {
        UserResProcessor.process(uid, params);
    }
}

定义Context

@Component
public class PayContext {
    
    public void process(byte type , Object params , long uid){
        this.getHandler(type).process(params, uid);    
    }
    
    private PayHandler getHandler(byte type) {
        Optional any = payResultHandlers.stream().filter(x -> x.check(type)).findAny();
        if (any.isPresent()) {
            return any.get();
        }
        throw new ServiceException("不支持的处理类型");
    }    
}

Context负责串接上下文,自动匹配合适的策略,执行策略的方法。当有新的商品加入系统,只需要考虑增加新的策略实现,对商品数据进行对应的配置,就能实现新商品核销的扩展,用较小改动实现新需求。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章