变量工厂模式是封装业务规则的对象初始化策略,通过工厂类聚合输入源、执行校验、自动补全字段,解决new或字面量无法满足动态约束的问题。

变量工厂模式不是标准设计模式术语,但结合你提到的“创建符合特定业务约束的初始变量状态”,实际指的是一种面向业务规则的对象初始化策略——即用工厂类(或工厂函数)封装变量/对象的构造逻辑,确保每次产出的状态都满足当前场景下的校验、默认值、依赖推导等约束条件。
为什么不能直接 new 或字面量赋值?
在真实业务中,初始状态往往不是静态的。比如:
- 门店盘点单的单据号必须按“日期+门店编码+流水号”生成,且同一天同一门店不能重复;
- 用户提交的库存调整请求,其“生效时间”需根据模板规则自动对齐到凌晨2点(跨日盘点),而非前端传入的时间;
- 合同克隆时,某些字段要清空(如签署人、时间),某些要继承(如标的物、金额),还有些要重算(如有效期截止日)。
这些都不是简单赋值能解决的——它们涉及外部服务调用(单据号生成器)、领域规则判断(CheckingHelper)、历史数据查取(上一张单据)、甚至事务一致性要求。硬编码在业务方法里,会导致逻辑散落、难以复用、测试困难。
变量工厂的核心职责:组装 + 校验 + 补全
它不只做“new”,而是承担三项关键动作:
- 组装来源:聚合多个输入源(命令对象、模板实体、配置项、仓储查询结果);
- 执行校验:检查必填字段、业务唯一性(如当日不可重复盘点)、权限前置(是否允许创建临时盘点);
- 自动补全:填充默认值(status = “暂存”)、派生字段(erpStatus = “未同步”)、时间规整(createDate → floorToDayStart())。
例如,一个简化版的盘点单工厂方法可能长这样(伪代码):
CheckingDoc createFrom(Command cmd, Template tpl, DocsDayIdGenerator gen) {if (tpl.isOncePerDay() && hasTodayDoc(cmd.storeId)) throw ConflictException();
String code = gen.next(cmd.storeId, cmd.date);
return new CheckingDoc(
code,
cmd.storeId,
tpl.id,
floorToDayStart(cmd.startTime), // 自动规整
"DRAFT",
"NOT_SYNC"
);
}
如何落地:从简单工厂到可扩展结构
初期可用静态工厂方法快速交付;当模板类型增多(每日/每周/突击/月结)、或需要支持不同租户差异化规则时,建议升级为工厂方法模式:
- 定义抽象工厂接口:
CheckingDocFactory,声明create(Command, Template); - 为每类模板实现具体工厂:
DailyCheckingFactory、MonthlyClosingFactory; - 通过 Spring 或 .NET DI 注入对应工厂实例,由上下文(如模板 type 字段)决定使用哪个。
这样新增一种盘点类型,只需加一个新工厂类,不改原有任何代码,也无需触碰 if-else 判断分支。
和依赖注入(DI)配合的关键点
工厂本身往往需要协作对象(如单据号生成器、模板仓储)。不要在工厂内部 new 它们,而是通过构造函数注入:
class DailyCheckingFactory {private final DocsDayIdGenerator idGen;
private final CheckingTemplateRepo templateRepo;
DailyCheckingFactory(DocsDayIdGenerator idGen, CheckingTemplateRepo repo) {
this.idGen = idGen;
this.templateRepo = repo;
}
}
再把该工厂注册进 DI 容器(如 ASP.NET Core 的 AddScoped),就能天然获得生命周期管理和解耦能力。










