美文网首页Android设计模式设计模式
享元模式-构建简易缓存池

享元模式-构建简易缓存池

作者: h2coder | 来源:发表于2020-09-27 17:08 被阅读0次

    本篇一起来写一个简易的缓存池,就是对象缓存池,就是设计模式中的享元模式。其实support包(Androidx一样也有)中提供了一个叫Pools的类,可能不是很多小伙伴知道,我也是偶然发现Glide使用它来做对象缓存复用,所以顺手看了一下源码,代码不多,但是很精华,我看完后手写了一遍源码,更改了获取和回收的方法名(相对原方法名更加容易懂一些),加了一些注释。

    Pool池接口

    首先我们先定义Pool池接口,目的是为了给后续不同策略的缓存池做一个统一的获取、回收方法,面向接口编程!

    • obtain()获取一个缓存对象,如果没有缓存对象复用,则返回null。
    • recycle(),回收一个对象到缓存池中,如果对象池已满,则不会回收,返回值,如果返回true,则回收成功,返回false,代表回收失败(回收时,池子已满则会出现)。
    public class CachePool {
        private CachePool() {
        }
    
        /**
         * 池接口
         */
        public interface Pool<T> {
            /**
             * 获取一个缓存对象,如果没有缓存对象复用,则返回null
             */
            T obtain();
        
            /**
             * 回收缓存对象到池子里,如果对象池已满,则不会回收
             *
             * @return 返回true,则回收成功,返回false,代表回收失败(回收时,池子已满则会出现)
             */
            boolean recycle(T instance);
        }
    }
    

    简单的对象池

    Pool只是一个接口,而SimpleCachePool为Pool接口的简单实现,它是不支持在多线程中保证线程安全的池子。如果不需要在多线程中使用,则使用它就可以。

    如果需要多线程中保证多线程安全,则需要使用下面的SynchronizedCachePool。

    • 构造时传入最大缓存大小,例如10,当缓存个数达到最大值,则不会将对象放入缓存池中缓存。
    /**
     * 简单的对象池
     */
    public static class SimpleCachePool<T> implements Pool<T> {
        /**
         * 对象池
         */
        private Object[] mPool;
        /**
         * 对象池大小
         */
        private int mPoolSize;
    
        /**
         * @param maxPoolSize 最大池容量
         */
        public SimpleCachePool(int maxPoolSize) {
            if (maxPoolSize <= 0) {
                throw new IllegalArgumentException("对象池大小必须大于0");
            }
            mPool = new Object[maxPoolSize];
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public T obtain() {
            //对象池中有对象可以复用时,才拿取最后一个对象返回
            if (mPoolSize > 0) {
                int lastIndex = mPoolSize - 1;
                T object = (T) mPool[lastIndex];
                //将对象从池子中移除
                mPool[lastIndex] = null;
                //同步池子大小
                mPoolSize--;
                return object;
            }
            return null;
        }
    
        @Override
        public boolean recycle(T instance) {
            //判断传入的对象是否在池子中,正常调用obtain()获取的对象会从池子中移除
            //如果判断还在池子中则可能是已经被回收过了,多次调用回收
            if (isInPool(instance)) {
                throw new IllegalStateException("对象已经在池子中了,请确保没有多次调用recycle()回收同一个对象");
            }
            //判断池子是否已满,如果满了,则不放入池子
            if (mPoolSize < mPool.length) {
                //将对象放回池子中复用
                mPool[mPoolSize] = instance;
                //同步池子大小
                mPoolSize++;
                return true;
            }
            return false;
        }
    
        /**
         * 判断对象是否在池子中
         *
         * @return 返回true则代表对象在池子中,返回false则不在
         */
        private boolean isInPool(T target) {
            for (Object object : mPool) {
                if (object == target) {
                    return true;
                }
            }
            return false;
        }
    }
    

    支持多线程同步的缓存池

    SynchronizedCachePool继承于SimpleCachePool,并在它的obtain()和recycle()中加入synchronized同步锁来保证线程安全。

    /**
     * 同步存取的缓存池,一般用于多线程需要保证线程安全的情况
     */
    public static class SynchronizedCachePool<T> extends SimpleCachePool<T> {
        /**
         * 对象锁
         */
        private final Object mLock = new Object();
    
        public SynchronizedCachePool(int maxPoolSize) {
            super(maxPoolSize);
        }
    
        @Override
        public T obtain() {
            synchronized (mLock) {
                return super.obtain();
            }
        }
    
        @Override
        public boolean recycle(T instance) {
            synchronized (mLock) {
                return super.recycle(instance);
            }
        }
    }
    

    简单使用

    使用则很简单了,使用obtain()方法获取缓存对象,如果获取不到,则自己创建,经过使用后,通过recycle()将对象回收即可。如果需要使用SynchronizedCachePool,则创建SynchronizedCachePool即可。

    //1、创建缓存池
    val cachePool = CachePool.SimpleCachePool<MessageModel>(10)
    //2、先从缓存池中获取,如果没获取到则创建
    var model: MessageModel? = cachePool.obtain()
    if (model == null) {
        model = ToiletModel()
    }
    
    ...一轮使用
    
    //3、进行回收
    cachePool.recycle(model)
    

    完整代码(直接拷贝去用)

    public class CachePool {
        private CachePool() {
        }
    
        /**
         * 池接口
         */
        public interface Pool<T> {
            /**
             * 获取一个缓存对象,如果没有缓存对象复用,则返回null
             */
            T obtain();
    
            /**
             * 回收缓存对象到池子里,如果对象池已满,则不会回收
             *
             * @return 返回true,则回收成功,返回false,代表回收失败(回收时,池子已满则会出现)
             */
            boolean recycle(T instance);
        }
    
        /**
         * 简单的对象池
         */
        public static class SimpleCachePool<T> implements Pool<T> {
            /**
             * 对象池
             */
            private Object[] mPool;
            /**
             * 对象池大小
             */
            private int mPoolSize;
    
            /**
             * @param maxPoolSize 最大池容量
             */
            public SimpleCachePool(int maxPoolSize) {
                if (maxPoolSize <= 0) {
                    throw new IllegalArgumentException("对象池大小必须大于0");
                }
                mPool = new Object[maxPoolSize];
            }
    
            @SuppressWarnings("unchecked")
            @Override
            public T obtain() {
                //对象池中有对象可以复用时,才拿取最后一个对象返回
                if (mPoolSize > 0) {
                    int lastIndex = mPoolSize - 1;
                    T object = (T) mPool[lastIndex];
                    //将对象从池子中移除
                    mPool[lastIndex] = null;
                    //同步池子大小
                    mPoolSize--;
                    return object;
                }
                return null;
            }
    
            @Override
            public boolean recycle(T instance) {
                //判断传入的对象是否在池子中,正常调用obtain()获取的对象会从池子中移除
                //如果判断还在池子中则可能是已经被回收过了,多次调用回收
                if (isInPool(instance)) {
                    throw new IllegalStateException("对象已经在池子中了,请确保没有多次调用recycle()回收同一个对象");
                }
                //判断池子是否已满,如果满了,则不放入池子
                if (mPoolSize < mPool.length) {
                    //将对象放回池子中复用
                    mPool[mPoolSize] = instance;
                    //同步池子大小
                    mPoolSize++;
                    return true;
                }
                return false;
            }
    
            /**
             * 判断对象是否在池子中
             *
             * @return 返回true则代表对象在池子中,返回false则不在
             */
            private boolean isInPool(T target) {
                for (Object object : mPool) {
                    if (object == target) {
                        return true;
                    }
                }
                return false;
            }
        }
    
        /**
         * 同步存取的缓存池,一般用于多线程需要保证线程安全的情况
         */
        public static class SynchronizedCachePool<T> extends SimpleCachePool<T> {
            /**
             * 对象锁
             */
            private final Object mLock = new Object();
    
            public SynchronizedCachePool(int maxPoolSize) {
                super(maxPoolSize);
            }
    
            @Override
            public T obtain() {
                synchronized (mLock) {
                    return super.obtain();
                }
            }
    
            @Override
            public boolean recycle(T instance) {
                synchronized (mLock) {
                    return super.recycle(instance);
                }
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:享元模式-构建简易缓存池

        本文链接:https://www.haomeiwen.com/subject/jpsluktx.html