Service Locator Pattern,学习spring,遇到了的设计模式 。 geeksforgeeks的原文
Service Locator Pattern是用 抽象层 封装 获取服务 的过程。
使用一个被称为 service locator的中心注册表,service locator 根据请求返回执行具体任务所需要的的信息。
当服务消费者请求服务实例时,serviceLocator负责返回对应的服务实例。
service Locator service locator 将 查找服务的API、服务提供者依赖、查找的复杂性以及业务对象的创建做了抽象,仅对服务消费者暴露一个简单的接口,这样将复杂封装在自己内部,使得客户端变的简单。
InitialContext 初始化上下文,类似于 spring里面的容器概念。如果对容器的概念也不清楚,那就只可意会不可言传了。
是整个服务查找和创建过程的起点。将所有的服务提供商放进这个容器里面,如果,后续有新的服务提供商加入进来,也需要将它们放进这个InitialContext容器来。
InitialContext 根据具体的业务对象类型返回具体服务对象。
ServiceFactory 服务工厂对象负责管理 业务服务对象 的生命周期,何时实例化,何时销毁等。
BusinessService 业务服务对象,是一个角色,由客户端需求的服务对象来扮演。所以说,就是具体的服务提供商对象。
业务服务对象 由 服务工厂创建、查找、删除
图例
以前的类关系
服务消费者和服务提供商,绑定在一起,增加或删除服务提供商,都需要更改服务消费者中的代码。
在编译的时候,具体的服务提供商的类就需要存在。
Service Locator Pattern 模式的类关系
服务提供商和服务消费者之间的耦合,转移到 locator 里面
在编译的时候,具体的服务提供商的类不需要存在。增加或修改服务提供商,服务消费者也不需要改代码。
java code demo 服务接口 1 2 3 4 5 6 7 8 9 10 interface Service { public String getName () ; public void execute () ; }
服务提供商类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class ServiceOne implements Service { public void execute () { System.out.println("Executing ServiceOne" ); } @Override public String getName () { return "ServiceOne" ; } } class ServiceTwo implements Service { public void execute () { System.out.println("Executing ServiceTwo" ); } @Override public String getName () { return "ServiceTwo" ; } }
容器类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class InitialContext { public Object lookup (String name) { if (name.equalsIgnoreCase("ServiceOne" )) { System.out.println("Creating a new ServiceOne object" ); return new ServiceOne(); } else if (name.equalsIgnoreCase("ServiceTwo" )) { System.out.println("Creating a new ServiceTwo object" ); return new ServiceTwo(); } return null ; } }
缓存类
搭配上面的 InitialContext 更像容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Cache { private List<Service> services; public Cache () { services = new ArrayList<Service>(); } public Service getService (String serviceName) { for (Service service : services) { if (service.getName().equalsIgnoreCase(serviceName)) { System.out.println("Returning cached " + serviceName + " object" ); return service; } } return null ; } public void addService (Service newService) { boolean exists = false ; for (Service service : services) { if (service.getName().equalsIgnoreCase(newService.getName())) { exists = true ; } } if (!exists) { services.add(newService); } } }
ServiceLocator 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class ServiceLocator { private static Cache cache; static { cache = new Cache(); } public static Service getService (String name) { Service service = cache.getService(name); if (service != null ) { return service; } InitialContext context = new InitialContext(); Service ServiceOne = (Service)context.lookup(name); cache.addService(ServiceOne); return ServiceOne; } }
测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class ServiceLocatorPatternDemo { public static void main (String[] args) { Service service = ServiceLocator.getService("ServiceOne" ); service.execute(); service = ServiceLocator.getService("ServiceTwo" ); service.execute(); service = ServiceLocator.getService("ServiceOne" ); service.execute(); service = ServiceLocator.getService("ServiceTwo" ); service.execute(); } }
优点
`ServiceLocator` 配合 `cache`,完成了`service`的单例模式。并不需要具体的`service`自己实现单例模式,通过`cache` 完成了单例的需求。这在某些场景下,很实用,假如考虑,创建具体的服务提供商对象很占用资源,但是具体的服务又是第三方提供的,这时候就可以用这种思路实现单例,缓存起来。
程序可以在运行时动态调整依赖
解耦合,服务消费者和服务提供者之间并没有之间的联系,所有的联系都在注册表中
缺点
如果服务提供商不存在,本来应该在编译期间就会被发现的,因为是直接依赖。现在转移到运行期间才能发现。(其实算不得缺点,将依赖耦合解耦了,就这样)
总结
最后,设计模式不能完全理解,或者想不到对应的案列,是正常的。毕竟设计模式是总结会来的经验性准则,需要一定的阅历或者说经历过类似的坑,才能感同身受。
就像后来的我们学 spring 框架,永远也不会多么深刻的理spring的轻量级,轻量在哪里。但是如果你是从EJB 时代过来的,你就会 会心一笑。