小菜学设计模式——享元模式

背景

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

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、模式类图

  1. 抽象享元(Flyweight)角色:享元接口,首先声明享元对象的方法,其次很重要的一点是要声明外部状态的操作,比如外部状态的传入方法,setState 等,因为具体享元对象虽然共享,但是也只是共享一部分,对于外部状态他是通过客户端动态替换,从而达到不共享的状态。
  2. 具体享元(ConcreteFlyweight)角色:具体的享元对象,共享的(享元工厂类对这种类的实例只产生一个,所以类似于单例模式,达到系统共享一个对象),之外还需要封装Flyweight的内部状态。
  3. 非共享的具体享元(UnsharedConcreteFlyweight)角色:非共享的具体享元对象,并不是所有的Flyweight对象都需要共享,非共享的享元对象通常是对共享享元对象的组合对象。享元工厂类不会维护这种类的实例,客户端只要需要这种类的实例,工厂就会从新生成一个最新的实例,所以他们是不共享实例。
  4. 享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元对象的接口。
  5. 客户端(Client)角色:享元客户端,主要的工作是维持一个对享元对象的引用,计算或存储享元对象的外部状态,也可以访问共享和非共享的享元对象。

5、模式优点

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

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

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

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

6、与类似模式比较

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

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

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

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

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

时间: 2024-08-05 14:13:44

小菜学设计模式——享元模式的相关文章

设计模式——享元模式

Flyweight 直译为蝇量.就其表示的模式来说,翻译成享元,确实是不错的 package designpattern.structure.flyweight; public interface Flyweight { void action(int arg); } package designpattern.structure.flyweight; public class FlyweightImpl implements Flyweight { public void action(int

8. 星际争霸之php设计模式--享元模式

题记==============================================================================本php设计模式专辑来源于博客(jymoz.com),现在已经访问不了了,这一系列文章是我找了很久才找到完整的,感谢作者jymoz的辛苦付出哦! 本文地址:http://www.cnblogs.com/davidhhuan/p/4248186.html============================================

深入浅出设计模式——享元模式(Flyweight Pattern)

模式动机 面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.享元模式正是为解决这一类问题而诞生的.享元模式通过共享技术实现相同或相似对象的重用. 在享元模式中可以共享的相同内容称为内部状态(Intrinsic State),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有

[工作中的设计模式]享元模式模式FlyWeight

一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 享元模式:主要为了在创建对象时,对共有对象以缓存的方式进行保存,对外部对象进行单独创建 模式要点: 1.享元模式中的对象分为两部分:共性部分和个性化部分,共性部分就是每个对象都一致的或者多个对象可以共享的部分,个性化部分指差异比较大,每个类均不同的部分 2.共性部分的抽象就是此模

设计模式-享元模式

***********************************************声明****************************************************** 原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不足,欢迎斧正! *******************************************

iOS设计模式——享元模式

公共交通(如公共汽车)已有一百多年的历史了.大量去往相同方向的乘客可以分担保有和经营车辆(如公共汽车)的费用.公共汽车有多个站台,乘客沿着路线在接近他们目的地的地方上下车.到达目的地的费用仅与行程有关.跟保有车辆相比,乘坐公共汽车要便宜得多.这就是利用公共资源的好处. 在面向对象软件设计中,我们利用公共对象不仅能节省资源还能提高性能.比方说,某个人物需要一个类的一百万个实例,但我们可以把这个类的一个实例让大家共享,而把某些独特的信息放在外部,节省的资源可能相当可观(一个实例与一百万个实例的差别)

设计模式——享元模式详解

0. 前言 写在最前面,本人的设计模式类博文,建议先看博文前半部分的理论介绍,再看后半部分的实例分析,最后再返回来复习一遍理论介绍,这时候你就会发现我在重点处标红的用心,对于帮助你理解设计模式有奇效哦~本文原创,转载请注明出处为SEU_Calvin的博客. 春运买火车票是一件疯狂的事情,同一时刻会有大量的查票请求涌向服务器,服务器必须做出应答来满足我们的购票需求.试想,这些请求包含着大量的重复,比如从A地到B地的车票情况,如果每次都重复创建一个车票查询结果的对象,那么GC任务将非常繁重,影响性能

C#设计模式-享元模式

前言 最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高.保证代码可靠性.所谓设计模式,我找了下定义:是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.毫无疑问,设计模式于己于他人于系统都是多赢的:设计模式使代码编制真正工程化:设计模式是软件工程的基石脉络,如同大厦的结构一样. 为什么要提倡“Design Pattern(设计模式)”? 根本原因是为了代码复用,增加可维护性.因此这次我们来学习下设计模式,最后会通过C#语言来实现这些设计模式作为例子,深刻理解其中的

PHP设计模式——享元模式

声明:本系列博客参考资料<大话设计模式>,作者程杰. 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分状态是可以分享.常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元. UML类图: 角色分析: 享元工厂角色(FWFactory):创建并管理BlogModel对象. 所有具体享元父接口角色(BolgModel):接受并作用与外部状态. 具体享元角色(JobsBlog)