Android设计模式详解之享元模式

前言

享元模式是对象池的一种实现,用来尽可能减少内存使用量,适合用于可能存在大量重复对象的场景,来缓存可共享的对象;

定义:使用共享对象可有效地支持大量的细粒度的对象;

使用场景:

  • 系统中存在大量的相似对象;
  • 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;
  • 需要缓冲池的场景;

UML类图:
享元模式UML
Flyweight:享元对象抽象基类或者接口;

ConcreteFlyweight:具体的享元对象;

FlyweightFactory:享元工厂,负责管理享元对象池和创建享元对象;

示例代码

这里以读书进行举例,现在想阅读三国演义,但家里没有那就需要去买一本(享元工厂生产一本三国),读完了又想看水浒传,家里也没有那也需要去买一本(享元工厂生产一本水浒),回过头,又想要在读一遍三国,那就不再在去买了,直接找到原来的一本读就好了;

下面用享元模式实现:

  • 定义抽象享元类,Book
/**
 * 享元对象抽象基类
 */
interface Book {

    /**
     * readBook
     */
    fun readBook()
}
  • 定义具体享元对象,ConcreteBook
/**
 * 具体的书籍,具体的享元对象
 * @param name 图书名称
 */
class ConcreteBook(private val name: String) : Book {

    override fun readBook() {
        println("当前正在阅读:$name")
    }
}
  • 定义享元工厂,BookFactory
/**
 * 图书工厂
 */
object BookFactory {
    private val bookMaps = hashMapOf<String, Book>()


    fun getBook(name: String): ConcreteBook {
        return if (bookMaps.containsKey(name)) {
            println("家里有该书籍,直接找到")
            bookMaps[name] as ConcreteBook
        } else {
            println("家里没有该书籍,去买一本")
            val book = ConcreteBook(name)
            bookMaps[name] = book
            book
        }
    }
}
  • 编写调用类,验证功能
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //阅读三国演义
        val book1 = BookFactory.getBook("三国演义")
        book1.readBook()
        println("============================")
        //阅读水浒传
        val book2 = BookFactory.getBook("水浒传")
        book2.readBook()
        println("============================")
        //再读一遍三国演义
        val book3 = BookFactory.getBook("三国演义")
        book3.readBook()
    }
}

输出结果如下:

家里没有该书籍,去买一本
当前正在阅读:三国演义
============================
家里没有该书籍,去买一本
当前正在阅读:水浒传
============================
家里有该书籍,直接找到
当前正在阅读:三国演义

Android源码中的享元模式

  • Message,熟悉Android消息机制的同学,对于Message肯定不陌生,我们废话不多说,直接看源码:
public final class Message implements Parcelable {
  	
  	//message相关信息
    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    public Messenger replyTo;
	//可以看出message是一个链表结构
     Message next;

    public static final Object sPoolSync = new Object();
    private static Message sPool;
    //当前消息池的大小
    private static int sPoolSize = 0;
	//消息池中最多缓存50个message
    private static final int MAX_POOL_SIZE = 50;

    private static boolean gCheckRecycle = true;
	
	//如果sPool不为null,则从消息池中取消息,否则直接new Message()对象;
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
            	//从链表头取出Message
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
	
	//进行回收
  public void recycle() {
  		//如果当前正在使用,则调用recycle方法抛异常
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }
	
	//回收处理,清除相关信息,并将message插入到消息池中
    void recycleUnchecked() {
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;
        synchronized (sPoolSync) {
        	//判断消息池不满50时,将消息插入到链表头部
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }


}

从上面我们可以看出,调用Message.obtain()方法会从消息缓存池中取消息,这也是为什么推荐大家使用Message.obtain()方法而不是直接new Message()的原因,当Message被回收的时候,会清除相关信息,将消息存放到消息池中,从而实现消息的重复利用,典型的享元模式!!!

总结

优点:

  • 大幅度地降低内存中对象的数量,降低程序内存占用;

缺点:

  • 使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,使得程序的逻辑复杂化;
  • 将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值