项目地址:https://github.com/houbb/cache
1、数据结构
实现一个缓存数据结构
无法使用Map直接作为缓存的数据结构,我们可以自定义接口实现Map接口,实现自己的数据结构作为缓存。
一条缓存数据就是一个Cache对象,存储缓存数据的是Cache类中定义的Map属性,
/**
* 缓存接口
* @author binbin.hou
* @since 0.0.1
*/
public interface ICache<K, V> extends Map<K, V> {
}
2、淘汰策略
有很多种淘汰策略:FIFO,LFU,LRU
我们定义一个接口,ICacheEvict接口,每实现一种淘汰策略就实现一次ICacheEvict接口(可扩展的代码)
eg:FIFO
public class CacheEvictFIFO<K,V> implements ICacheEvict<K,V> {
/**
* queue 信息
* @since 0.0.2
*/
private Queue<K> queue = new LinkedList<>();
@Override
public void evict(ICacheEvictContext<K, V> context) {
final ICache<K,V> cache = context.cache();
// 超过限制,执行移除
if(cache.size() >= context.size()) {
K evictKey = queue.remove();
// 移除最开始的元素
cache.remove(evictKey);
}
// 将新加的元素放入队尾
final K key = context.key();
queue.add(key);
}
}
为了用户使用,封装一个引导类CacheBs,使用流式写法,提升用户体验
/**
* 缓存引导类
* @author binbin.hou
* @since 0.0.2
*/
public final class CacheBs<K,V> {
private CacheBs(){}
/**
* 创建对象实例
* @param <K> key
* @param <V> value
* @return this
* @since 0.0.2
*/
public static <K,V> CacheBs<K,V> newInstance() {
return new CacheBs<>();
}
/**
* map 实现
* @since 0.0.2
*/
private Map<K,V> map = new HashMap<>();
/**
* 大小限制
* @since 0.0.2
*/
private int size = Integer.MAX_VALUE;
/**
* 驱除策略
* @since 0.0.2
*/
private ICacheEvict<K,V> evict = CacheEvicts.fifo();
/**
* map 实现
* @param map map
* @return this
* @since 0.0.2
*/
public CacheBs<K, V> map(Map<K, V> map) {
ArgUtil.notNull(map, "map");
this.map = map;
return this;
}
/**
* 设置 size 信息
* @param size size
* @return this
* @since 0.0.2
*/
public CacheBs<K, V> size(int size) {
ArgUtil.notNegative(size, "size");
this.size = size;
return this;
}
/**
* 设置驱除策略
* @param evict 驱除策略
* @return this
* @since 0.0.2
*/
public CacheBs<K, V> evict(ICacheEvict<K, V> evict) {
this.evict = evict;
return this;
}
/**
* 构建缓存信息
* @return 缓存信息
* @since 0.0.2
*/
public ICache<K,V> build() {
CacheContext<K,V> context = new CacheContext<>();
context.cacheEvict(evict);
context.map(map);
context.size(size);
return new Cache<>(context);
}
}
fluent 流式写法:
一个对象的返回值是当前对象的引用,return this,这样多个方法就可以挨着修改当前对象的值。
使用方式(可以链式调用)
ICache<String, String> cache = CacheBs.<String,String>newInstance()
.size(2)
.build();
3、过期expire
和上面的淘汰功能一样,我们在api包中定义一个ICacheExpire
接口,每次我们想要实现一种过期策略的时候只需要实现一下ICacheExpire接口就行。如下:
定义一个expireMap,key 是对应的要过期的信息,value 存储的是过期时间。这个expireMap存的是需要过期的信息
/**
* 过期 map
*
* 空间换时间======
* @since 0.0.3
*/
private final Map<K, Long> expireMap = new HashMap<>();
//调用这个expire方法,可以设置过期时间
@Override
public void expire(K key, long expireAt) {
expireMap.put(key, expireAt);
}