享元(Flyweight)模式通过共享对象来最小化内存使用和实例化对象的数量。
什么是享元模式
在Java应用程序中,创建和处理大量对象会占用大量的内存和处理器时间,从而影响应用程序的性能。这时候,享元模式可以派上用场了。享元模式利用对象共享来最小化对象的数量,从而提高应用程序的性能。在享元模式中,内部状态与外部状态是分开存储的,内部状态指的是同类对象间具有的相同信息,而外部状态指的是对象间的不同信息。通过共享内部状态,并将外部状态作为参数传进去,可以减少对象的创建和存储,从而节省资源。
享元模式的使用场景
适用于需要创建大量相似对象或者对象数量很大的场景,例如对象池、GUI界面中的图形和文本等。
组成部分:
-
抽象享元:定义享元接口方法,规定外部状态为参数。
-
具体享元:实现抽象享元定义的方法。
-
享元工厂:创建并管理享元对象,确保共享相同享元对象。
享元模式的代码示例
我们将创建一个 Text(文本)接口和一个 TextType(文本类型)类来表示我们的享元。文本类型只需指定文本应使用的字体,因为颜色是外部状态。
我们还将使用一个 Color(颜色)类来表示文本的颜色。在我们的例子中,颜色将作为外部状态传递给 TextType 对象。
首先,我们需要定义一个抽象的文本接口:
// 文本接口
public interface Text {
void draw(String content);
}
然后,我们可以实现具体的文本和颜色类,这里我们实现了两种颜色类:
// 颜色类
public class Color {
// 颜色名称
private final String color;
public Color(String color) {
this.color = color;
}
public String getColor() {
return color;
}
}
// 具体文本类
public class TextType implements Text {
// 字体名称
private final String font;
public TextType(String font) {
this.font = font;
}
// 绘制文本
@Override
public void draw(String content) {
System.out.println("使用 " + font + " 字体绘制文本,内容为:" + content);
}
}
在 TextType 类中,我们使用了共享的字体对象,但外部状态是通过 draw() 方法传递进来的。
接下来,我们可以创建一个享元工厂来管理文本和颜色对象:
// 享元工厂,用于创建和管理文本共享对象
import java.util.HashMap;
public class TextFactory {
// 存放颜色和文本类型之间的映射关系
private static final HashMap<Color, TextType> textTypeMap = new HashMap<>();
// 根据颜色和字体获取文本类型
public static TextType getText(Color color, String font) {
// 判断是否存在对应的共享文本对象
TextType textType = textTypeMap.get(color);
// 如果不存在,则创建一个新的共享文本对象,并加入到Map中
if (textType == null) {
textType = new TextType(font);
textTypeMap.put(color, textType);
}
return textType;
}
}
最后,我们可以使用 TextFactory 和 Color 对象来创建、共享和使用文本对象:
// 测试代码
public class FlyweightDemo {
private static final String[] fonts = new String[]{"Arial", "Times New Roman", "Verdana", "Calibri"};
private static final String[] colors = new String[]{"Red", "Green", "Blue", "Orange"};
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Color color = getColor();
String font = getFont();
TextType textType = TextFactory.getText(color, font);
textType.draw("贵州欢迎您!");
}
}
private static String getFont() {
return fonts[(int) (Math.random() * fonts.length)];
}
private static Color getColor() {
return new Color(colors[(int) (Math.random() * colors.length)]);
}
}
运行结果如下:
使用 Arial 字体绘制文本,内容为:贵州欢迎您!
使用 Calibri 字体绘制文本,内容为:贵州欢迎您!
使用 Calibri 字体绘制文本,内容为:贵州欢迎您!
使用 Arial 字体绘制文本,内容为:贵州欢迎您!
使用 Times New Roman 字体绘制文本,内容为:贵州欢迎您!
使用 Arial 字体绘制文本,内容为:贵州欢迎您!
使用 Arial 字体绘制文本,内容为:贵州欢迎您!
使用 Times New Roman 字体绘制文本,内容为:贵州欢迎您!
使用 Calibri 字体绘制文本,内容为:贵州欢迎您!
使用 Verdana 字体绘制文本,内容为:贵州欢迎您!
使用 Times New Roman 字体绘制文本,内容为:贵州欢迎您!
使用 Arial 字体绘制文本,内容为:贵州欢迎您!
使用 Calibri 字体绘制文本,内容为:贵州欢迎您!
使用 Calibri 字体绘制文本,内容为:贵州欢迎您!
使用 Verdana 字体绘制文本,内容为:贵州欢迎您!
使用 Verdana 字体绘制文本,内容为:贵州欢迎您!
使用 Times New Roman 字体绘制文本,内容为:贵州欢迎您!
使用 Arial 字体绘制文本,内容为:贵州欢迎您!
使用 Times New Roman 字体绘制文本,内容为:贵州欢迎您!
使用 Verdana 字体绘制文本,内容为:贵州欢迎您!
享元模式的实际应用
享元(Flyweight)模式是一种轻量级的设计模式,在应用开发中,我们通常会使用一些常用框架来帮助我们实现享元模式。
- Java 缓存库
Java 缓存库,如 Ehcache、Guava Cache、Caffeine 等,为应用程序提供了跨多个会话和请求的缓存容器,以减少数据库访问和增加性能。
这些缓存库通常使用享元模式来存储和管理缓存对象,以提高应用程序性能。
- Servlet
Servlet API 中的 HttpSession 对象使用了享元模式来处理会话状态。服务器只需为每个新会话创建一个 HttpSession 对象,其余的会话状态可以共享。
在这种情况下,每个 HttpSession 仅包含对会话的参考,而实际的数据则存储在一个更大的共享存储区域中。
- Spring Framework
Spring Framework是一个轻量级的 Java 开发框架,它提供了大量的特性和功能,其中之一就是使用享元模式来管理大量的 Bean 对象。
Spring Framework 使用了很多设计模式,在 DI(Dependency Injection)和 AOP(Aspect Oriented Programming)方面,也使用了享元模式来处理 Bean 对象的创建和管理。
- JDBC
JDBC(Java Database Connectivity)API 用于访问关系型数据库。在 JDBC 中,数据库连接是一个昂贵的资源,因为它需要建立网络连接和进行身份验证等复杂操作。
因此,JDBC 使用了池化技术来管理数据库连接,这也是使用了享元模式的一种方式。
关注微信公众号:“小虎哥的技术博客”。我们会定期发布关于Java技术的详尽文章,让您能够深入了解该领域的各种技巧和方法,让我们一起成为更优秀的程序员👩💻👨💻!