背景

如果一个应用程序中使用了大量的对象,而大量的这些对象造成了恨得的存储开销时就应该考虑这个新是设计模式:享元模式。

1、使用意图

最大限度地减少了尽可能与其他类似的对象多的数据共享内存的使用,换句话说就是通过共享对象达到系统内维护的对象数量减少从而降低了系统的开销。因为是细粒度的控制,所以享元模式不是控制整个实例共享,那为何不用单例呢?而是只是共享对象的部分,不共享的部分称为对象的外部状态,需要外部动态修改这个共享对象。

2、生活实例

围棋的棋子,如果用编程去实现的话,势必要new出很多实例,整盘棋结束时估计内存也快爆了。如果使用享元模式,把围棋的共性共性出来,一些外部状态则外部动态控制,那么这个效率才是最优的。比如共享的应该是这个棋子的形状、大小、图片,外部动态修改的应该是棋子的位置。那么,只要定义两个类,黑棋和白棋,而且工厂中或说整个系统中也就只维护两个对象,一个是黑棋一个是白棋。

3、Java 例子(框架、JDK 、JEE)

Java字符串的维护就是一个享元模式的具体体现,我们知道String的实例有两种方式分别是:

String str =  "hello world";

String str2 = new String("hello world");

其中前者字面量的方式具体流程是这样的:首先查找String Pool中是否有“hello world”,如果不存在,那会在String Pool中创建一个“hello world”,同时将这个对象的引用返回给str;如果String Pool中存在,那么直接获取String Pool中的值返回;

后者new一个的对象的具体流程是这样的:首先查找String Pool中是否有“hello world”,如果不存在,那么同样在String Pool中创建一个,然后去堆(Heap)中创建一个“hello world”对象,并且把堆中的引用返回给str2;如果String Pool中存在了这个对象,那么,跳过String Pool中创建,而是直接在堆中去创建一个“hello world”然后把引用返回。

通过以上就会明白:

为什么 “hello world” == “hello world” 为 true ;

但是 new String("hello world") == new String("hello wrold") 为 false;

同时 “hello world” == new String("hello world") 也为false;

另外,String Pool 就是一个字符串的享元工厂,字面量的方式就是一个享元工厂模式。大家都知道StringBuffer的性能要好过String,StringBuilder的性能要好过StringBuffer,可是为什么还要用String呢?原因就在这里,他们说的性能是字符串修改的时候,而真正字符的基本操作,以及字符串从系统中获取的时候,String是最快的,维护的对象也最少。

4、模式类图

抽象享元(Flyweight)角色:享元接口,首先声明享元对象的方法,其次很重要的一点是要声明外部状态的操作,比如外部状态的传入方法,setState 等,因为具体享元对象虽然共享,但是也只是共享一部分,对于外部状态他是通过客户端动态替换,从而达到不共享的状态。

具体享元(ConcreteFlyweight)角色:具体的享元对象,共享的(享元工厂类对这种类的实例只产生一个,所以类似于单例模式,达到系统共享一个对象),之外还需要封装Flyweight的内部状态。

非共享的具体享元(UnsharedConcreteFlyweight)角色:非共享的具体享元对象,并不是所有的Flyweight对象都需要共享,非共享的享元对象通常是对共享享元对象的组合对象。享元工厂类不会维护这种类的实例,客户端只要需要这种类的实例,工厂就会从新生成一个最新的实例,所以他们是不共享实例。

享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元对象的接口。

客户端(Client)角色:享元客户端,主要的工作是维持一个对享元对象的引用,计算或存储享元对象的外部状态,也可以访问共享和非共享的享元对象。

5、模式优点

享元模式:运用共享技术有效地支持大量细粒度的对象。

享元模式可以避免大量非常相似类实例的开销,在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能实现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类数量。如果能把那些参数移到类实例的外面,在方法调用时将他们传递进来,就可以通过共享大幅度地减少单个实例的数目。

享元模式执行时所需的状态是有内部的可能也有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给他。

如果一个应用程序中使用了大量的对象,而大量的这些对象造成了恨得的存储开销时就应该考虑使用享元模式;还有就是对象的大多数状态可以是外部状态,如果删除对象的外部状态,你们可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。

6、与类似模式比较

享元角色是最小粒度的共享对象,其实个人觉得他的问题的还是挺多的,比如多线程控制下,共享的自然是没有问题,客户数不共享的可能就会发生错乱。

另外,享元模式中有两个不共享:

