文章目录
Service Locator Pattern
geeksforgeeks的原文 ,我理解性的翻译了下,添加了些自己的理解。
用 抽象层 封装 获取服务 的过程。
使用一个被称为 service locator
的中心注册表,service locator
根据请求返回执行具体任务所需要的的信息。
当服务消费者请求服务实例时,serviceLocator
负责返回对应的服务实例。
service Locator
service locator
将 查找服务的API
、服务提供者依赖、查找的复杂性以及业务对象的创建做了抽象,仅对服务消费者暴露一个简单的接口,这样将复杂封装在自己内部,使得客户端变的简单。
InitialContext
初始化上下文,类似于 spring
里面的容器概念。如果对容器的概念也不清楚,那就只可意会不可言传了。
是整个服务查找和创建过程的起点。将所有的服务提供商放进这个容器里面,如果,后续有新的服务提供商加入进来,也需要将它们放进这个InitialContext
容器来。
InitialContext
根据具体的业务对象类型返回具体服务对象。
ServiceFactory
服务工厂对象负责管理 业务服务对象 的生命周期,何时实例化,何时销毁等。
BusinessService
业务服务对象,是一个角色,由客户端需求的服务对象来扮演。所以说,就是具体的服务提供商对象。
业务服务对象 由 服务工厂创建、查找、删除
图例
以前的类关系
服务消费者和服务提供商,绑定在一起,增加或删除服务提供商,都需要更改服务消费者中的代码。
在编译的时候,具体的服务提供商的类就需要存在。
Service Locator Pattern
模式的类关系
服务提供商和服务消费者之间的耦合,转移到
locator
里面
在编译的时候,具体的服务提供商的类不需要存在。增加或修改服务提供商,服务消费者也不需要改代码。
java code demo
服务接口
/**
* 首先将 服务 的功能,抽取出来。
* 这个抽取很有意义,在后面这个接口将代替具体的服务提供商,参与到逻辑中。
* 将具体的服务提供商,排除在外,这样整体逻辑,将和具体的服务提供商无关。
* 也就是和具体的服务提供商没有耦合关系
*/
interface Service {
public String getName();
public void execute();
}
服务提供商类
// 具体的服务提供商 one
class ServiceOne implements Service {
public void execute()
{
System.out.println("Executing ServiceOne");
}
@Override
public String getName()
{
return "ServiceOne";
}
}
// 具体的服务提供商 two
class ServiceTwo implements Service {
public void execute()
{
System.out.println("Executing ServiceTwo");
}
@Override
public String getName()
{
return "ServiceTwo";
}
}
容器类
/**
* 上下文对象
* 是一个容器,负责注册和查找具体的服务
* 后续如有新的服务提供商,需要在这里修改代码
* 这里是用硬编码方式,注册服务商。
* 其实容器,还有其他优雅的方式处理,像 spring 那样
*/
class InitialContext {
// 这里面的代码,简单化了
// 业务复杂的话,这里面应该抽象出一个 ServiceFactory 类,复杂具体服务的创建
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
更像容器。
/**
* 缓存
*/
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 类
// Locator class
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;
}
// 越看越像 spring里面的 ApplicationContext
InitialContext context = new InitialContext();
// getBean 方法
Service ServiceOne = (Service)context.lookup(name);
cache.addService(ServiceOne);
return ServiceOne;
}
}
测试类
// Driver class
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
时代过来的,你就会 会心一笑。