工具類用單例模式仍是靜態方法

上一篇blog中將工具類寫成了靜態類(全部的方法都是靜態方法),今天發現了這種方式的弊端。且聽我慢慢道來:java

今天須要重構一個實習生的代碼,邏輯很簡單,消費kafka,提取須要的內容寫入ssdb,他將配置信息直接寫到了項目中,而咱們須要區分本地、測試、生產環境,不現實,這就是重構的緣由。redis

這就要求我必須封裝kafka消費、jedis(ssdb兼容jedis)讀寫工具類。原本打算照着前幾天的作,可是想着參照參照大牛的代碼,學習學習提高本身。spring

打開大牛的代碼,發現全部相似的工具類都是非靜態的,而是spring注入(默認是單例模式)那麼問題來了:工具類用單例模式仍是靜態類好?ide

因而又是上網搜,最後經過知乎、博客等途徑,主要了解了一下區別:工具

說靜態類好的:學習

  1. 靜態類不用引用就能調用,而單例須要有對象的引用,所以節約資源(我以爲這個影響微乎其微,能夠忽略)
  2. 靜態類方便,隨處可用;而單例必須有引用,須要注入或者new(是有點麻煩,我上次寫靜態類也是由於這個緣由)

說單例好的:測試

  1. 單例模式的類是普通的類,它具備面向對象的特性,方便擴展
  2. 對於有配置的工具類,能夠輕鬆的建立多個不一樣配置的單例對象(想起我主導的另外一個項目就存在5-6個redis數據源,若是使用靜態類就是災難)

所以,我得出如下結論:this

  • 若是沒有配置信息的工具類,固然是靜態類好,隨處調用,不需引用爽得不要不要的。好比Math.abs(),若是寫個單例,可能全世界都要笑話你了。
  • 若是有配置信息的工具類,最好仍是使用單例模式吧,這樣之後若是有多個數據源,你會感謝你本身。

下面貼一個有配置信息的工具類,並以此分析:code

代碼1server

public interface JedisResourceFactory {

    public Jedis getResource();
}

代碼2

public class JedisPoolResourceFactory implements JedisResourceFactory, DisposableBean {

    private static final int DEFAULT_PORT = 3306;
    private JedisPoolConfig jedisPoolConfig;
    private String host;
    private int port;
    private JedisPool jedisPool;

    public JedisPoolResourceFactory(JedisPoolConfig jedisPoolConfig, String host) {
        this(jedisPoolConfig, host, DEFAULT_PORT);
    }

    public JedisPoolResourceFactory(JedisPoolConfig jedisPoolConfig, String host, int port) {
        this.jedisPoolConfig = jedisPoolConfig;
        this.host = host;
        this.port = port;
        init();
    }

    private void init() {
        this.jedisPool = new JedisPool(this.jedisPoolConfig, this.host, this.port);
    }

    @Override
    public Jedis getResource() {
        return jedisPool.getResource();
    }

    @Override
    public void destroy() throws Exception {
        jedisPool.close();
    }
}

代碼3

public class JedisServer {

    JedisResourceFactory jedisResourceFactory;

    public JedisServer(JedisResourceFactory jedisResourceFactory) {
        this.jedisResourceFactory = jedisResourceFactory;
    }

    abstract class Executor<T>  {
        Jedis jedis;

        public Executor(JedisResourceFactory jedisResourceFactory) {
            this.jedis = jedisResourceFactory.getResource();
        }

        abstract T execute();

        public T getResult() {
            T result = null;
            try {
                result = execute();
            } catch (Exception e) {
                throw new RuntimeException("Redis execute Error", e);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    jedis = null;
                }
            }
            return result;
        }
    }


    public Long lpushStrings(final String key, final String[] values) {
        return new Executor<Long>(jedisResourceFactory) {
            @Override
            Long execute() {
                return jedis.lpush(key, values);
            }
        }.getResult();
    }


}

首先上面這3段代碼爲了訪問redis,先經過redisPool獲取redis,而後訪問redis。(以上工具類僅用來訪問單機redis,redis集羣須要經過其餘方式

假如咱們如今有一個redis源,那麼實例化一個JedisPoolResourceFactory對象factory1,而後實例化一個JedisServer的對象jserver1。

又一天咱們多了一個redis源,一樣再實例化一個JedisPoolResourceFactory對象factory2,而後實例化一個JedisServer的對象jserver2。這樣咱們就能夠輕鬆的經過不一樣的對象訪問不一樣的redis。

若是使用靜態的工具類,難道CV(ctrl c , ctrl v)大法複製多個工具類出來嗎?

相關文章
相關標籤/搜索