服務定位器模式(service locator)

來源:互聯網
上載者:User
文章目錄
  • Using a Segregated Interface for the Locator
  • A Dynamic Service Locator
  • Using both a locator and injection with Avalon
Using a Service Locator 使用服務定位器

    The key benefit of a Dependency Injector is that it removes the dependency that the MovieLister

class has on the concrete MovieFinder implementation. This allows me to give listers to friends

and for them to plug in a suitable implementation for their own environment. Injection isn't

the only way to break this dependency, another is to use a service locator.

    使用依賴注入的主要好處就是能夠消除MovieLister對具體實現MovieFinder的依賴。這允許我把Movielister

給朋友並讓他們根據自身環境情況注入相應的實現。注入並不是解除依賴關係的唯一方法,還有一種方法也可以

解除依賴關係,那就是使用服務定位器。

    The basic idea behind a service locator is to have an object that knows how to get hold of

all of the services that an application might need. So a service locator for this application

would have a method that returns a movie finder when one is needed. Of course this just shifts

the burden a tad, we still have to get the locator into the lister, resulting in the dependencies

of Figure。

    服務定位器的最基本的思想就是有一個對象定位器知曉如何控制應用程式需要的所有服務。所以以上例子中

提到的應用程式的一個服務定位器在需要的時候將會使用某個方法返回一個movie finder的執行個體。當然這僅僅是

轉移一些負擔而已,我們仍舊必須取得進入lister的服務定位器,結果就呈現以下的依賴關係。

    In this case I'll use the ServiceLocator as a singleton Registry. The lister can then use that to

get the finder when it's instantiated.

    在下面這個例子中,我將使用服務定位器作為單例註冊器。MovieLister能夠使用該服務定位器在初始化時得到

MovieFinder的執行個體。

class MovieLister...
    MovieFinder finder = ServiceLocator.movieFinder();
class ServiceLocator...
    public static MovieFinder movieFinder() {
        return soleInstance.movieFinder;
    }
    private static ServiceLocator soleInstance;
    private MovieFinder movieFinder;

As with the injection approach, we have to configure the service locator. Here I'm doing it in code, but it's not hard

 

to use a mechanism that would read the appropriate data from a configuration file.

 

就像注入方法一樣,我們必須佈建服務定位器。下面我用代碼來完成這個功能,但是使用從設定檔讀取相應資料的機制也並不困難。

 

class Tester...

 

    private void configure() {

        

           ServiceLocator.load(new ServiceLocator(new ColonMovieFinder("movies1.txt")));

    

    }

 

class ServiceLocator...
 
    public static void load(ServiceLocator arg) {
                
           soleInstance = arg;
          
    }
 
    public ServiceLocator(MovieFinder movieFinder) {
          
           this.movieFinder = movieFinder;  
 
     }

    Here's the test code.

 

    下面就是測試代碼。    

 

class Tester...

 

    public void testSimple() {
 
 
        configure();
 
        MovieLister lister = new MovieLister();
 
 
        Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
 
 
        assertEquals("Once Upon a Time in the West", movies[0].getTitle());
    }
 

I've often heard the complaint that these kinds of service locators are a bad thing because they aren't testable

 

because you can't substitute implementations for them. Certainly you can design them badly to get into this kind of

 

trouble, but you don't have to. In this case the service locator instance is just a simple data holder. I can easily

 

create the locator with test implementations of my services.

 

我經常聽到一些抱怨,說這些服務定位器如何如何不好,因為找不到替代實現而不可測試。當然,你的設計如果很差,自然會被這

 

類問題糾纏,但是你可以選擇好的設計。在本例中服務定位器只是如此簡單的資料容器,我很容易使用服務的測試實現來建立我的定位器。

 

For a more sophisticated locator I can subclass service locator and pass that subclass into the registry's class variable.

 

I can change the static methods to call a method on the instance rather accessing instance variables directly. I can provide

 

thread specific locators by using thread specific storage. All of this can be done without changing clients of service locator.

    對於更進階一點的定位器,我可以用子類繼承並且傳遞子類給註冊器的類變數(實現一個ServiceLocator的子類並且在初始化時傳遞給
soleInstance)。我可以修改靜態方法來調用ServiceLocator執行個體的一個方法而不是直接存取執行個體變數。(不是直接存取
soleInstance.movieFinder方法)。我還可以提供線程相關的儲存機制來提供線程相關的定位器。所有的這些都無需改變用戶端的服務定位器。
    A way to think of this is that service locator is a registry not a singleton. A singleton provides a simple way of 
implementing a registry, but that implementation decision is easily changed. 
    一種改進的辦法是:服務定位器仍然是註冊器而非singleton.singleton提供了一種簡單實現註冊機的辦法,但是那種實現很容易被改變。
Using a Segregated Interface for the Locator 對服務定位器採用隔離介面

One of the issues with the simple approach above, is that the MovieLister is dependent on the full service locator class,

 

even though it only uses one service. We can reduce this by using a segregated interface. That way, instead of using the

 

full service locator interface, the lister can declare just the bit of interface it needs.

 

