包名设计是解耦第一道防线,须用反向域名+业务分层(如com.example.order.api),配合默认访问修饰符与module-info.java导出控制,实现编译期边界隔离。

包名设计是解耦的第一道防线
大型项目里,模块之间不该随意调用,包结构就是最直观的边界标识。比如订单模块和支付模块,必须拆成 com.example.order 和 com.example.payment 两个独立顶层包。这样不仅避免类名冲突,更让团队一眼看出“哪些代码属于哪个业务域”。包名采用反向域名前缀(如 com.company.project),再按业务分层展开,例如 com.example.order.api(对外契约)、com.example.order.domain(核心模型)、com.example.order.infra(基础设施实现)。这种命名不是为了好看,而是把职责边界写进路径里——路径即契约。
访问修饰符配合包结构控制可见粒度
包定边界,修饰符管门禁。在 com.example.order.domain 包内,领域实体类通常用 public,但内部聚合根的构造逻辑可能只允许同包使用,就用默认(无修饰符);而某些仅限本模块子类扩展的策略基类,可设为 protected。关键点在于:默认权限(包私有)是解耦利器——它天然阻止跨包直接访问,比写注释“请勿调用”管用十倍。若某工具类只供 order 模块内部使用,就别放 com.example.shared.util 这种宽泛包下,而应放在 com.example.order.internal 并用默认修饰符封装。
避免跨包强依赖的实操习惯
当一个类需要被其他模块使用时,不靠“把它改成 public 就行”,而是明确暴露契约:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 对外接口统一放在 .api 或 .contract 子包,且只含 public interface 和 DTO 类
- 禁止在 controller 或 service 包里直接 new 另一模块的实现类,必须通过接口 + 依赖注入
- 跨包调用只 import 接口所在包,绝不 import 实现类所在的 .infra 或 .impl 包
- 用 IDE 的“Find Usages”定期检查:如果 com.example.payment.service.PaymentService 被 order 模块的非 .api 类直接引用,说明边界已泄漏
JDK9+ 模块系统强化包级隔离
在支持模块化的项目中,module-info.java 是包解耦的升级开关。即使两个模块都定义了 com.example.common.utils.StringUtils,只要它们属于不同命名模块,就不会冲突。更重要的是,你可以:
立即学习“Java免费学习笔记(深入)”;
- 用 exports com.example.order.api; 显式开放对外接口包
- 用 requires com.example.payment.api; 声明合法依赖,编译期就能拦截非法跨层调用
- 未导出的包(如 com.example.order.internal)即使被其他模块 import,也会编译失败
这相当于给包加了一把编译期锁,比运行时才发现循环依赖或越权访问,可靠得多。

















