核心是限制对象仅与“直接朋友”通信以降低耦合:合法对象限于自身创建、参数传入、私有成员变量及this;禁用链式调用,改用委托方法封装语义;返回值需克制,避免暴露可变内部引用;多对象协作应通过协调者统一调度。

核心是让对象只跟“直接朋友”说话,不越级、不暴露、不强依赖。不是消灭通信,而是把耦合关进可控的笼子里。
明确谁是你的“直接朋友”
Java 中一个类合法的通信对象只有四类:
- 自己创建的对象(比如构造方法里 new 出来的)
- 作为参数传进来的对象(方法签名里声明的)
- 自己的成员变量(private 字段,且类型是已知、受控的)
- this 本身(调用自己的方法或字段)
像 user.getProfile().getAddress().getCity() 这种写法,Address 和 City 都不算 user 的朋友——Profile 是朋友,Address 是 Profile 的朋友,但对 user 来说就是“陌生人”。这种链式调用等于把三层内部结构全摊开,一旦 Address 类改名、City 字段变 private 或加了校验逻辑,user 所在的所有地方都得跟着动。
用委托方法代替层层点取
需要跨层获取信息时,别自己动手挖,让“朋友”代劳:
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 在 Profile 类里加一个 getCity() 方法,内部调用 address.getCity()
- User 就只需写 user.getProfile().getCity(),完全不知道 Address 存在
- 将来 Address 拆成 DomesticAddress 和 OverseasAddress,只要 Profile 的 getCity() 内部适配好,User 代码零修改
这不只是加个 getter,而是封装语义:不是“取地址里的城市”,而是“取用户所在城市”——后者才是业务语言,更稳定。
返回值要克制,别交出内部容器或可变对象
暴露内部引用等于主动开门放耦合进来:
- ❌ public List
- getItems() { return items; }
—— 外部能 add/remove,破坏一致性 - ✅ public List
- getItems() { return Collections.unmodifiableList(items); }
- ✅ 更进一步:public int getItemCount()、public Item getItem(int index) —— 只给能力,不给容器
同理,避免返回 private 字段的原始引用(如 Date、StringBuilder、数组),优先返回副本或不可变包装。
用协调者隔离多对象协作
当多个对象天然要配合完成一件事(比如下单:查库存 → 扣减 → 创建订单 → 发通知),别让 Controller 层一手包办所有调用:
- ❌ Controller 直接调 inventoryService.check() → paymentService.charge() → notifyService.send()
- ✅ 引入 OrderService.place(Order order),它内部调度各组件,但 Inventory 不认识 Payment,Payment 也不依赖 Notify
- 后续加风控、积分、物流单,只需改 OrderService,不影响已有模块
协调者不一定是新类,也可以是现有服务的聚合接口,关键是把“谁该和谁说话”的规则收口。

















