门面模式是落实迪米特法则的典型方式,通过统一入口封装子系统协作,聚焦业务场景提供高频、稳定、跨域接口,隐藏内部细节,预处理参数,按业务域或使用方合理划分粒度,保持轻量无状态,避免嵌入业务逻辑;适用于复杂调用需解耦场景,但天然强关联、临时脚本或已稳定低频接口则无需引入。

引入门面类是落实迪米特法则最直观、也最常用的方式之一。它不改变原有逻辑,而是把多层对象的访问路径收束到一个统一入口,让调用方只跟门面打交道,完全不知道背后有多少个子系统在协作。
门面类该封装哪些能力?
门面不是简单地把所有方法堆在一起,而是围绕具体业务场景提炼出有意义的操作接口:
- 聚焦高频、稳定、跨域的业务动作,比如“创建带默认配置的订单”“获取用户完整档案(含地址+偏好+头像)”
- 隐藏内部组合关系,不暴露子系统类名或字段路径,例如不提供
getProfile().getAddress().getCity(),而提供getUserLocation() - 对参数做预处理或兜底,如自动补全缺失字段、转换协议格式、合并多次远程调用
怎么设计门面的粒度?
门面太粗会变成“上帝类”,太细则失去意义。关键看职责边界是否清晰:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 按业务域划分:用户门面、订单门面、支付门面,各自负责本域内聚合操作
- 按使用方划分:面向前端 API 的门面、面向后台批处理的门面,接口契约和错误处理策略可不同
- 避免在门面里写业务判断逻辑,如“如果是 VIP 就走 A 流程”,这类分支应下沉到具体服务类中
门面与原有类如何协作?
门面本身不实现核心逻辑,而是协调已有类完成任务。它应保持轻量、无状态,并通过依赖注入获取所需服务:
- 构造函数只接收真正需要协作的对象,不传入无关的 DAO 或工具类
- 不持有子系统实例变量以外的状态,避免引入隐式上下文
- 若某操作需调用多个服务且存在顺序依赖,门面可封装成原子方法,内部处理异常传播与回滚边界
什么时候不该用门面?
不是所有耦合都需要门面来解。以下情况可暂缓或绕过:
- 两个类天然强关联,比如
Order和OrderItem,它们属于同一聚合根,直接访问更自然 - 临时脚本、单元测试或调试代码,追求快速而非长期可维护性
- 已有接口已稳定、调用量低、上下游都可控,强行加门面反而增加间接层
门面的价值不在“有没有”,而在“是否让调用变得更专注、更安全、更不易断裂”。它不消灭依赖,而是把依赖约束在一个可控的边界里。










