设计模式详解-享元模式
设计模式详解:享元模式
一、模式概述
享元模式(Flyweight Pattern)是结构型设计模式中最具性能洞察力的模式,其核心意图在于运用共享技术有效地支持大量细粒度的对象。这一模式直面软件系统中一个普遍的内存困境:当对象数量达到百万、千万级别时,即便单个对象仅占少量内存,累积起来也可能压垮整个系统的可用资源。
享元模式的命名源自拳击比赛中的"蝇量级"(Flyweight),暗示其处理的是轻量级对象。然而,这一模式的真正力量不在于对象本身的轻量,而在于通过共享消除冗余。它将对象状态拆分为"内部状态"(Intrinsic State)与"外部状态"(Extrinsic State):内部状态是对象可共享的不变特征,存储于享元对象内部;外部状态是随场景变化的上下文数据,由客户端在调用时传入。这种拆分使得大量看似独立的对象,实际上共享着同一组享元实例。
享元模式的深层价值在于以时间换空间的经典权衡。它通过增加状态传递的开销,换取内存占用的数量级下降。在内存敏感、对象高度相似、创建成本高昂的场景中,这一模式是系统性能优化的关键杠杆。
二、模式结构
享元模式包含四个核心角色,形成工厂-产品的共享体系:
抽象享元(Flyweight):声明享元对象的公共接口,该接口接收外部状态作为参数,实现与具体场景的结合。
具体享元(Concrete Flyweight):实现抽象享元接口,存储内部状态。具体享元对象必须是可共享的,即内部状态不可变。
非共享具体享元(Unshared Concrete Flyweight):并非所有享元子类都需要被共享。非共享享元通常作为共享享元的组合组成部分,从享元工厂创建但不纳入共享池。
享元工厂(Flyweight Factory):负责创建和管理享元对象。维护一个享元池(通常以HashMap实现),当客户端请求享元时,工厂先检查池中是否存在匹配实例,存在则返回引用,不存在则创建并纳入池中。
客户端(Client):维护对享元的引用,计算或存储享元所需的外部状态,并在调用享元方法时传递外部状态。
三、深度案例:实时风控引擎的规则系统
以下展示一个真实场景下的享元模式应用——金融交易实时风控引擎中的规则匹配系统,需支持每秒数十万笔交易的毫秒级规则判定。
3.1 问题域分析:规则对象的内存爆炸
风控系统维护数万条风控规则,每条规则包含复杂的条件表达式、阈值配置、关联指标计算逻辑。 naive 的实现为每笔交易的每个匹配规则创建独立实例:
java
// 反模式:每条规则每个交易独立实例
public class RuleInstance {
private String ruleId;
private String ruleName;
private RuleType type;
private ConditionExpression condition; // 复杂AST
private List<IndicatorCalculator> indicators; // 指标计算器
private ThresholdConfig threshold; // 阈值配置
private AlertAction action; // 触发动作
private RiskLevel level; // 风险等级
// 运行时状态(每笔交易不同)
private TransactionContext context;
private Map<String, Object> computedValues;
private boolean triggered;
private String triggerReason;
}
当规则数量达到5万条,交易并发1万笔/秒,每秒需创建5亿个规则实例,内存占用超过200GB,GC停顿导致系统完全不可用。享元模式通过分离不变与可变状态,将5万个规则定义压缩为共享的享元实例,每笔交易仅需传递轻量的上下文句柄。
3.2 享元设计:规则对象的状态拆分
java
/**
* 抽象享元:规则定义的核心接口
* 所有方法接收外部状态(RuleContext)作为参数
*/
public interface RuleFlyweight {
// 规则身份标识(内部状态)
String getRuleId();
String getRuleName();
RuleType getType();
RiskLevel getDefaultLevel();
// 规则判定:结合外部状态执行
RuleMatchResult evaluate(RuleContext context);
// 获取规则依赖的指标列表(用于预计算优化)
Set<String> getRequiredIndicators();
// 获取规则复杂度评分(用于执行排序)
int getComplexityScore();
}
/**
* 具体享元:标准风控规则
* 内部状态不可变,构造后通过Builder冻结
*/
public final class StandardRuleFlyweight implements RuleFlyweight {
// ========== 内部状态(共享) ==========
private final String ruleId;
private final String ruleName;
private final RuleType type;
private final RiskLevel defaultLevel;
private final ConditionExpression condition; // 编译后的AST,不可变
private final List<IndicatorCalculator> indicators; // 不可变计算器列表
private final ThresholdConfig threshold; // 不可变阈值
private final AlertAction action; // 不可变动作模板
private final int complexityScore;
private final Set<String> requiredIndicators;
// 私有构造器,强制通过工厂创建
private StandardRuleFlyweight(Builder builder) {
this.ruleId = builder.ruleId;
this.ruleName = builder.ruleName;
this.type = builder.type;
this.defaultLevel = builder.defaultLevel;
this.condition = builder.condition;
this.indicators = List.copyOf(builder.indicators); // 不可变包装
this.threshold = builder.threshold;
this.action = builder.action;
this.complexityScore = computeComplexity();
this.requiredIndicators = extractRequiredIndicators();
}
// ========== 享元接口实现 ==========
@Override
public String getRuleId() { return ruleId; }
@Override
public String getRuleName() { return ruleName; }
@Override
public RuleType getType() { return type; }
@Override
public RiskLevel getDefaultLevel() { return defaultLevel; }
@Override
public Set<String> getRequiredIndicators() {
return requiredIndicators;
}
@Override
public int getComplexityScore() { return complexityScore; }
@Override
public RuleMatchResult evaluate(RuleContext context) {
// 核心:使用传入的外部状态,而非自身存储
try {
// 1. 指标计算(从上下文中获取或触发计算)
Map<String, Object> indicatorValues = new HashMap<>();
for (IndicatorCalculator calc : indicators) {
Object value = context.getOrComputeIndicator(calc.getIndicatorName());
indicatorValues.put(calc.getIndicatorName(), value);
}
// 2. 条件判定(AST求值,使用外部状态)
boolean matched = condition.evaluate(indicatorValues, context.getTransaction());
if (!matched) {
return RuleMatchResult.noMatch(this);
}
// 3. 阈值比较
ThresholdComparison comparison = threshold.compare(indicatorValues);
// 4. 构建匹配结果(包含外部状态的快照)
return RuleMatchResult.builder()
.matched(true)
.rule(this) // 引用享元本身,非复制
.triggeredLevel(comparison.getExceededLevel().orElse(defaultLevel))
.triggeredValue(comparison.getTriggeredValue())
.thresholdValue(comparison.getThresholdValue())
.indicatorSnapshot(Map.copyOf(indicatorValues))
.contextSnapshot(context.createSnapshot())
.build();
} catch (Exception e) {
context.recordEvaluationError(ruleId, e);
return RuleMatchResult.error(this, e);
}
}
// 复杂度计算:用于规则执行排序,简单规则优先
private int computeComplexity() {
return condition.getNodeCount() * 10
+ indicators.size() * 5
+ threshold.getDimensionCount() * 3;
}
private Set<String> extractRequiredIndicators() {
return indicators.stream()
.map(IndicatorCalculator::getIndicatorName)
.collect(Collectors.toUnmodifiableSet());
}
// Builder模式创建(确保不可变性)
public static Builder builder() { return new Builder(); }
public static class Builder {
private String ruleId;
private String ruleName;
private RuleType type;
private RiskLevel defaultLevel;
private ConditionExpression condition;
private List<IndicatorCalculator> indicators = new ArrayList<>();
private ThresholdConfig threshold;
private AlertAction action;
public Builder ruleId(String id) { this.ruleId = id; return this; }
public Builder ruleName(String name) { this.ruleName = name; return this; }
public Builder type(RuleType type) { this.type = type; return this; }
public Builder defaultLevel(RiskLevel level) { this.defaultLevel = level; return this; }
public Builder condition(ConditionExpression expr) { this.condition = expr; return this; }
public Builder addIndicator(IndicatorCalculator calc) {
this.indicators.add(calc); return this;
}
public Builder threshold(ThresholdConfig threshold) {
this.threshold = threshold; return this;
}
public Builder action(AlertAction action) { this.action = action; return this; }
public StandardRuleFlyweight build() {
validate();
return new StandardRuleFlyweight(this);
}
private void validate() {
if (ruleId == null || condition == null) {
throw new IllegalStateException("规则ID和条件表达式必须指定");
}
}
}
}
/**
* 具体享元:组合规则(规则树中的非叶子节点)
* 自身不执行判定,委托给子规则,但共享子规则引用
*/
public final class CompositeRuleFlyweight implements RuleFlyweight {
private final String ruleId;
private final String ruleName;
private final RuleType type;
private final RiskLevel defaultLevel;
private final List<RuleFlyweight> children; // 共享的子规则引用
private final CompositeLogic logic; // AND / OR / NOT / WEIGHTED
// 构造与StandardRuleFlyweight类似,省略...
@Override
public RuleMatchResult evaluate(RuleContext context) {
List<RuleMatchResult> childResults = new ArrayList<>();
switch (logic) {
case AND:
for (RuleFlyweight child : children) {
RuleMatchResult result = child.evaluate(context);
childResults.add(result);
if (!result.isMatched()) {
return RuleMatchResult.noMatch(this, childResults);
}
}
return aggregateMatch(childResults);
case OR:
for (RuleFlyweight child : children) {
RuleMatchResult result = child.evaluate(context);
childResults.add(result);
if (result.isMatched()) {
return aggregateMatch(childResults);
}
}
return RuleMatchResult.noMatch(this, childResults);
case WEIGHTED:
double totalScore = 0;
for (RuleFlyweight child : children) {
RuleMatchResult result = child.evaluate(context);
childResults.add(result);
if (result.isMatched()) {
totalScore += getWeight(child);
}
}
if (totalScore >= getThresholdScore()) {
return aggregateMatch(childResults);
}
return RuleMatchResult.noMatch(this, childResults);
default:
throw new UnsupportedOperationException("未知组合逻辑: " + logic);
}
}
// 聚合子结果,取最高风险等级
private RuleMatchResult aggregateMatch(List<RuleMatchResult> childResults) {
RiskLevel maxLevel = childResults.stream()
.filter(RuleMatchResult::isMatched)
.map(RuleMatchResult::getTriggeredLevel)
.max(Comparator.comparingInt(RiskLevel::getSeverity))
.orElse(defaultLevel);
return RuleMatchResult.builder()
.matched(true)
.rule(this)
.triggeredLevel(maxLevel)
.childResults(childResults)
.build();
}
}
3.3 享元工厂:规则共享池管理
java
/**
* 享元工厂:规则享元的创建、共享、生命周期管理
* 支持热更新、版本控制、分区隔离
*/
@Component
public class RuleFlyweightFactory {
// 主享元池:ruleId -> RuleFlyweight
private final ConcurrentHashMap<String, RuleFlyweight> flyweightPool =
new ConcurrentHashMap<>();
// 版本化享元池:支持蓝绿发布和灰度
private final ConcurrentHashMap<String, ConcurrentHashMap<Integer, RuleFlyweight>>
versionedPool = new ConcurrentHashMap<>();
// 规则定义仓库
private final RuleDefinitionRepository ruleRepository;
// 规则编译服务(DSL -> AST)
private final RuleCompiler ruleCompiler;
// 指标计算器工厂
private final IndicatorCalculatorFactory calculatorFactory;
// 元数据索引:支持非ID查询
private final RuleMetadataIndex metadataIndex = new RuleMetadataIndex();
// 加载统计
private final MeterRegistry meterRegistry;
@Autowired
public RuleFlyweightFactory(RuleDefinitionRepository repository,
RuleCompiler compiler,
IndicatorCalculatorFactory calculatorFactory,
MeterRegistry meterRegistry) {
this.ruleRepository = repository;
this.ruleCompiler = compiler;
this.calculatorFactory = calculatorFactory;
this.meterRegistry = meterRegistry;
}
/**
* 获取享元(核心方法):先查池,不存在则创建
*/
public RuleFlyweight getFlyweight(String ruleId) {
RuleFlyweight flyweight = flyweightPool.get(ruleId);
if (flyweight != null) {
meterRegistry.counter("rule.flyweight.cache.hit").increment();
return flyweight;
}
// 缓存未命中,创建享元(带锁防止重复创建)
meterRegistry.counter("rule.flyweight.cache.miss").increment();
return flyweightPool.computeIfAbsent(ruleId, this::createFlyweight);
}
/**
* 批量预加载:系统启动时或规则更新后
*/
public void preloadFlyweights(List<String> ruleIds) {
// 并行加载,利用CompletableFuture优化
List<CompletableFuture<RuleFlyweight>> futures = ruleIds.stream()
.map(id -> CompletableFuture.supplyAsync(() -> getFlyweight(id)))
.toList();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
meterRegistry.gauge("rule.flyweight.pool.size", flyweightPool.size());
}
/**
* 热更新:规则变更时替换享元
* 采用写时复制策略,保证正在执行的判定不受影响
*/
public void updateFlyweight(String ruleId, RuleDefinition newDefinition) {
// 创建新版本享元
RuleFlyweight newFlyweight = compileToFlyweight(newDefinition);
// 原子替换
RuleFlyweight oldFlyweight = flyweightPool.put(ruleId, newFlyweight);
// 旧版本放入版本池,供未完成的事务继续使用
if (oldFlyweight != null) {
versionedPool
.computeIfAbsent(ruleId, k -> new ConcurrentHashMap<>())
.put(oldFlyweight.hashCode(), oldFlyweight);
}
// 更新元数据索引
metadataIndex.update(newFlyweight);
// 异步清理旧版本(延迟30秒后)
scheduleCleanup(ruleId, oldFlyweight);
meterRegistry.counter("rule.flyweight.update").increment();
}
/**
* 按条件查询享元:利用元数据索引
*/
public List<RuleFlyweight> findByCriteria(RuleQueryCriteria criteria) {
// 先通过索引快速过滤
Set<String> candidateIds = metadataIndex.query(criteria);
// 再获取享元实例(自动触发加载)
return candidateIds.stream()
.map(this::getFlyweight)
.filter(f -> criteria.matches(f)) // 精确匹配
.collect(Collectors.toList());
}
/**
* 获取池统计信息
*/
public PoolStatistics getStatistics() {
return PoolStatistics.builder()
.totalFlyweights(flyweightPool.size())
.totalMemoryEstimate(estimateMemory())
.hitRate(calculateHitRate())
.versionedFlyweights(versionedPool.values().stream()
.mapToInt(Map::size)
.sum())
.build();
}
// ========== 私有辅助方法 ==========
private RuleFlyweight createFlyweight(String ruleId) {
RuleDefinition definition = ruleRepository.findById(ruleId)
.orElseThrow(() -> new RuleNotFoundException(ruleId));
return compileToFlyweight(definition);
}
private RuleFlyweight compileToFlyweight(RuleDefinition definition) {
// 编译条件表达式为AST
ConditionExpression condition = ruleCompiler.compile(
definition.getConditionDsl()
);
// 创建指标计算器(计算器本身也可能是享元)
List<IndicatorCalculator> indicators = definition.getIndicatorConfigs()
.stream()
.map(config -> calculatorFactory.getOrCreate(config))
.collect(Collectors.toList());
// 构建享元
StandardRuleFlyweight flyweight = StandardRuleFlyweight.builder()
.ruleId(definition.getId())
.ruleName(definition.getName())
.type(definition.getType())
.defaultLevel(definition.getDefaultLevel())
.condition(condition)
.indicators(indicators)
.threshold(definition.getThreshold())
.action(definition.getAction())
.build();
// 注册到元数据索引
metadataIndex.index(flyweight);
return flyweight;
}
private void scheduleCleanup(String ruleId, RuleFlyweight oldVersion) {
// 延迟清理,确保引用旧版本的事务已完成
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(() -> {
Map<Integer, RuleFlyweight> versions = versionedPool.get(ruleId);
if (versions != null) {
versions.remove(oldVersion.hashCode());
if (versions.isEmpty()) {
versionedPool.remove(ruleId);
}
}
}, 30, TimeUnit.SECONDS);
}
private long estimateMemory() {
// 基于规则复杂度估算内存占用
return flyweightPool.values().stream()
.mapToLong(this::estimateFlyweightSize)
.sum();
}
private long estimateFlyweightSize(RuleFlyweight flyweight) {
// 简化估算:基础开销 + 条件AST节点数 * 节点大小
return 256 + flyweight.getComplexityScore() * 64L;
}
}
3.4 外部状态管理:规则上下文
java
/**
* 外部状态容器:每笔交易的规则执行上下文
* 轻量、可复用、线程隔离
*/
public class RuleContext {
// 交易基础信息(外部状态核心)
private final Transaction transaction;
private final Instant evaluationTime;
private final String traceId;
// 指标计算缓存:避免重复计算
private final Map<String, Object> indicatorCache = new HashMap<>();
// 计算过程中的临时状态
private final Map<String, Object> sessionData = new HashMap<>();
// 执行追踪:用于调试和审计
private final List<EvaluationTrace> traces = new ArrayList<>();
private final List<EvaluationError> errors = new ArrayList<>();
// 性能统计
private final Map<String, Long> indicatorComputeTime = new HashMap<>();
// 上下文对象池(避免频繁创建)
private static final ThreadLocal<ObjectPool<RuleContext>> contextPool =
ThreadLocal.withInitial(() -> new ObjectPool<>(RuleContext::new, 100));
// 私有构造器,强制通过对象池获取
private RuleContext() {
this.transaction = null;
this.evaluationTime = null;
this.traceId = null;
}
public static RuleContext acquire(Transaction transaction) {
RuleContext ctx = contextPool.get().borrow();
ctx.reset(transaction);
return ctx;
}
public void release() {
this.indicatorCache.clear();
this.sessionData.clear();
this.traces.clear();
this.errors.clear();
this.indicatorComputeTime.clear();
contextPool.get().returnObject(this);
}
private void reset(Transaction transaction) {
// 重置可复用对象的状态
this.transaction = transaction;
this.evaluationTime = Instant.now();
this.traceId = TraceContext.getCurrentTraceId();
}
/**
* 获取或计算指标:核心外部状态传递机制
*/
public Object getOrComputeIndicator(String indicatorName) {
// 1. 检查缓存
Object cached = indicatorCache.get(indicatorName);
if (cached != null) return cached;
// 2. 计算指标
long start = System.nanoTime();
IndicatorCalculator calculator = IndicatorRegistry.get(indicatorName);
Object value = calculator.compute(this);
long elapsed = System.nanoTime() - start;
// 3. 缓存结果
indicatorCache.put(indicatorName, value);
indicatorComputeTime.put(indicatorName, elapsed);
// 4. 记录追踪
traces.add(new EvaluationTrace(indicatorName, elapsed, value));
return value;
}
/**
* 创建快照:用于匹配结果的持久化
*/
public ContextSnapshot createSnapshot() {
return ContextSnapshot.builder()
.transactionId(transaction.getId())
.evaluationTime(evaluationTime)
.indicatorValues(Map.copyOf(indicatorCache))
.sessionData(Map.copyOf(sessionData))
.build();
}
// 其余方法...
}
/**
* 对象池:轻量级的享元辅助设施
*/
public class ObjectPool<T> {
private final Queue<T> available;
private final Supplier<T> factory;
private final int maxSize;
public ObjectPool(Supplier<T> factory, int maxSize) {
this.factory = factory;
this.maxSize = maxSize;
this.available = new ArrayBlockingQueue<>(maxSize);
}
public T borrow() {
T obj = available.poll();
return obj != null ? obj : factory.get();
}
public void returnObject(T obj) {
available.offer(obj); // 满则丢弃
}
}
3.5 规则引擎:享元的协调执行
java
/**
* 规则引擎:协调享元执行,管理外部状态
*/
@Component
public class RuleEngine {
private final RuleFlyweightFactory flyweightFactory;
private final RuleExecutionStrategy executionStrategy;
private final MeterRegistry meterRegistry;
/**
* 执行规则集:对单笔交易进行完整风控判定
*/
public RiskAssessment assessTransaction(Transaction transaction,
List<String> ruleSetIds) {
// 从对象池获取轻量上下文
RuleContext context = RuleContext.acquire(transaction);
try {
long startTime = System.currentTimeMillis();
// 1. 加载规则享元(共享的内部状态)
List<RuleFlyweight> rules = ruleSetIds.stream()
.map(flyweightFactory::getFlyweight)
.sorted(Comparator.comparingInt(RuleFlyweight::getComplexityScore))
.collect(Collectors.toList());
// 2. 预计算指标:批量获取所有需要的指标
Set<String> requiredIndicators = rules.stream()
.map(RuleFlyweight::getRequiredIndicators)
.flatMap(Set::stream)
.collect(Collectors.toSet());
for (String indicator : requiredIndicators) {
context.getOrComputeIndicator(indicator); // 触发计算并缓存
}
// 3. 执行规则判定(传递外部状态)
List<RuleMatchResult> matches = new ArrayList<>();
for (RuleFlyweight rule : rules) {
RuleMatchResult result = rule.evaluate(context);
if (result.isMatched()) {
matches.add(result);
if (result.getTriggeredLevel() == RiskLevel.BLOCK) {
break; // 阻断级规则触发,提前终止
}
}
}
// 4. 聚合风险结果
RiskAssessment assessment = aggregateResults(transaction, matches, context);
// 5. 记录性能指标
meterRegistry.timer("rule.engine.assessment")
.record(System.currentTimeMillis() - startTime, TimeUnit.MILLISECONDS);
return assessment;
} finally {
context.release(); // 归还对象池
}
}
/**
* 批量评估:利用享元共享,高效处理大量交易
*/
public List<RiskAssessment> assessBatch(List<Transaction> transactions,
List<String> ruleSetIds) {
// 预加载所有享元,避免批量过程中的缓存未命中
flyweightFactory.preloadFlyweights(ruleSetIds);
// 并行评估,利用享元的线程安全性
return transactions.parallelStream()
.map(tx -> assessTransaction(tx, ruleSetIds))
.collect(Collectors.toList());
}
private RiskAssessment aggregateResults(Transaction transaction,
List<RuleMatchResult> matches,
RuleContext context) {
if (matches.isEmpty()) {
return RiskAssessment.clean(transaction.getId());
}
RiskLevel maxLevel = matches.stream()
.map(RuleMatchResult::getTriggeredLevel)
.max(Comparator.comparingInt(RiskLevel::getSeverity))
.orElse(RiskLevel.LOW);
return RiskAssessment.builder()
.transactionId(transaction.getId())
.overallRisk(maxLevel)
.matchedRules(matches)
.indicatorsSnapshot(context.createSnapshot())
.assessmentTime(Instant.now())
.build();
}
}
四、享元模式的高级主题
4.1 字符串驻留与值对象享元
Java字符串常量池是语言级享元实现。自定义值对象同样可应用此思想:
java
/**
* 货币金额的值对象享元
* 高频出现的金额(如0.00, 1.00, 100.00)共享实例
*/
public final class Money implements Serializable {
private static final ConcurrentHashMap<BigDecimal, Money> CACHE =
new ConcurrentHashMap<>();
private static final int CACHE_SIZE_LIMIT = 10000;
// 预加载常用金额
static {
for (int i = 0; i <= 10000; i++) {
BigDecimal amount = BigDecimal.valueOf(i, 2); // 0.00 ~ 100.00
CACHE.put(amount, new Money(amount, Currency.CNY));
}
}
private final BigDecimal amount;
private final Currency currency;
private Money(BigDecimal amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}
public static Money of(BigDecimal amount, Currency currency) {
// 标准化金额(去除末尾零)
BigDecimal normalized = amount.stripTrailingZeros();
// 尝试从缓存获取
if (currency == Currency.CNY && CACHE.size() < CACHE_SIZE_LIMIT) {
return CACHE.computeIfAbsent(normalized, a -> new Money(a, currency));
}
return new Money(normalized, currency);
}
// 运算返回新享元(或缓存中的实例)
public Money add(Money other) {
assertSameCurrency(other);
return Money.of(this.amount.add(other.amount), this.currency);
}
// 不可变,无需防御性复制
public BigDecimal getAmount() { return amount; }
public Currency getCurrency() { return currency; }
}
4.2 数据库连接池:享元的资源管理变体
java
/**
* 数据库连接享元:连接池的本质是享元模式
* 连接对象(内部状态:URL、驱动、配置)共享
* 会话状态(外部状态:事务、隔离级别、当前SQL)分离
*/
public class PooledConnection implements Connection {
// 内部状态:共享的物理连接属性
private final String url;
private final String username;
private final Connection physicalConnection; // 真实的JDBC连接
// 外部状态:每次借出时重置
private boolean inUse;
private long checkoutTime;
private String checkoutThread;
private Map<String, Object> sessionState = new HashMap<>();
// 借出时重置外部状态
synchronized void checkout() {
this.inUse = true;
this.checkoutTime = System.currentTimeMillis();
this.checkoutThread = Thread.currentThread().getName();
this.sessionState.clear();
// 重置连接状态为干净状态
physicalConnection.setAutoCommit(true);
physicalConnection.setTransactionIsolation(
Connection.TRANSACTION_READ_COMMITTED);
physicalConnection.setReadOnly(false);
}
// 归还时清理外部状态
synchronized void checkin() {
try {
if (!physicalConnection.getAutoCommit()) {
physicalConnection.rollback(); // 清理未提交事务
}
} catch (SQLException e) {
// 标记连接为无效
this.valid = false;
}
this.inUse = false;
this.checkoutTime = 0;
this.checkoutThread = null;
this.sessionState.clear();
}
// 所有Connection方法委托给physicalConnection
// 但需在外部状态变更时记录
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
sessionState.put("autoCommit", autoCommit);
physicalConnection.setAutoCommit(autoCommit);
}
}
五、享元模式与相关模式的辨析
享元 vs 单例:单例保证全局唯一实例,强调访问点的统一;享元保证同类对象的共享,强调内存效率。单例通常只有一个,享元通常有多个按key区分的实例。
享元 vs 对象池:对象池管理可复用的重量级对象(如数据库连接),关注资源获取的开销;享元管理轻量级对象的共享,关注内存占用。对象池的对象被取出后独占使用,享元对象可同时被多个上下文共享。
享元 vs 原型:原型通过复制创建新对象,享元通过共享避免创建。二者可结合:享元工厂内部使用原型模式创建初始实例。
享元 vs 不变对象:享元要求内部状态不可变,这与函数式编程的不变对象理念一致。享元可视为不变对象在共享场景下的工程优化。
六、设计考量与陷阱规避
内部状态与外部状态的边界划分:划分不当导致共享数据被意外修改,或外部状态传递开销过大。建议:内部状态在构造后绝对不可变;外部状态尽量扁平、避免嵌套对象。
享元工厂的线程安全:ConcurrentHashMap是标准选择,但需注意复合操作的原子性。computeIfAbsent是安全的,先get再putIfAbsent需额外同步。
缓存淘汰策略:无限增长的享元池可能导致内存泄漏。需实现LRU、TTL、或基于内存压力的淘汰机制。Caffeine、Guava Cache提供了生产级的本地缓存实现。
外部状态的传递开销:当外部状态体积庞大时,传递成本可能抵消共享收益。此时可考虑将外部状态也部分共享(二级享元),或使用ThreadLocal缓存。
七、结语
享元模式是性能优化工具箱中的利器,其价值在于以系统化的状态分离,实现内存使用的数量级优化。在现代大数据、实时计算、高并发系统中,对象创建的内存压力是架构设计的关键约束。理解享元模式的内部/外部状态分离思想,掌握享元工厂的线程安全与生命周期管理,警惕状态污染与缓存泄漏的陷阱,是构建高性能系统的必备能力。享元模式不仅是一种代码结构,更是一种资源管理哲学——在有限与无限之间,寻找最优的共享平衡点。