当使用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. 手把手教你搭建Pytest+Allure2.X环境详细教程,生成让你一见钟情的测试报告(非常详细,非常实用)

    简介 宏哥之前在做接口自动化的时候,用的测试报告是HTMLTestRunner,虽说自定义模板后能满足基本诉求,但是仍显得不够档次,高端,大气,遂想用其他优秀的report框架替换之.一次偶然的机会, ...

  2. 编程范式 --- 函数式编程(Funtional Programming,简称FP)

    函数式编程(Funtional Programming,简称FP)是一种编程范式,也就是如何编写程序的方法论 主要思想:把计算过程尽量分解成一系列可复用函数的调用 主要特征:函数是"第一等公 ...

  3. 2019-2020-1 20199303 《Linux内核原理分析》 第一周作业

    2019-2020-1 20199303 <Linux内核原理分析> 第一周作业 1. 环境准备 在众多的Linux发行版中,Ubuntu,小红帽还有类Unix系统的BSD系统,我选择了目 ...

  4. 【JVM 知识体系框架总结】

    JVM 内存分布 线程共享数据区: 方法区->类信息,静态变量 堆->数组对象 线程隔离区 虚拟机栈-> 方法 本地方法栈->本地方法库 native 堆.程序计数器 JVM ...

  5. Two progressions CodeForce 125D 思维题

    An arithmetic progression is such a non-empty sequence of numbers where the difference between any t ...

  6. <机器学习>无监督学习算法总结

    本文仅对常见的无监督学习算法进行了简单讲述,其他的如自动编码器,受限玻尔兹曼机用于无监督学习,神经网络用于无监督学习等未包括.同时虽然整体上分为了聚类和降维两大类,但实际上这两类并非完全正交,很多地方 ...

  7. .Net Core 商城微服务项目系列(十二):使用k8s部署商城服务

    一.简介 本篇我们将会把商城的服务部署到k8s中,同时变化的还有以下两个地方: 1.不再使用Consul做服务的注册和发现,转而使用k8s-dns来实现. 2.不再使用Ocelot作为业务网关,使用T ...

  8. .Net Core与Vue.js模块化前后端分离快速开发解决方案(NetModular)

    NetModular是什么? NetModular不仅仅是一个框架,它也是一整套的模块化与前后端分离的快速开发的解决方案,目标是致力于开箱即用,让开发人员完全专注于业务开发,不需要关心底层封装和实现. ...

  9. MySQL InnoDB如何保证事务特性

    如果有人问你"数据库事务有哪些特性"?你可能会很快回答出原子性.一致性.隔离性.持久性即ACID特性.那么你知道InnoDB如何保证这些事务特性的吗?如果知道的话这篇文章就可以直接 ...

  10. 【译】微软的Python入门教程(一)

    Getting started with Python(Python入门) Overview 概述 The series of videos on Channel 9 is designed to h ...