第1部分 避免浪费
注:其内容主要来自于【日】-结城浩 著《图解设计模式》20章节 极力推荐大家阅读原著
第1章 Flyweight 模式 - 共享对象避免浪费
1.1 Flyweight 模式
Flyweight 的意思"轻量级",其在英文中的原意指比赛中选手体重最轻等级的一种描述。所以顾名思义,该模式的主要作用就是为了让对象变得更"轻"。
那么这里的"轻"又如何理解呢?
在计算机的应用体系当中,所有的一切应用层的东西都是虚拟的,而这些虚拟的构建都存储在内存当中。所以这里的"轻"代指的就是一个对象所占内存的空间大小。占用空间的比率越大则越"重",反之则"轻"。
举个例子,比如说我们在 Java 当中需要创建一个对象,该对象的本身生成的中间过程比较复杂,也使得该对象比较庞大,内存分配给该对象的占用比也就响应的比距大。当程序在执行过程当中,如果大量的需要使用到该对象,先不谈,该对象每次一的 new 关键字所带来的资源上的负荷,就其该对象如果都使用 new 关键字来进行分配,将会消耗大量的内存空间。
所以关于 Flyweight 模式,其实最终的目的就是为了“尽量的通过共享实例取代 new 实例”。
相当于我们有一个共享池,在共享池中只存在唯一不同实例,公用已经存在的实例。这就是 Flyweight 模式的核心重点。
1.2 实例程序
这里先使用 Flyweight 模式设计一个简单的示例程序。
其具体的程序目的就是将其下 代码清单中 20-1 ~ 20-9 中的许多普通文本组合成一个 “大型字符”的类,而这些普通字符的实例就是重复的实例。
而下面的代码清单中的各个以 bigx.txt 命名的文件,是为了方便进行测试,而通过文本的格式将单个普通字符存储到本地文件当中,在拼接"大型字符"的时候,将其需要的文件内容加载读取到内存当中。
关于类的构建说明如表 20-1 下图所示
这里我用其他字符格式代替需要的可复制或该网站生成 BootSchool
代码清单 1.1 BootSchool banner图
__ _______ ______
/ \ / ___ ) / ___ \
\/) ) \/ ) | \/ \ \
| | / ) ___) /
| | _/ / (___ (
| | / _/ ) \
__) (_ ( (__/\ /\___/ /
\____/ \_______/ \______/
___ _______ ______
/ ) ( ____ \ / ____ \
/ /) | | ( \/ ( ( \/
/ (_) (_ | (____ | (____
(____ _) (_____ \ | ___ \
) ( ) ) | ( ) )
| | /\____) ) ( (___) )
(_) \______/ \_____/
______ _____ _____
/ ___ \ / ___ \ / ___ \
\/ ) ) ( (___) ) ( ( ) )
/ / \ / ( (___) |
/ / / ___ \ \____ |
/ / ( ( ) ) ) |
/ / ( (___) ) /\____) )
\_/ \_____/ \______/
BigChar 表示 “大型字符” 的类,该类的主要作用就是通过文件流的形式将其上述代码清单 20-8 中提到的内容读取到内存当中,然后通过 print 方法打印输出大型字符。而这些大型字符,在创建的过程当中会消耗大量的计算机内存资源,因此我们考虑的重点是在于,如何通过共享的形式,将这些唯一的 BigChar 实例作为其共享资源。
BigCharFactory 工厂的作用就是,会更具其具体的需要从而生成指定而 BigChar 实例,但是在其生成之前首先会进行相应的具体判断,如果其发现之前已经生成过该唯一的 BigChar 实例,则直接使用即可,否则生成新的唯一实例。而对于生成的实例,我们将其存储在 java.util.HashMap 类定义的 pool 字段当中,进行维护。
BigString 类的作用就是将其 BgiChar “大型字符” 组合成指定“大型字符串” 。
Main 类用于最终测试程序行为的类。
实例程序 UML 类图
代码清单 1.1 BigChar 类 (BigChar.java)
package com.peggy.flyweight.example01;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* @Projectname: designPatterns
* @Filename: BigChar
* @Author: peggy
* @Data:2023/5/25 11:14
* @Description: 根据字符生成字符串
*/
public class BigChar {
//字符名字
private char charname;
//大型字符对应的字符串
private String fontdata;
//字符串文件路径
private static String PATH = "E:\\workspaces\\java\\designPatterns\\peggy-flyweight-pattren-01\\src\\main\\resources\\";
public BigChar(char charname) {
this.charname = charname;
try {
BufferedReader reader = new BufferedReader(
new FileReader(PATH + "big" + charname + ".txt"));
String line;
StringBuilder buf = new StringBuilder();
while ((line = reader.readLine()) != null) {
//写入到内存
buf.append(line);
buf.append("\n");
}
this.fontdata = buf.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void print() {
System.out.println(fontdata);
}
}
代码清单 1.1 BigCharFactory类 (BigCharFactory.class)
- !标注[1] 处 BigCharFactory 声明成静态单利模式,是为了保证全局只有一个静态工厂 BigCharFactory 实例。试想如果全局中为私有化其构造方法,就可以创建多个工厂实例,其每个工厂实例都会有一个 pool ,也就失去了 Flyweight 模式存在的意义。
- !标注[2] 处对于 getBigchar 方法用其 synchronized 关键字进行修饰,其目的也是为了保证 pool 的对象不会重复创建。值得注意的是,虽然无论是否在并发情况下, pool 中的实例受 Map 集合的 Key / Value 键值对的约束,都是有且只有一个唯一的不同实例存在。但是这并不影响在并发情况下出现,BigChar 实例重复创建的可能性存在。所以这里使用 synchronized 关键字修饰是显得尤为重要的。
package com.peggy.flyweight.example01;
import java.util.HashMap;
import java.util.Map;
/**
* @Projectname: designPatterns
* @Filename: BigCharFactory
* @Author: peggy
* @Data:2023/5/25 14:48
* @Description: 生成 BigChar 实例的工厂 实现其共享功能
*/
public class BigCharFactory {
//管理已经生成的 BigChar 实例
private Map<String, BigChar> pool = new HashMap<>();
//单利模式,其保证只有一个工厂对象
/*!标注[1]*/
private static BigCharFactory singleton = new BigCharFactory();
private BigCharFactory() {
}
public static BigCharFactory getSingleton() {
return singleton;
}
//生成共享 BigChar 唯一对象
/*!标注[2]*/
public synchronized BigChar getBigChar(char charname) {
BigChar bc = pool.get(String.valueOf(charname));
if (bc == null) {
bc = new BigChar(charname);
pool.put(String.valueOf(charname), bc);
}
return bc;
}
}
代码清单 1.1 BigString类 (BigString.class)
package com.peggy.flyweight.example01;
/**
* @Projectname: designPatterns
* @Filename: BigString
* @Author: peggy
* @Data:2023/5/25 15:15
* @Description: 大型字符串创建类
*/
public class BigString {
//"大型字符" 的数组
private BigChar[] bigChars;
//构造函数
public BigString(String string) {
bigChars = new BigChar[string.length()];
BigCharFactory factory = BigCharFactory.getSingleton();
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();
}
}
}
Main 类
package com.peggy.flyweight.example01;
/**
* @Projectname: designPatterns
* @Filename: Main
* @Author: peggy
* @Data:2023/5/25 15:25
* @Description: 案例测试类
*/
public class Main {
public static void main(String[] args) {
BigString bs = new BigString("15569732xxx");
bs.print();
}
}