设计模式(二十)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 简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑.为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂 ...
随机推荐
- 【django】分页
分页 1.简单分页 from django.conf.urls import url from django.contrib import admin from app01 import views ...
- 前端获取后台传输过来是数据 {张三:12} 解析为[object object],获取其中内容
昨天遇到前端传输过来的数据为[{张三:12},{李四:23}],后台用的是map格式,我在前端js中暂未找到直接调用对象内容的方法,故利用以下方法来获取: $.each(data.data,funct ...
- idea必备快捷键
ctrl + F: 在当前文件进行文本查找 ctrl + R: 在当前文件进行文本的替换 ctrl + Z: 撤销操作 ctrl + Y:删除光所在的行 或者选中的行 ctrl + D: 复制光标所在 ...
- 【SQL基础】char,nchar,vchar,nvchar之间的区别
(1) 定义: char: 固定长度,存储ANSI字符,不足的补英文半角空格. nchar: 固定长度,存储Unicode字符,不足的补英文半角空格 varchar: 可变长度 ...
- 一文彻底理解Redis序列化协议,你也可以编写Redis客户端
前提 最近学习Netty的时候想做一个基于Redis服务协议的编码解码模块,过程中顺便阅读了Redis服务序列化协议RESP,结合自己的理解对文档进行了翻译并且简单实现了RESP基于Java语言的解析 ...
- ELK 学习笔记之 Logstash之output配置
Logstash之output配置: 输出到file 配置conf: input{ file{ path => "/usr/local/logstash-5.6.1/bin/spark ...
- ELK 学习笔记之 Logstash之codec配置
Logstash之codec: Logstash处理流程: input=>decode=>filter=>encode=>output 分类: Plain编码: input{ ...
- Mysql数据类型TINYINT(1)与BOOLEAN踩坑记
熟悉Mysql的同学应该都知道,Mysql查询的boolean结果将输出为0或者1. 比如: ; 其输出结果为1. 查阅mysql官方文档仅找到如下描述: 11.10 Using Data Types ...
- 1.linux系统基础笔记(互斥量、信号量)
操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的windows系统已经开始运行了.如果问大家操作系统是什么?可能有的人会说操作系统就是windows,就是那些 ...
- .net cookie跨域请求指定请求域名
HttpCookie cookie = new HttpCookie("OrderApiCookie"); //初使化并设置Cookie的名称 cookie.HttpOnly = ...