zoukankan      html  css  js  c++  java
  • 【设计模式】服务定位器模式

    前言

    服务定位器模式(Service Locator Pattern)是控制反转原理的实现方式之一。本文详细介绍该模式,并提供了 UML 图和示例 Java 代码。

    服务定位器模式

    服务定位器模式实现了按需返回服务实例。在该模式中,应用所有需要的服务都会被注册到服务定位器中,并通过 ID 唯一标识。应用需要哪个服务,用这个 ID 就能从服务定位器中得到这个服务的实例。服务定位器模式解耦了服务调用者和具体的服务实现。该模式的 UML 类图可以表示如下:

    服务定位器模式包含如下组件:

    • Client:服务调用者,向服务定位器发出服务调用请求
    • Service Locator:客户端/服务端间通信入口,从 Cache 中返回服务
    • Cache:缓存、复用服务
    • Initializer:创建、注册服务到 Cache 中
    • Service:服务具体实现

    Java 示例

    让我们看一个具体的例子来理解服务定位器模式,准备代码如下:

    // Java program to 
    // illustrate Service Design Service 
    // Locator Pattern 
      
    import java.util.ArrayList; 
    import java.util.List; 
    

    首先,定义服务 Service 接口以及两个具体服务实现:

    // Service interface 
    // for getting name and 
    // Executing it. 
      
    interface Service { 
        public String getName(); 
        public void execute(); 
    }
    
    // Service one implementing Locator 
    class ServiceOne implements Service { 
        public void execute() 
        { 
            System.out.println("Executing ServiceOne"); 
        } 
      
        @Override
        public String getName() 
        { 
            return "ServiceOne"; 
        } 
    } 
      
    // Service two implementing Locator 
    class ServiceTwo implements Service { 
        public void execute() 
        { 
            System.out.println("Executing ServiceTwo"); 
        } 
      
        @Override
        public String getName() 
        { 
            return "ServiceTwo"; 
        } 
    } 
    

    接着定义 Service Locator 类,该服务器类实现了一个服务 Cache 以及一个服务实例返回函数 getService。getService 函数会优先返回缓存的服务实例,如果没有,则通过 Initializer 创建。

    // 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; 
            } 
      
            InitialContext context = new InitialContext(); 
            Service ServiceOne = (Service)context.lookup(name); 
            cache.addService(ServiceOne); 
            return ServiceOne; 
        } 
    } 
    

    上面提到的 Cache 类和 Initializer 类具体实现如下:

    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); 
            } 
        } 
    } 
    
    // Checking the context 
    // for ServiceOne and ServiceTwo 
    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; 
        } 
    }
    

    最后是 Client 类,测试代码效果:

    // Client class 
    class ServiceConsumer { 
        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(); 
        } 
    } 
    

    输出结果:

    Creating a new ServiceOne object
    Executing ServiceOne
    Creating a new ServiceTwo object
    Executing ServiceTwo
    Returning cached ServiceOne object
    Executing ServiceOne
    Returning cached ServiceTwo object
    Executing ServiceTwo
    

    总结

    与依赖注入的区别

    两种模式都是控制反转原理的实现,即对象不应该知道如何构造其依赖项。不同点在于,对于服务定位器模式,Client 仍然需要对依赖项的创建负责,虽然借助了 Service Locator 来完成。

    优缺点

    优点:

    • 应用可以在运行时,选择添加或移除依赖服务
    • 应用和服务间松耦合,唯一的连接仅仅在于服务定位器的服务注册

    缺点:

    • 服务定位器的服务注册使代码更加复杂,不得不维护比较多的服务唯一标识 ID
    • 如果依赖有错误,只能在运行时报错,不能在编译时发现
    • 由于应用仍要负责创建依赖项,因此不能 mock 依赖,不方便写测试代码

    参考资料

    [1] 30分钟学会UML类图
    [2] Baeldung: Service Locator Pattern
    [3] GeeksforGeeks: Service Locator Pattern

  • 相关阅读:
    09-JS的事件流的概念(重点)
    08-jQuery的位置信息
    07-小米导航案例
    python-selector模块
    python--day9--异步IO、数据库、队列、缓存
    python--select多路复用socket
    python--gevent高并发socket
    python--协程
    python--进程锁、进程池
    python--多进程
  • 原文地址:https://www.cnblogs.com/huanggze/p/12537446.html
Copyright © 2011-2022 走看看