提要
前几天做项目时,遇到一个类设计的问题,请教同事后,参考已有代码完成我需要的设计,这时回想设计模式,终于能体会它的意义了😁
问题
简单描述问题就是:
我希望有一个从Redis取特定String缓存的工具,可以依据不同参数做不同取缓存操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Pattern { public String getStringById (String keyPrefix, Long id) { ... A ... } private String getStringByIdWithRedisLock (String keyPrefix, Long id) { ... B ... } }
整体模板就是这样,现在问题是,在调用private
时B部分代码会依据参数不同走不同的调用,也就是我需要一种能利用这个模板,仅仅暴露出public
方法便可完成调用
可以想一想自己会怎么做?
解决
有想法了吗?
最简单最容易想到的就是设计接口,不同实现,构造器传入这样的
废话不多说上代码
1 2 3 4 5 6 7 8 9 10 11 12 public interface RedisService { String getStringById (String keyPrefix, Long id) ; String getStringByIdFromDB (Long id) ; }
设计接口,其实也不是很必要,直接设计抽象类也可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 @Component @Slf4j public abstract class AbstractRedisService implements RedisService { @Autowired StringRedisTemplate stringRedisTemplate; @Override public String getStringById (String keyPrefix, Long id) { String value = stringRedisTemplate.opsForValue().get(keyPrefix + id); if (StringUtils.isEmpty(value)) { log.info("缓存未命中。。。将要查询数据库。。。" ); value = getStringByIdWithRedisLock(keyPrefix, id); stringRedisTemplate.opsForValue().set(keyPrefix + id, value, RedisKeyConstants.DEFAULT_TTL, TimeUnit.SECONDS); return value; } log.info("缓存命中。。。直接读取。。。" ); return value; } private String getStringByIdWithRedisLock (String keyPrefix, Long id) { String key = keyPrefix + id; String uuid = UUID.randomUUID().toString(); Boolean lock = stringRedisTemplate.opsForValue() .setIfAbsent(RedisLockUtils.LOCK + key, uuid, RedisLockUtils.EXPIRE, TimeUnit.SECONDS); if (Objects.nonNull(lock) && lock) { log.info("获取分布式锁成功。。。" ); String value = "" ; try { value = this .getStringByIdFromDB(id); } catch (Exception e) { log.error("查询数据库失败" , e); } finally { stringRedisTemplate.execute(new DefaultRedisScript <>(RedisLockUtils.UNLOCK_LUA, Boolean.class) , Collections.singletonList(RedisLockUtils.LOCK + key), uuid); } return value; } else { log.info("获取分布式锁失败。。。等待重试。。。" ); try { Thread.sleep(RedisLockUtils.RETRY_TIME); } catch (InterruptedException e) { e.printStackTrace(); } return getStringByIdWithRedisLock(keyPrefix, id); } } @Override public abstract String getStringByIdFromDB (Long id) ; }
上面的已经很清晰了自己看就能明白
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Component @Slf4j public class UserRedisService extends AbstractRedisService { @Autowired UserMapper userMapper; @Override public String getStringByIdFromDB (Long id) { String userName = stringRedisTemplate.opsForValue().get(RedisKeyConstants.USER_NAME + id); if (!StringUtils.isEmpty(userName)) { return userName; } log.info("查询了数据库。。。" ); User user = userMapper.selectByPrimaryKey(id); if (Objects.isNull(user)) { return "" ; } stringRedisTemplate.opsForValue().set(RedisKeyConstants.USER_NAME + id, user.getUserName() , RedisKeyConstants.DEFAULT_TTL, TimeUnit.SECONDS); return user.getUserName(); } public void deleteUserName (Long id) { stringRedisTemplate.delete(RedisKeyConstants.USER_NAME + id); } }
抽象类的一个实现
完成这个设计还是很自豪,转头一想,这是不是哪种设计模式啊?
果然,查到了,它属于设计模式-行为模式-模板模式,感兴趣的可以查资料好好看一看
小结
果然呐,一些设计模式只有你在生产工作中才会有更深的体会和理解!