4.7 服务定位器模式
服务定位器模式(Service Locator)提供一个集中的注册表,客户端通过它按名字获取服务,而不必自己去创建或查找。它最初的动机是:在 J2EE 里,通过 JNDI 查找一个服务(数据源、EJB、消息队列)代价很高。服务定位器把首次查到的服务缓存起来,后续直接命中缓存,避免重复的昂贵查找。
下面的实验:第一次获取某个服务会走“昂贵的 JNDI 查找”,第二次则命中缓存、瞬间返回。
正在加载交互实验...
注册表 + 缓存
java
class ServiceLocator {
private static Map<String, Service> cache = new HashMap<>();
public static Service get(String name) {
if (cache.containsKey(name)) return cache.get(name); // 命中缓存
Service svc = new InitialContext().lookup(name); // 昂贵查找,仅一次
cache.put(name, svc);
return svc;
}
}客户端只需 ServiceLocator.get("OrderService"),完全不关心服务是怎么被查找、创建、缓存的。下面的实验是一个 JNDI 查找模拟器,让你按名字定位不同的服务实例。
正在加载交互实验...
正在加载概念检查...
争议:服务定位器 vs 依赖注入
这是现代设计里一个著名的辩论。两者都在解决“对象如何获得它依赖的服务”,但方向相反:
- 服务定位器:对象主动向定位器索取依赖(
locator.get(...))。
- 依赖注入(DI):依赖被被动地注入对象(通过构造函数/setter)。
许多人(包括 Martin Fowler)更偏爱 DI,理由是:服务定位器隐藏了依赖——你从一个类的构造函数签名里看不出它到底依赖了什么,必须读它的实现,这削弱了可测试性与可见性。
不过服务定位器并非一无是处:在无法控制对象创建(如某些框架回调、遗留系统)或需要运行时动态解析服务的场景里,它依然实用。理解这场辩论,能帮你在真实项目里做出有依据的取舍。
正在加载概念检查...
正在加载本节练习...