当使用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模式的更多相关文章

  1. 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)

    设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...

  2. C#设计模式之二十策略模式(Stragety Pattern)【行为型】

    一.引言   今天我们开始讲"行为型"设计模式的第七个模式,该模式是[策略模式],英文名称是:Stragety Pattern.在现实生活中,策略模式的例子也非常常见,例如,在一个 ...

  3. php设计模式(二):结构模式

    上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式. 一.什么是结构型模式? 结构型模式是解析类和对象的内部结构和外部组 ...

  4. C#设计模式之十组合模式(Composite)【结构型】

    一.引言   今天我们要讲[结构型]设计模式的第四个模式,该模式是[组合模式],英文名称是:Composite Pattern.当我们谈到这个模式的时候,有一个物件和这个模式很像,也符合这个模式要表达 ...

  5. C#设计模式之十外观模式(Facade Pattern)【结构型】

    一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...

  6. JavaScript设计模式(二):工厂模式

    工厂模式模式的定义与特点 工厂模式(Factory Pattern)是编程中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.在工厂模式中,我们在创建对象时不会对 ...

  7. 适配器、工厂模式、线程池、线程组、互斥锁、Timer类、Runtime类、单例设计模式(二十四)

    1.多线程方法 * Thread 里面的俩个方法* 1.yield让出CPU,又称为礼让线程* 2.setPriority()设置线程的优先级 * 优先级最大是10,Thread.MAX_PRIORI ...

  8. Java进阶篇设计模式之十 ---- 访问者模式和中介者模式

    前言 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern).本篇则来学习下行为型模式的两个模式,访问者模式(Visito ...

  9. Java设计模式之十 ---- 访问者模式和中介者模式

    前言 2018年已经过去,新的一年工作已经开始,继续总结和学习Java设计模式. 在上一篇中我们学习了行为型模式的解释器模式(Interpreter Pattern)和迭代器模式(Iterator P ...

  10. 【C++设计模式二】工厂模式

    (1)定义3 简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑.为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂 ...

随机推荐

  1. 决策树(基于增益率)之python实现

    如图,为使用到的公式,信息熵表明样本的混乱程度,增益表示熵减少了,即样本开始分类,增益率是为了平衡增益准则对可取值较多的属性的偏好,同时增益率带来了对可取值偏小的属性的偏好,实际中,先用增益进行筛选, ...

  2. 基于Docker搭建大数据集群(二)基础组件配置

    主要内容 jdk环境搭建 scala环境搭建 zookeeper部署 mysql部署 前提 docker容器之间能免密钥登录 yum源更换为阿里源 安装包 微云分享 | tar包目录下 JDK 1.8 ...

  3. Spring MVC 梳理 - 四种HandlerMapping

    总结 (1)SpringMVC导入jar包,配置web.xml 这些都是基础的操作. (2)四种HandlerMapping:DefaultAnnotationHandlerMapping;Simpl ...

  4. 浅析java垃圾回收机制

    什么是java程序中的垃圾?什么这些垃圾又是怎样被回收的?为什么会被回收?不进行回收又会怎样?这些问题都是我们要在这篇博客中要解决的问题! 大家都知道,在c语言中,作为程序员,必须得考虑到去怎样回收已 ...

  5. .NET进阶篇-丑话先说,Flag先立--致青春

    作为开发者,工作了半年,也总觉得技术栈和刚毕业区别不大,用的技术还都是N年前的,每每看到新东西,也只心里哇塞惊叹一下,然后就回归于忙碌.怪自己的技术池太浅,热门的令人称奇的技术也都是在其他巨人的肩膀上 ...

  6. C++——数组与字符串

    目录 一.数组 1.1定义与初始化 1.1.1使用 1.1.2存储 1.1.3初始化 1.2作函数参数 1.3对象数组 1.3.1定义与访问 1.3.2初始化 1.3.3数组元素所属类的构造函数 二. ...

  7. 使用 Docker 让部署 Django 项目更加轻松

    作者:HelloGitHub-追梦人物 文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 之前一系列繁琐的部署步骤让我们感到痛苦.这些痛苦包括: 要去服务器上执行 n 条命令 ...

  8. Spring Boot 2.X(四):Spring Boot 自定义 Web MVC 配置

    0.准备 Spring Boot 不仅提供了相当简单使用的自动配置功能,而且开放了非常自由灵活的配置类.Spring MVC 为我们提供了 WebMvcConfigurationSupport 类和一 ...

  9. Dubbo和Zookerper的关系

    1.Dubbo的作用 Dubbo是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo提供一个框架解决这个问题.Dubbo基于RPC(Remote Procedur ...

  10. Linux入门(服务)

    LInux入门之 服务 服务介绍 常驻在内存中的程序,且可以提供一些系统或网络功能,那就是服务.比如: apache提供web服务 ftp提供文件下载上传服务 ssh提供了远程连接服务 防火墙提供了安 ...