设计模式(二十)Flyweight模式
当使用new关键字生成类的实例时,需要给其分配足够的内存空间。当程序中需要大量对象时,如果都是用new关键字来分配内存,将会消耗大量内存空间。Flyweight模式就是尽量避免new出实例,而是通过尽量共用已经存在的实例。

示例程序类图。这个示例程序要实现的就是给定传统的普通数字字符可以得到对应数字的“大型字符”。
package bigjunoba.bjtu.flyweight; import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException; public class BigChar {
//字符名字
private char charname;
//大型字符对应的字符串,就是txt文本里面的内容
private String fontdata;
//构造函数
public BigChar(char charname) {
this.charname = charname;
try {
BufferedReader bufferedReader = new BufferedReader(
new FileReader("big" + this.charname + ".txt")
);
String line;
StringBuffer stringBuffer = new StringBuffer();
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line);
stringBuffer.append("\n");
}
bufferedReader.close();
this.fontdata = stringBuffer.toString(); } catch (IOException e) {
this.fontdata = this.charname + "?";
}
}
//显示大型字符
public void print() {
System.out.print(fontdata);
}
}
BigChar类是表示“大型字符”的类。这个类的构造函数中,首先会读取给定数字字符对应的.txt文件,然后将读取到的文件先存到缓冲区bufferedReader中,最后再把bufferedReader中的内容存到stringBuffer中,并用fontdata字段来保存。由于“大型字符”会消耗很多内存,因此我们需要考虑如何共享BigChar类的实例。
package bigjunoba.bjtu.flyweight;
import java.util.HashMap;
public class BigCharFactory {
// 管理已经生成的BigChar的实例
private HashMap<String, BigChar> pool = new HashMap<String, BigChar>();
// Singleton模式
private static BigCharFactory singleton = new BigCharFactory();
// 构造函数
private BigCharFactory() {
}
// 获取唯一的实例
public static BigCharFactory getInstance() {
return singleton;
}
// 生成(共享)BigChar类的实例
public synchronized BigChar getBigChar(char charname) {
BigChar bc = (BigChar)pool.get("" + charname);
if (bc == null) {
bc = new BigChar(charname); // 生成BigChar的实例
pool.put("" + charname, bc);
}
return bc;
}
}
BigCharFactory类是生成BigChar类的实例的工厂。它实现了共享实例的功能。pool字段中保存的是已经生成的BigChar类的实例,并用HashMap来管理“字符串--实例”的对应关系。pool.put("" + charname, bc);中的put方法可以将某个字符串与一个实例关联起来,就可以通过键来获取它对应的值。getInstance方法用于获取BigCharFactory类的实例,这里是Singleton模式。getBigChar是该模式的核心,首先通过get方法查找输入的字符串是否存在对应的BigChar类的实例,如果没有就创建一个,并记录对应关系,如果有就直接将对应的实例返回。
这里为什么要用synchronized关键字,给出如下解答:


package bigjunoba.bjtu.flyweight;
public class BigString {
// “大型字符”的数组
private BigChar[] bigchars;
// 构造函数
public BigString(String string) {
bigchars = new BigChar[string.length()];
BigCharFactory factory = BigCharFactory.getInstance();
for (int i = 0; i < bigchars.length; i++) {
bigchars[i] = factory.getBigChar(string.charAt(i));
}
}
// 显示
public void print() {
for (int i = 0; i < bigchars.length; i++) {
bigchars[i].print();
}
}
}
BigString类表示由BigChar组成的“大型字符串”的类。bigchars字段中保存的是BigChar类的实例。factory.getBigChar(string.charAt(i));这句话就实现了共享实例。
package bigjunoba.bjtu.flyweight;
public class Main {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java Main digits");
System.out.println("Example: java Main 1212123");
System.exit(0);
}
BigString bs = new BigString(args[0]);
bs.print();
}
}
Main类作为测试类,很简单就不解释了。
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
....######......
..##......##....
..##............
..########......
..##......##....
..##......##....
....######......
................
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
..##########....
..##......##....
..........##....
........##......
......##........
......##........
......##........
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
..##########....
..##............
..##............
..########......
..........##....
..##......##....
....######......
................
测试结果如上图。

BigString类的实例的bigchars字段对应Bigchar类的实例。

