【原】抽象的な汎用テンプレートによる優雅な設計拡張コード

11467 ワード

前言:


コードクラウド上のオープンソースの優れたプロジェクトを学ぶことで、より良い設計方法を発見したので、ここでまとめます。


プロセス:


大体の流れはサービス層からデータを取得し、まずRedisを経由し、Redisにデータがなければdbをクエリーし、最後にデータをRedisに戻す.
簡単に見えるステップで、実際には異なるスタイルの方法を書くことができます.一般的に最初に考えられるのは、次のような(プロセス向けの偽コード)にほかならない.
    
Object val = redisutils.get("key");
if(val == null || val == ""){
    Object obj = userdaoMapper.getUserById("key");
BeanUtils.cover(obj,User.class); }
else{ return val; }

上の疑似コードは一見分かりやすいですが、実際の開発では、特にマルチモジュール開発の場面でこのようなコードが大量にあふれているとメンテナンスが難しく、大量の重複コードを書くだけでなく、異なるエンティティタイプを変換する必要がありますが、この問題を回避するにはどうすればいいのでしょうか.1つ目の方法はAOPに詳しいことですが、ここではAOPを紹介するつもりはなく、ブログのタイトルに示すように(抽象的な汎用テンプレートを通じて).
 

実装方法:


#まずキャッシュ抽象テンプレートを作成します。この抽象テンプレートはベースクラスに属し、汎用的に定義し、後続の拡張を容易にすることが望ましいです。ベースクラスで最も核心的な機能を実現した--』redisからデータを取得し、あれば取り出し、なければdbから取得する。  

public abstract class CacheWorker

{ private static Log logger = LogFactory.getLog(CacheWorker.class); @Autowired protected RedisUtil redisUtil; /** * get * * @param params * @param expireSeconds * @return * @throws SQLException */ @SuppressWarnings("unchecked") public R get(P params, Class clazz) { // key, String key = getKey(params); Object res = getCache(key, clazz); // if (res != null) { if (logger.isDebugEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(" redis (key:{").append(key).append("})"); logger.debug(sb.toString()); } return (R) res; } if (logger.isDebugEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(" redis (key:{").append(key).append("}), DB ."); logger.debug(sb.toString()); } // DB R dataFromDb = getDataWhenNoCache(params); // cache if (dataFromDb != null) { setCache(getExpireSeconds(), key, dataFromDb); } return dataFromDb; } /** * * * @return */ protected abstract int getExpireSeconds(); /** * set * * @param expireSeconds * @param key * @param dataFromDb */ protected void setCache(int expireSeconds, String key, R dataFromDb) { redisUtil.set(key, dataFromDb, expireSeconds); } /** * set * * @param key * @return */ protected Object getCache(String key, Class clazz) { // return redisUtil.get(key, clazz); } public void del(P params) { // key, String key = getKey(params); redisUtil.delete(key); } /** * , DB * * @param params * @return * @throws SQLException */ protected abstract R getDataWhenNoCache(P params); /** * key * * @param params * @return */ protected abstract String getKey(P params);


     

#サブクラスを作成し、上のベースクラスを継承します。このサブクラスは特定の作業コンポーネントです。このサブクラスで自分の方法を拡張します。

@Component
public class GoodsInfoCacheWorker extends CacheWorker
{
    @Autowired
    private GoodsMapper goodsMapper;

    @Override
    protected Goods getDataWhenNoCache(Integer goodsId)
    {
        return goodsMapper.selectByPrimaryKey(goodsId);
    }

    @Override
    protected String getKey(Integer goodsId)
    {
        String key = MessageFormat.format(CommonConstant.RedisKey.GOODS_INFO_BY_ID, new Object[] { goodsId });
        return key;
    }

    @Override
    protected int getExpireSeconds()
    {
        return CommonConstant.RedisKeyExpireSeconds.GOODS_STORE_BY_ID;
    }

}

         

#呼び出し元は、Spring注入後に抽象タッチボードクラスのgetメソッドを直接呼び出し、keyと対応するClassクラスの2つのパラメータを入力します。

    @Autowired
    private GoodsInfoCacheWorker goodsInfoCacheWorker;


    public String getGoodsRandomName(Integer goodsId)
    {
        Goods goods = goodsInfoCacheWorker.get(goodsId, Goods.class);
        long now = System.currentTimeMillis();

        //
        if (goods.getStartTime().getTime() < now && now < goods.getEndTime().getTime())
        {
            return goods.getRandomName();
        }

        return StringUtils.EMPTY;
    }

 
  ·