工具类用单例模式仍是静态方法

上一篇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)大法复制多个工具类出来吗?

相关文章
相关标签/搜索