享元模式 vs. 单例模式
1. 核心目标
模式 核心目标 享元模式 共享多个对象 :通过复用相同内部状态的对象,减少内存占用和对象创建开销。单例模式 限制唯一实例 :确保一个类仅有一个实例,并提供全局访问点,通常用于控制资源或共享服务。
2. 关键区别
维度 享元模式 单例模式 实例数量 可以有多个实例(每个享元对应不同的内部状态)。 严格仅有一个实例。 状态管理 区分内部状态(共享)和外部状态(非共享),依赖外部状态传入。 单例通常管理自身状态,所有客户端共享同一状态。 适用场景 存在大量重复对象的场景(如游戏中的子弹、文本编辑器中的字符)。 需要全局唯一访问点的场景(如配置管理、数据库连接池)。 实现方式 使用工厂类管理共享对象池,按需返回享元对象。 通过私有构造函数和静态方法确保唯一实例。 线程安全 享元对象若仅包含不可变状态则线程安全,否则需处理外部状态的线程安全。 需显式处理多线程环境下的实例化问题(如双重检查锁定)。
3. 代码对比
享元模式示例
interface Flyweight {
void operation ( String extrinsicState) ;
}
class ConcreteFlyweight implements Flyweight {
private final String intrinsicState;
public ConcreteFlyweight ( String state) {
this . intrinsicState = state;
}
@Override
public void operation ( String extrinsicState) {
System . out. println ( "Intrinsic: " + intrinsicState + ", Extrinsic: " + extrinsicState) ;
}
}
class FlyweightFactory {
private final Map < String , Flyweight > pool = new HashMap < > ( ) ;
public Flyweight getFlyweight ( String key) {
return pool. computeIfAbsent ( key, ConcreteFlyweight :: new ) ;
}
}
单例模式示例
class Singleton {
private static volatile Singleton instance;
private Singleton ( ) { }
public static Singleton getInstance ( ) {
if ( instance == null ) {
synchronized ( Singleton . class ) {
if ( instance == null ) {
instance = new Singleton ( ) ;
}
}
}
return instance;
}
public void doSomething ( ) {
System . out. println ( "Singleton action" ) ;
}
}
4. 结合使用场景
互补场景 享元工厂本身可以实现为单例,确保全局统一管理共享对象池。 例如:在游戏中,所有子弹享元对象由一个单例工厂管理。
class FlyweightFactory {
private static final FlyweightFactory INSTANCE = new FlyweightFactory ( ) ;
private final Map < String , Flyweight > pool = new HashMap < > ( ) ;
private FlyweightFactory ( ) { }
public static FlyweightFactory getInstance ( ) {
return INSTANCE ;
}
public Flyweight getFlyweight ( String key) {
return pool. computeIfAbsent ( key, ConcreteFlyweight :: new ) ;
}
}
冲突场景 若单例对象需要持有多个享元实例,需避免混淆两者的设计目标。 (例如:单例的配置管理器内部使用享元优化重复配置项的存储。)
5. 总结
模式 选择依据 享元模式 当系统中存在大量重复对象,且可分离内部状态(共享)与外部状态(非共享)时使用。 单例模式 当需要确保全局唯一实例,或控制对共享资源(如线程池、配置)的访问时使用。
关键区别 :享元模式关注对象共享 ,单例模式关注实例唯一性 。共同点 :二者均可减少资源占用,但实现方式和应用场景不同。