中介者模式是否等同于服务定位器?其是否违反迪米特法则?
关于中介者模式的困惑与澄清
你的核心困惑
- 误认为中介者模式和服务定位器(反模式)类似,只是存放对象的容器
- 觉得重构后的代码违反迪米特法则,出现过多链式调用
中介者模式 vs 服务定位器:本质区别
你觉得两者像,是因为误用了中介者模式——你写的ModelsMediator只是单纯持有模型实例,没有承担中介者的核心职责。两者的核心差异在于:
- 目的不同:中介者是为了协调多个对象间的复杂交互,让对象只和中介者通信,避免对象间直接耦合;服务定位器是提供全局对象查找入口,本质是隐藏依赖的全局访问点,容易导致代码难以追踪。
- 依赖关系不同:中介者模式中,业务对象和中介者的依赖是双向且明确的,中介者封装了所有对象间的协作逻辑;服务定位器是对象主动去查找依赖,依赖关系是隐式的,调用方不知道依赖的来源。
正确的中介者模式示例
class ModelsMediator { private $users; private $userPasswords; public function __construct(UserModel $users, UserPasswordModel $userPasswords) { $this->users = $users; $this->userPasswords = $userPasswords; } // 封装跨模型的协作逻辑 public function getUserWithPassword(int $userId) { $user = $this->users->getById($userId); $password = $this->userPasswords->getByUserId($userId); return ['user' => $user, 'password' => $password]; } } class Test { private $mediator; public function __construct(ModelsMediator $mediator) { $this->mediator = $mediator; } public function handleUser(int $userId) { // 只和中介者交互,无需直接操作模型 $userData = $this->mediator->getUserWithPassword($userId); } }
这个示例里,中介者不是容器,而是交互的协调中心,业务类Test不需要知道各个模型的存在,只需要调用中介者提供的高层方法。
关于迪米特法则的误解
你提到的this.models.users.getAll()确实违反了迪米特法则——这是因为你把中介者当成了模型容器,让Test直接访问了中介者内部的对象(朋友的朋友)。
在正确的中介者模式下,Test只和ModelsMediator这个直接依赖交互,不会触及中介者内部的模型,完全符合迪米特法则的要求:只和直接朋友通信。
链式调用的问题根源
你遇到的链式调用问题,同样是误用中介者模式导致的。真正的中介者会封装所有跨对象的协作逻辑,业务类只需要调用中介者的封装方法,不会出现models.users.getAll()这种需要逐层访问的链式调用。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