1)非共享的具体享元角色,他是说享元工厂不需要维护这个类的实例,每次客户端需要的时候都需要从新生成一个实例返回。那么,可以猜到享元工厂的实现就是一个Map 每次客户端需要实例的时候,看Map中的key是否存在,如果不存在那么new一个返回同时存储在Map中,如果已经在Map中存在那么直接从Map中获取返回。当然,还需要判断获取的实例是非共享的具体享元还是共享的,因为非共享的就是new一个返回,不需要Map去维护。

2)外部状态,所谓外部状态是针对共享具体角色来说的,因为是外部状态,所以,是外部进行控制的,每次外部需要的时候就更换这个状态,所以共享的具体亨元角色应该提供外部状态的修改方法。

和其他设计模式比较肯定就会想到单例模式,单例模式是整个系统就一个对象,而且这个对象没有外部状态,这就是二者最大的区别,可以说享元角色是比单例更细粒度的控制一个类的状态,单例只是一个享元的特殊情况。

陈臣java_小菜学设计模式——享元模式相关推荐

  1. Python设计模式-享元模式

    Python设计模式-享元模式 基于Python3.5.2,代码如下 #coding:utf-8class Coffee:name = ""price = 0def __init_ ...

  2. 10-Python与设计模式--享元模式

    10-Python与设计模式--享元模式 一.网上咖啡选购平台 假设有一个网上咖啡选购平台,客户可以在该平台上下订单订购咖啡,平台会根据用户位置进行线下配送.假设其咖啡对象构造如下: class Co ...

  3. 设计模式--享元模式实现C++

    /********************************* *设计模式--享元模式实现 *C++语言 *Author:WangYong *Blog:http://www.cnblogs.co ...

  4. 【设计模式】Java设计模式 - 享元模式

    [设计模式]Java设计模式 - 享元模式

  5. Unity设计模式——享元模式(附代码)

    Unity设计模式--享元模式(附源码) 享元Flyweight模式是什么 享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的 ...

  6. 第二十二章 Caché 设计模式 享元模式

    文章目录 第二十二章 Caché 设计模式 享元模式 定义 优点 使用场景 结构图 描述 完整示例 实体类 抽象享元角色 实现享元角色 享元工厂 调用 思考 第二十二章 Caché 设计模式 享元模式 ...

  7. JavaScript设计模式-享元模式

    JavaScript设计模式-享元模式 概念 例子 内部状态与外部状态 享元模式的通用结构 例子 总结 github仓库地址:点击 [设计模式例子](https://github.com/fanhua ...

  8. JAVA 设计模式 享元模式

    用途 享元模式 (Flyweight) 运用共享技术有效地支持大量细粒度的对象. 享元模式是一种结构型模式. 结构 图-享元模式结构图 Flyweight : 它是所有具体享元类的超类或接口,通过这个 ...

  9. java设计模式---享元模式

    Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自己 对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广 泛,遵循一定的编程模式,才能使自己的 ...

最新文章

  1. Android环境结构--安装Eclipse错
  2. python基础之数据类型与变量
  3. python中的encode()和decode()函数
  4. 没数据时y轴不显示_Matplotlib数据可视化
  5. 扒一扒面向对象编程的另一面
  6. 知识越分享,收获越多。
  7. Python学习笔记1:数据模型和特殊方法(魔术方法)
  8. chapter10--进程和计划任务管理
  9. java计算机毕业设计-智慧农业水果销售系统源码+mysql数据库+系统+lw文档+部署
  10. Excel:文本数字转换成数字的三种方法(转)
  11. 利用CouchDB未授权访问漏洞执行任意系统命令
  12. KeilMDK编译错误Error: L6218E: Undefined symbol __aeabi_assert (referred from xxx.o).
  13. for in在python中什么意思_Python for 循环中 in 关键字含义是什么?
  14. JavaScript之显示和隐藏图片
  15. spring boot网上购物系统毕业设计源码311236
  16. 这届90后女博士,对30岁不屑一顾
  17. ps快速将白底图片变为透明图片
  18. 怎样不改变图片像素把图片压缩到20KB以内?
  19. 成都天瑞地安:学java开发的一些重要知识
  20. 对加噪音前后的音频信号进行频谱分析

热门文章

  1. EQS(场景查询系统)
  2. 医疗大数据平台的标准化通迅协议构建和架构
  3. 3DMax提示:单位不匹配
  4. afn原理 ios_iOS AFNetworking网络框架详解
  5. leetcode 968 监控摄像头
  6. 华为路由器BGP联邦综合实验
  7. 杰理之手机同步时间接口【篇】
  8. C语言中从字符串中提取数字
  9. 揭秘:游戏开发的薪资情况和发展前景!
  10. 深入理解C# Unity List集合去除重复项 Distinct