注册和策略模式

      入职新公司一年多的时间都没写博客了额,有点久。

      今天要说的是策略模式,策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。

      定义还是比较简单的,难点在于使用。

      首先,怎么决定使用哪个策略呢?网上的教程大部分都是if/else,我就想说,在策略模式中还大量使用if/else的怎么没被打死呢???

       那如果不用if/else该怎么办呢,答案就是map。仔细想想,if/else的目的是什么,就是为了拿到一种策略,那么map.get(key)不也能达到吗?这样是不是更优雅一些?

       问题来了,map中怎么会有各种策略呢?这个就是我们注册的了。在项目启动的时候我们就会把这些策略注册到map中,这样在使用的时候就简单了,有些同学可能会说,这样不是浪费内存吗?其实这个担心是有道理的,但是如果这个策略对象的内存大小可以忽略不计,就没有有必要担心了。实际上策略模式的对象所占内存就是很小的,因为策略模式本身是不携带数据的,只是一个策略(方法)。这种map在spring、mybatis中也被大量使用着的。连大厂都是这么做的,我们效仿一下又如何呢?

     上面说了这么多理论,下面给大家展示一下我现在项目中的一个策略模式的应用。场景是:我们需要从天猫、淘宝、京东、小红书、有赞等等六七十个平台拉取订单,保存到我们自己的数据库中,然后业务再去做统一的处理。策略模式在这里的应用就是,不同的平台会有不一样的拉取策略,每个平台提供的接口也不一样。

    首先我们定义了一个公共的接口,定义了一个获取执行器名称的方法。

/**
 * 执行器
 */
public interface Executor {
	
    /**
     * 获取具体的执行器名称
     * 
     * @return
     */
	String getName();
	
}

然后又定义了一个子接口,定义了几种拉取的方法

/**
 * 导入订单的执行器
 */
public interface ImportExecutor extends Executor {

    /**
     * 导入订单
     */
    void importOrderList();

    /**
     * 导入订单
     * @param syncDate 同步时间
     */
    void importOrderList(Date syncDate);

    /**
     * 导入订单
     * 
     * @param pageNo
     * @param syncDate
     * @return
     */
    boolean importOrderList(int pageNo, Date syncDate);
    
    /**
     * 根据平台订单号下载单个订单
     * @param platformSoCode
     */
    void importOrderByCode(String platformSoCode);
}

再然后就是重点了,给出了一个抽象的执行器

/**
 * 抽象订单导入执行器
 */
public abstract class AbstractImportExecutor implements ImportExecutor {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

/**
* 精华的方法,统一注册
*/
    @PostConstruct
    public void register() {
       //注意下面的方法中的this,一定是在运行的时候的子类
        ExecutorRegistryUtil.registerImportExecutor(getName(), this);
    }

    @Override
    public void importOrderList() {
    	if(!omsConstantConfig.getInvokeRemote()) {
    		return ;
    	}        
    	//上一次拉取时间
       Date syncDate=null;
        try {
            if (!importOrderList(1, syncDate)) {
                return;//如果本次拉取不成功,则不更新拉取时间
            }
            Update(nowDate);//更新拉取时间为当前时间
        } catch (Exception e) {
            logger.error("第三方的下载订单接口出现异常,平台[{}]订单下载失败,同步时间保持不变,error:{}", getName(),e.getMessage());
            return;//发生异常也不更新拉取时间
        }

    }

//公共的休眠方法,用于缓冲接口,不要频繁调用
    protected void sleep(long milliseconds) {
        try {
            TimeUnit.MILLISECONDS.sleep(milliseconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

    /**
     * 根据指定的日期范围导入订单
     * @param syncDate 上一次的导入时间
     */
    @Override
    public void importOrderList(Date syncDate) {
        importOrderList(1, syncDate);
    };


}

然后就是各个平台的子类了,反倒是简单了,截取一个天猫的瞅瞅

/**
 * 天猫导入Executor
 */
@Component
public class TmallImportExecutor extends AbstractImportExecutor {

    private static final int PAGE_SIZE = 50;
 
    @Override
    public void importOrderByCode(String platformSoCode) {
    	
        //调用天猫的接口拉取订单
    }

  

    @Override
    public String getName() {
        return TppPlatformEnum.TMALL.getKey();
    }


    
    @SuppressWarnings("unchecked")
    @Override
    public boolean importOrderList(int pageNo, Date syncDate) {
    	//调用天猫的接口拉取订单
        return true;
    }
}

最后一个类就是怎么获取具体的执行器了

/**
 * 执行器路由类
 * 
 */
@Component
public class ExecutorRouter {

    /**
     *  获取指定的订单处理器
     * 
     * @param platformShopCode
     * @return
     */
    public OrderExecutor getOrderExecutor(String platformShopCode) {
        check(platformShopCode);

        return ExecutorRegistryUtil.getOrderExecutor(platformShopCode);
    }

    private void check(String platformShopCode) {
        if (StringUtil.isEmpty(platformShopCode)) {
            throw new BizException("平台名称不能为空");
        }
    }
}

至于这几个类中的ExecutorRegistryUtil就是一个对map的再次封装,不用过于关心,实际项目中,可以使用一个final static map代替

转载于:https://my.oschina.net/hnqingping1255/blog/1861939

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值