当前位置: 首页 > news >正文

《java与模式》学习系列——享元模式

 

一、 享元(Flyweight)模式的结构

享元模式是对象的结构模式,享元模式以共享的方式高效地支持大量的细粒度对象。

享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)

一个内蕴状态是存储在享元对象内部的,并且是不会随环境改变而有所不同的。因此,一个享元可以具有内蕴状态并可以共享。

一个外蕴状态是随环境改变而改变的、不可共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。

外蕴状态不可以影响享元对象的内蕴状态。换句话说,它们是相互独立的。

享元模式可分为单纯享元模式和复合享元模式。

单纯享元模式所下图所示

复合享元模式的结构:

二、 享元模式的实现

单纯享元模式

public abstract class Flyweight {

         abstract public void operation(String state);

}

/**

 * 享元对象有一个内蕴状态,以一个Character类型的intrinsicState属性代表

 * 它的值应当在享元对象被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变。

 *如果享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,在使用享元对象时,

 *再由客户端传入享元对象。

 */

public class ConcreteFlyweight extends Flyweight {

 

         private Character intrinsicState = null;

         public ConcreteFlyweight(Character state){

                   this.intrinsicState = state;

         }

         @Override

         //外蕴状态作为参量传入方法中,改变方法的行为,但并不改变对象的内蕴状态

         public void operation(String state) {

                   System.out.println("/nIntrinsic State = "

                                     +intrinsicState+",Extrinsic State" + state);

         }

}

/**

 * 客户端不可以直接将具体享元类实例化,而必须通过一个工厂对象,

 * 利用一个factory()方法得到享元对象。一般而言,享元工厂对象在整个系统中只有一个

 * 因此可以使用单例模式。

 */

public class FlyweightFactory {

 

         private HashMap flies = new HashMap();

         private Flyweight lnkFlyweight;

        

         public FlyweightFactory(){}

         public Flyweight factory(Character state){

                   if(flies.containsKey(state))

                            return (Flyweight)flies.get(state);

                   else{

                            Flyweight fly = new ConcreteFlyweight(state);

                            flies.put(state, fly);

                            return fly;

                   }

         }

}

复合享元模式的实现

这里只列出ConcreteCompositeFlyweight的代码:

/**

 * 1、复合享元对象是由单纯的享元对象通过复合而成,因此它提供了add()这样的聚集管理方法。

 * 由于一个复合享元对象具有不同的聚集元素,这些聚集元素在复合享元对象被创建之后加入,

 * 这本身就意味着复合享元对象的状态是会改变的,因此复合享元对象是不能共享的。

 * 2、复合享元角色实现了抽象享元角色所规定的接口,也就是operation方法,这个方法有一个参量

 * 代表复合享元对象的外蕴状态,一个复合享元对象的所有单纯享元对象元素的外蕴状态 都是与复合

 * 享元对象含有的单纯享元对象的内蕴状态一般是不相等的,不然就没有使用价值了。

 */

public class ConcreteCompositeFlyweight extends Flyweight {

 

         private HashMap flies = new HashMap(10);

         private Flyweight flyweight;

         public ConcreteCompositeFlyweight() {}

         public void add(Character key,Flyweight fly){

                   flies.put(key, fly);

         }

         public void operation(String extrinsicState){

                   Flyweight fly = null;

                   for(Iterator it = flies.entrySet().iterator();it.hasNext();){

                            Map.Entry e = (Map.Entry)it.next();

                            fly = (Flyweight)e.getValue();

                            fly.operation(extrinsicState);

                   }

         }

}

三、 享元模式适用的情况

1、一个系统有大量的对象。

2、这些对象耗费大量的内存。

3、这些对象的状态中的大部分都可以外部化。

4、这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。

5、软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。

享元模式的优点在于它大幅度地降低内在中对象的数量。但是,它做到这一点所付出的代价也是很高的:一是享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。二是享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

四、享元模式举例

         一个文本编辑器往往会提供很多种字体,而通常的做法就是将每一个字母做成一个享元对象。享元对象的内蕴状态就是这个字母,而字母在文本中的位置和字模风格等其他信息则是外蕴状态。比如,字母a可能出现在文本的很多地方,虽然这些字母a的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。这样一来,字母对象就可以在整个系统中共享。

 

 

 

相关文章:

  • Java WebService 简单实例
  • java.lang.instrument使用
  • 《java与模式》学习系列——门面模式
  • 《java与模式》学习系列——桥梁模式
  • 《java与模式》学习系列——观察者模式
  • angularjs服务-service
  • 《java与模式》学习系列——迭代子模式
  • Werkzeug工具包学习-官方例子Shortly分析
  • 《java与模式》学习系列——责任链模式
  • iOS中的交换空间(swap space)
  • 《java与模式》学习系列——命令模式
  • Windows10中无法打开这个应用的解决方案
  • sqlbulkcopy 使用DataTable作为数据源的数据类型问题--来自数据源的String类型的给定值不能转换为指定目标列的类型 uniqueidentifier...
  • 《java与模式》学习系列——状态模式
  • debian终端菱形乱码修复
  • ES6指北【2】—— 箭头函数
  • 《剑指offer》分解让复杂问题更简单
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 2018一半小结一波
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • CentOS从零开始部署Nodejs项目
  • css的样式优先级
  • Gradle 5.0 正式版发布
  • JDK9: 集成 Jshell 和 Maven 项目.
  • laravel 用artisan创建自己的模板
  • node.js
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • ReactNativeweexDeviceOne对比
  • Spring声明式事务管理之一:五大属性分析
  • Vue ES6 Jade Scss Webpack Gulp
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 目录与文件属性:编写ls
  • 如何设计一个微型分布式架构?
  • 深度学习入门:10门免费线上课程推荐
  • 为什么要用IPython/Jupyter?
  • 物联网链路协议
  • 仓管云——企业云erp功能有哪些?
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #pragma 指令
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (六)激光线扫描-三维重建
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (原)本想说脏话,奈何已放下
  • (转)Unity3DUnity3D在android下调试
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .htaccess 强制https 单独排除某个目录
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .net反混淆脱壳工具de4dot的使用