java享元模式 | 如何共享对象

享元模式.png

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战java

欢迎来到今天的学习,今天咱们一块儿来学习下实现原理很简单,可是应用场景比较狭窄的一种模式----享元模式。多唠叨几句,我本月将会对java的设计模式精讲,欢迎点击头像,关注个人专栏,我会持续更新,加油!spring

系列文章:数据库

设计模式之单例模式设计模式

设计模式之工厂模式缓存

设计模式之建造者模式服务器

设计模式之代理模式markdown

设计模式之访问者模式ide

设计模式之适配器模式post

设计模式之命令者模式学习

java状态模式 | 随时随地监控状态改变

java观察者模式 | 如何通知事物的变化

java备忘录模式 | 如何记录历史信息

java迭代器模式模式 | 如何对各个元素进行访问

...持续更新中

话很少说,进入正题

享元模式

听到名字,享元,很抽象,这什么玩意,有什么用呢。 拆开来说,享,即共享,元,能够理解为元数据,内存当中的数据,对象。看来是共享对象喽

哈,立刻到七夕了,来共享下对象啊

image.png

哈哈,预祝你们七夕快乐!

回归正题,咱们先这样理解该模式,拿spring的常量池、数据库链接池、缓冲池等等这些都是享元模式的应用。

好比咱们每次建立字符串对象时,若是每次都建立一个新的字符串对象的话,内存开销会很大,因此若是第一次建立了字符串对象“七夕“,下次再建立相同的字符串”七夕“时,只是把它的引用指向”七夕“,这样就实现了”七夕“字符串再内存中的共享。

场景的话,能够想像王者荣耀,一台服务器链接了多个客户端(多个玩家),若是每一个进去的地图都要建立对象,那对象将无数啊。。。。因此这里要使用享元模式,将地图对象减小到几个实例。

官方是这样定义的:摒弃了在每一个对象中保存全部数据的方式,经过共享多个对象所共有的相同状态,从而让咱们能在有限的内存容量中载入更多对象。

咱们下面看张图

image.png

  • 享元类(Flyweight):定义了享元对象须要实现的公共操做方法。在该方法中会使用一个状态做为输入参数,也叫外部状态。

  • 享元工厂类(Flyweight Factory):管理一个享元对象类的缓存池

  • 可共享的具体享元类(ConcreteFlyweight):可以复用享元工厂内部状态并实现享元类公共操做的具体实现类。

  • 非共享的具体享元类(UnsharedConcreteFlyweight):不复用享元工厂内部状态,但实现享元类的具体实现类。

咱们下面拿王者荣耀场景例子实现下

场景代码展现

咱们都知道 王者荣耀分为战士,刺客,法师等等类型的英雄。下面用代码帮你深刻理解下

//定义英雄抽象类
 public abstract class HeroType {
     public abstract void init();  
 }
 
 
 
 //具体英雄类型
 public class ConcreteHeroType extends HeroType {

    private String typeName = "";

    public ConcreteHeroType(String typeName) {
        this.typeName = typeName;
    }

    @Override
    public void init() {
        System.out.println("英雄分类:" + typeName);
    }

}


//英雄工厂类
public class HeroTypeFactory {

    //用map做为存储
    private HashMap<String, ConcreteHeroType> pool = new HashMap<>();

    //得到英雄分类
    public HeroType getHeroTypeCategory(String key) {
        if(!pool.containsKey(key)) {
            pool.put(key, new ConcreteWebSite(key));
        }

        return (HeroType)pool.get(key);
    }

    //得到英雄分类总数
    public int getHeroTypeCount() {
        return pool.size();
    }

}
复制代码

咱们调用下,传几种类型的英雄,你们看下最后的个数

public class Client {
    public static void main(String[] args) {
        HeroTypeFactory factory = new HeroTypeFactory();

        HeroType fx = factory.getHeroTypeCategory("刺客");
        fx.init();

        HeroType fy = factory.getHeroTypeCategory("刺客");
        fy.init();

        HeroType fz = factory.getHeroTypeCategory("法师");
        fz.init();

        HeroType fa = factory.getHeroTypeCategory("法师");
        fa.init();

        HeroType fb = factory.getHeroTypeCategory("射手");
        fb.init();

        HeroType fc = factory.getHeroTypeCategory("射手");
        fc.init();

        System.out.println("英雄分类总数为:" + factory.getWebSiteCount());
    }
}
//输出
英雄分类:刺客
英雄分类:刺客
英雄分类:法师
英雄分类:法师
英雄分类:射手
英雄分类:射手

英雄分类总数为:3
复制代码

是否是原本该6个对象的,如今是3个。

因此说,享元模式本质上是经过建立更多的可复用对象的共有特征来尽量地减小建立重复对象的内存消耗。

OK 代码到这里就结束了

总结

咱们来看下java当中是如何用的 ,在 Java 中,享元模式一个经常使用的场景就是,使用数据类的包装类对象的 valueOf() 方法。好比,使用 Integer.valueOf() 方法时,实际的代码实现中有一个叫 IntegerCache 的静态类,它就是一直缓存了 -127 到 128 范围内的数值,以下代码所示,你能够在 Java JDK 中的 Integer 类的源码中找到这段代码。

image.png

你会发现,享元模式本质上在使用时就是找到不可变的特征,并缓存起来,当相似对象使用时从缓存中读取,以达到节省内存空间的目的。

优势:

一、第一个,减小内存消耗,节省服务器成本。 好比,当大量商家的商品图片、固定文字(如商品介绍、商品属性)在不一样的网页进行展现时,一般不须要重复建立对象,而是可使用同一个对象,以免重复存储而浪费内存空间。

二、聚合同一类的不可变对象,提升对象复用性

弦外之音

感谢你的阅读,若是你感受学到了东西,麻烦您点赞,关注。

我已经将本章收录在专题里,点击下方专题,关注专栏,我会天天发表干货,本月我会持续输入设计模式。

加油! 咱们下期再见!

相关文章
相关标签/搜索