サービスロケーターパターン

サービスロケーターパターン

1. 前書き

このチュートリアルでは、the Service Locator design pattern in Javaについて学習します。

概念を説明し、例を実装し、その使用の長所と短所を強調します。

2. パターンを理解する

The purpose of the Service Locator pattern is to return the service instances on demand.これは、サービスコンシューマーを具象クラスから切り離すのに役立ちます。

実装は、次のコンポーネントで構成されます。

  • クライアント-クライアントオブジェクトはサービスコンシューマです。 サービスロケーターからのリクエストを呼び出す責任があります

  • Service Locator –サービスをキャッシュから返すための通信エントリポイントです

  • キャッシュ-後で再利用するためにサービス参照を保存するためのオブジェクト

  • 初期化子-キャッシュ内のサービスへの参照を作成および登録します

  • サービス–サービスコンポーネントは、元のサービスまたはその実装を表します

元のサービスオブジェクトはロケーターによって検索され、オンデマンドで返されます。

3. 実装

それでは、実用的になって、例を通して概念を見てみましょう。

まず、さまざまな方法でメッセージを送信するためのMessagingServiceインターフェースを作成します。

public interface MessagingService {

    String getMessageBody();
    String getServiceName();
}

次に、メールとSMSを介してメッセージを送信する上記のインターフェースの2つの実装を定義します。

public class EmailService implements MessagingService {

    public String getMessageBody() {
        return "email message";
    }

    public String getServiceName() {
        return "EmailService";
    }
}

SMSServiceクラスの定義は、EmailServiceクラスに似ています。

2つのサービスを定義したら、それらを初期化するロジックを定義する必要があります。

public class InitialContext {
    public Object lookup(String serviceName) {
        if (serviceName.equalsIgnoreCase("EmailService")) {
            return new EmailService();
        } else if (serviceName.equalsIgnoreCase("SMSService")) {
            return new SMSService();
        }
        return null;
    }
}

サービスロケーターオブジェクトをまとめる前に必要な最後のコンポーネントはキャッシュです。

この例では、これはListプロパティを持つ単純なクラスです。

public class Cache {
    private List services = new ArrayList<>();

    public MessagingService getService(String serviceName) {
        // retrieve from the list
    }

    public void addService(MessagingService newService) {
        // add to the list
    }
}

最後に、サービスロケータークラスを実装できます。

public class ServiceLocator {

    private static Cache cache = new Cache();

    public static MessagingService getService(String serviceName) {

        MessagingService service = cache.getService(serviceName);

        if (service != null) {
            return service;
        }

        InitialContext context = new InitialContext();
        MessagingService service1 = (MessagingService) context
          .lookup(serviceName);
        cache.addService(service1);
        return service1;
    }
}

ここでのロジックはかなり単純です。

クラスはCache.のインスタンスを保持します。次に、getService()メソッドで、最初にサービスのインスタンスのキャッシュをチェックします。

次に、それがnull,の場合、初期化ロジックを呼び出して、新しいオブジェクトをキャッシュに追加します。

4. テスト

今すぐインスタンスを取得する方法を見てみましょう。

MessagingService service
  = ServiceLocator.getService("EmailService");
String email = service.getMessageBody();

MessagingService smsService
  = ServiceLocator.getService("SMSService");
String sms = smsService.getMessageBody();

MessagingService emailService
  = ServiceLocator.getService("EmailService");
String newEmail = emailService.getMessageBody();

The first time we get the EmailService from the ServiceLocator a new instance is created and returned。 次に、それを呼び出した後、EmailServiceがキャッシュから返されます。

5. サービスロケーターと依存性注入

一見すると、Service Locatorパターンは、別のよく知られているパターン、つまりDependency Injectionに似ているように見えます。

まず、both Dependency Injection and the Service Locator pattern are implementations of the Inversion of Control conceptに注意することが重要です。

先に進む前に、このwrite-upでの依存性注入について詳しく学んでください。

The key difference here is that the client object still creates its dependencies。 そのためにロケーターを使用するだけです。つまり、ロケーターオブジェクトへの参照が必要です。

比較すると、依存性注入を使用すると、クラスに依存性が与えられます。 インジェクターは、起動時に一度だけ呼び出され、依存関係をクラスに注入します。

最後に、ServiceLocatorパターンの使用を避けるいくつかの理由を考えてみましょう。

それに対する1つの議論は、ユニットテストを困難にするということです。 依存性注入を使用すると、依存クラスのモックオブジェクトをテスト対象のインスタンスに渡すことができます。 一方、これはService Locatorパターンのボトルネックです。

もう1つの問題は、このパターンに基づいてAPIを使用するのが難しいことです。 これは、依存関係がクラス内に隠されており、実行時にのみ検証されるためです。

これらすべてにもかかわらず、「Service Locator」パターンはコーディングと理解が容易であり、小規模なアプリケーションに最適です。

6. 結論

このガイドでは、Service Locatorデザインパターンを使用する方法と理由を示します。 Service Locatorの設計パターンと依存性注入の概念の主な違いについて説明します。

一般に、アプリケーションでクラスを設計する方法を選択するのは開発者次第です。

Service Locatorパターンは、コードを分離する単純なパターンです。 ただし、複数のアプリケーションでクラスを使用する場合、依存性注入は正しい選択です。

いつものように、完全なコードはGithub projectで入手できます。