Java设计模式——享元模式
⚪享元模式(Flyweight)是一种结构型设计模式,这个模式通过将对象的一部分状态外部化,使得多个对象可以共享相同的状态,从而减少了内存消耗。
⚪意图:通过共享对象来减少内存和性能开销,特别是在有大量相似对象需要创建的情况下。
⚪以下是工厂方法模式的关键要点:
▷ 角色和责任:
- 享元接口(Flyweight): 定义了享元对象的接口,通常包括一个设置外部状态的方法。
- 具体享元(ConcreteFlyweight): 实现了享元接口,包括了内部状态和一部分外部状态。具体享元对象必须是可共享的。
- 非共享具体享元(UnsharedConcreteFlyweight): 并非所有的享元对象都可以被共享,非共享具体享元包含了不能被共享的外部状态。
- 享元工厂(FlyweightFactory): 负责管理享元对象的创建和共享,通常包括一个享元池用于存储已经创建的享元对象。
▷ 工作流程:
- 客户端通过享元工厂请求一个享元对象。
- 如果该享元对象已存在于享元池中,则返回现有的对象。
- 如果对象不存在,则享元工厂创建一个新的享元对象,并将其存储在享元池中。
- 客户端使用享元对象,可能会设置一些外部状态。
- 因为相同的享元对象在享元池中是共享的,所以可以被多个客户端同时使用。
▷ 示例
// 享元接口
public interface Font {
void render(String text);
}
// 具体享元
public class ConcreteFont implements Font {
private String name;
public ConcreteFont(String name) {
this.name = name;
}
@Override
public void render(String text) {
System.out.println("Rendering text '" + text + "' with font " + name);
}
}
// 享元工厂
public class FontFactory {
private Map<String, Font> fontMap = new HashMap<>();
public Font getFont(String name) {
Font font = fontMap.get(name);
if (font == null) {
font = new ConcreteFont(name);
fontMap.put(name, font);
}
return font;
}
}
// 客户端代码
public class TextEditorClient {
public static void main(String[] args) {
FontFactory fontFactory = new FontFactory();
Font font1 = fontFactory.getFont("Arial");
Font font2 = fontFactory.getFont("Times New Roman");
Font font3 = fontFactory.getFont("Arial");
// font1 和 font3 实际上是相同的享元对象,它们共享相同的内部状态
// font2 是另一个享元对象,因为它的内部状态不同
font1.render("Hello, world!");
font2.render("This is a test.");
font3.render("Flyweight pattern.");
}
}
⚪适用性
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。由于 Flyweight 对象可以被共享,所以对于概念上明显有别的对象,标识测试将返回真值。
⚪应用场景
- 文本编辑器:在文本编辑器中,每个字符可以看作是一个字体和大小不同的文本对象。为了节省内存,可以使用享元模式来共享相同字体和大小的字符对象。
- 游戏开发:在游戏中,角色、道具、粒子效果等可以大量存在,但具有相似的属性。享元模式可以用于共享这些相似对象的状态,从而减少内存占用。
- 图形系统:在图形系统中,绘制大量相同形状、颜色的图形对象时,可以使用享元模式来共享相同的图形状态。
- 线程池:线程池中的线程对象可以看作是享元对象。线程池可以共享和管理这些线程对象,从而降低线程的创建和销毁开销。
⚪实际已有场景
- 字符串池:Java 中的字符串常量池是享元模式的一个实际应用。相同的字符串常量在内存中只保存一份,多个字符串变量可以共享相同的字符串对象。
- 连接池:数据库连接池和连接池中的连接对象也可以被看作享元对象。连接池管理和共享连接对象,避免了频繁创建和销毁连接的开销。
- Bean 对象管理:在 Spring IoC 容器中,Bean 对象的创建和管理可以被视为享元模式的一种实现。Spring 容器管理着一组共享的 Bean 定义,当需要时,它们可以被实例化和共享。
- 连接池:虽然连接池通常与数据库操作相关,但在 Spring 中也有广泛的应用。Spring 框架提供了对连接池的支持,例如通过使用 DataSource 来管理数据库连接,以便在应用程序中共享和重复使用连接对象。

浙公网安备 33010602011771号