Flyweight模式的类图。
关于Flyweight模式有以下需要说明的:
1.如何判断可以共享实例,就是如果要改变被共享的对象,就会对多个地方产生影响。也就是说,一个实例的改变会同时反映到所有使用该实例的地方。因此,使用该模式时需要精挑细选出那些真正应该在多个地方共享的字段。
2.Intrinsic信息被称为应当共享的信息,而Extrinsic信息被称为不应当共享的信息。
3.注意不要让被共享的实例被垃圾回收器回收了:在示例程序中,使用HashMap类管理已经生成的BigChar实例。在Java程序中可以通过new关键字分配内存空间。如果分配了过多内存,就会导致内存不足。这是,Java虚拟机就会开始垃圾回收处理。它会查看自己的内存空间中是否存在没有被使用的实例,如果存在就释放该实例,这样就可以护手可用的内存空间。如果其他对象引用了该实例,垃圾回收器就会认为“该实例正在被使用”,不会将其当做垃圾回收掉。在示例程序中,pool字段负责管理已经生成的BigChar的实例,因此,只要是pool字段管理的BigChar的实例,就不会被看作垃圾,即使该BigChar的实例实际上已经不再被BigString类的实例所使用。也就是说,只要生成了一个BigChar的实例,就会长期驻留在内存中。在示例程序中,字符串的显示处理很快就结束了,因此不会发生内存不足的问题。但是如果应用程序需要长期运行或是需要以有限的内存来运行,那么在设计程序时,开发人员就必须时刻警惕“不要让共享的实例被垃圾回收器回收了”。虽然不能显示删除实例,但可以删除对实例的引用。要想让实例可以被垃圾回收器回收掉,只需要显式地将其置于管理对象外即可。例如,只要从HashMap中移除该实例的Entry,就删除了对该实例的引用。
4.这里还要提出的是,虽然共享实例可以减少内存使用量,但是时间也是一种资源,使用new关键字生成实例会花费时间。使用Flyweight模式共享实例可以减少使用new关键字生成实例的次数,这样就可以提高程序运行速度。文件句柄和窗口句柄等也是一种资源,如果不共享实例,应用程序在运行时很容易就会达到资源极限而导致崩溃,因为操作系统中,可以同时使用的文件句柄和窗口句柄是有限制的。
设计模式(二十)Flyweight模式的更多相关文章
- 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)
设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...
- C#设计模式之二十策略模式(Stragety Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第七个模式,该模式是[策略模式],英文名称是:Stragety Pattern.在现实生活中,策略模式的例子也非常常见,例如,在一个 ...
- php设计模式(二):结构模式
上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式. 一.什么是结构型模式? 结构型模式是解析类和对象的内部结构和外部组 ...
- C#设计模式之十组合模式(Composite)【结构型】
一.引言 今天我们要讲[结构型]设计模式的第四个模式,该模式是[组合模式],英文名称是:Composite Pattern.当我们谈到这个模式的时候,有一个物件和这个模式很像,也符合这个模式要表达 ...
- C#设计模式之十外观模式(Facade Pattern)【结构型】
一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...
- JavaScript设计模式(二):工厂模式
工厂模式模式的定义与特点 工厂模式(Factory Pattern)是编程中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.在工厂模式中,我们在创建对象时不会对 ...
- 适配器、工厂模式、线程池、线程组、互斥锁、Timer类、Runtime类、单例设计模式(二十四)
1.多线程方法 * Thread 里面的俩个方法* 1.yield让出CPU,又称为礼让线程* 2.setPriority()设置线程的优先级 * 优先级最大是10,Thread.MAX_PRIORI ...
- Java进阶篇设计模式之十 ---- 访问者模式和中介者模式
前言 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern).本篇则来学习下行为型模式的两个模式,访问者模式(Visito ...
- Java设计模式之十 ---- 访问者模式和中介者模式
前言 2018年已经过去,新的一年工作已经开始,继续总结和学习Java设计模式. 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator P ...
- 【C++设计模式二】工厂模式
(1)定义3 简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑.为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂 ...
随机推荐
- 大文件分割、命令脚本 - Python
日志文件分割.命名 工作中经常会收到测试同学.客户同学提供的日志文件,其中不乏几百M一G的也都有,毕竟压测一晚上产生的日志量还是很可观的,xDxD,因此不可避免的需要对日志进行分割,通常定位问题需要针 ...
- 计算机视觉(二)-opencv之createTrackbar()详解
摘要: 我学习openCV3看的是<学习openCV3>这本书,很厚的一本,不知道是不是因为自己看的还不是很多,个人觉得里面的有些重要函数讲的不是很详细,比如createTrackbar( ...
- 02-13 Softmax回归
目录 Softmax回归 一.Softmax回归详解 1.1 让步比 1.2 不同类之间的概率分布 1.3 目标函数 1.4 目标函数最大化 二.Softmax回归优缺点 2.1 优点 2.2 缺点 ...
- 微信小程序路由跳转
微信小程序路由跳转 1.wx.switchTab(Object object) 这里的tabBar是底下的导航栏指定的页面, 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 参数 O ...
- Springboot 系列(十四)迅速启用 HTTPS 加密你的网站
1. 获取 HTTPS 证书 正常情况下 HTTPS 证书需要从证书授权中心获得,这样获得的证书才具有公信力,也会被各种浏览器客户端所认可.常见的证书品牌如 Symantec,GeoTrustm,Tr ...
- EasyExcel 轻松灵活读取Excel内容
写在前面 Java 后端程序员应该会遇到读取 Excel 信息到 DB 等相关需求,脑海中可能突然间想起 Apache POI 这个技术解决方案,但是当 Excel 的数据量非常大的时候,你也许发现, ...
- 自学web前端达到什么水平,才能满足求职的标准?
大多数野生程序员最棘手的问题就是如何依靠技术解决温饱,通俗来讲就是技术折现的问题. 如果是单纯出于兴趣,或者只是为了突击某一阶段或者某一项目技术壁垒,不跟就业挂钩的自学倒也是无关痛痒.但是当上岗成为自 ...
- PHP each
1.函数的作用:遍历数组元素 2.函数参数: @params array &$array 3.例子: <?php $arr = ['Boy','Girl']; while(list($k ...
- [LUOGU1437] 敲砖块
题目描述 在一个凹槽中放置了 n 层砖块.最上面的一层有n 块砖,从上到下每层依次减少一块砖.每块砖 都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示. 14 15 4 3 23 33 33 7 ...
- Halcon一日一练:获取程序运行时间
很多时候,我们需要知道每个函数的运算周期,以提高程序的运行效率.知道运行时间对于图像算法处理很重要 Halcon提供相关的算子,我们先来看代码: **获取图像处理时间 read_image(Image ...