以上所示範的簡單方法存在一個問題:MovieLister完全依賴service locator類,儘管它只是使用了一種服務。我們可以採用隔離介面來減少

 

這種依賴。那樣的話,MovieLister可以只是聲明它需要的介面,而不是使用整個service locator介面。

 

In this situation the provider of the lister would also provide a locator interface which it needs to get hold of the finder.

 

在這種情況之下,MovieLister的提供者也將提供一個locator介面,MovieLister需要這個locator介面來控制MovieFinder.

 

    

public interface MovieFinderLocator {
 
    public MovieFinder movieFinder();
 
 

The locator then needs to implement this interface to provide access to a finder.

 

服務定位器需要實現這個介面來提供對MovieFinder的訪問。

 

MovieFinderLocator locator = ServiceLocator.locator();
(如此隔離開不同服務的人使用的介面,叫做介面隔離,以免介面汙染)
 
MovieFinder finder = locator.movieFinder();
 
public static ServiceLocator locator() {
 
        return soleInstance;
 
}
public MovieFinder movieFinder() {
 
        return movieFinder;
}    
private static ServiceLocator soleInstance;    
private MovieFinder movieFinder;
 

You'll notice that since we want to use an interface, we can't just access the services through static methods any

 

more. We have to use the class to get a locator instance and then use that to get what we need.

 

你會發現因為我們使用了一個介面,我們不能再僅僅通過靜態方法來訪問服務,我們必須使用類來得到一個定位器執行個體,讓後通過該

 

執行個體得到我們要得到的服務。

 

A Dynamic Service Locator 動態服務定位器 

The above example was static, in that the service locator class has methods for each of the services that you need.

 

This isn't the only way of doing it, you can also make a dynamic service locator that allows you to stash any service

 

you need into it and make your choices at runtime.

 

以上是靜態定位器的例子,對於你所需要的每一項服務,service locator類都有對應的方法.這並不是實現服務定位器的唯一方式,你也

 

可以使用動態定位器,動態定位器允許你註冊任何你所需要的服務,並在運行期決定使用哪一項服務。

 

 

In this case, the service locator uses a map instead of fields for each of the services, and provides generic methods

 

to get and load services.

 

本例中,服務定位器使用map來代替每一個服務欄位,並且使用通用的方法來得到和定位服務。

 

class ServiceLocator...
    
private static ServiceLocator soleInstance;
    
public static void load(ServiceLocator arg) {
        
soleInstance = arg;
    
}
 
    private Map services = new HashMap();
 
    public static Object getService(String key){
 
        return soleInstance.services.get(key);
 
    }
 
    public void loadService (String key, Object service) {
 
        services.put(key, service);
 
    }
Configuring involves loading a service with an appropriate key.

 

同樣需要對服務定位器進行配置,將服務物件和適當的關鍵字載入到定位器中。

 

class Tester...
 
    private void configure() {
 
        ServiceLocator locator = new ServiceLocator();
 
        locator.loadService("MovieFinder", new ColonMovieFinder("movies1.txt"));
 
        ServiceLocator.load(locator);
 
    }

I use the service by using the same key string.

 

我使用與服務物件類名稱相同的字串作為關鍵字。

 

class MovieLister...
 
    MovieFinder finder = (MovieFinder) ServiceLocator.getService("MovieFinder");
 

On the whole I dislike this approach. Although it's certainly flexible, it's not very explicit. The only way I can

 

find out how to reach a service is through textual keys. I prefer explicit methods because it's easier to find where

 

they are by looking at the interface definitions.

 

大體上我並不喜歡這種方法。儘管他相當有彈性,但是它的使用方法不夠直觀明朗。我要定位一個服務只有通過文本形式的關鍵字。

 

我更喜歡直觀的方法,因為通過查看介面定義就很容易定位服務。

 

Using both a locator and injection with Avalon 

Dependency injection and a service locator aren't necessarily mutually exclusive concepts. A good example of using

 

both together is the Avalon framework. Avalon uses a service locator, but uses injection to tell components where

 

to find the locator.

 

依賴注入和服務定位並非相互排斥的概念。兩者全被使用的一個好的典範是Avalon 架構,Avalon使用了服務定位器,但是也使用了注入

 

來告訴組件如何找到定位器。

 

Berin Loritsch sent me this simple version of my running example using Avalon.

 

Berin Loritsch發了一個前面例子的Avalon的簡單版本給我。

 
public class MyMovieLister implements MovieLister, Serviceable {    
    private MovieFinder finder;    public void service( ServiceManager manager ) throws ServiceException {
 
        finder = (MovieFinder)manager.lookup("finder");
    }       

The service method is an example of interface injection, allowing the container to inject a service manager into MyMovieLister.

 

The service manager is an example of a service locator. In this example the lister doesn't store the manager in a field,

 

instead it immediately uses it to lookup the finder, which it does store.

 

service方法就是介面注入的一個例子。允許容器把服務管理員注入MyMovieLister.服務管理員是服務定位器的一個例子。在這個例子中,lister

 

並不以欄位的形式儲存manager,而是使用它立即找到MovieFinder,並以欄位的形式儲存MovieFinder.

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.