1前書き

このチュートリアルでは、JavaでのService Locatorデザインパターンについて学びます。

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


2パターンを理解する

  • Service Locatorパターンの目的は、サービスインスタンスをオンデマンドで返すことです** これは、サービスコンシューマを具象クラスから切り離すのに役立ちます。

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

  • クライアント – クライアントオブジェクトはサービスコンシューマです。責任は

サービスロケータから要求を呼び出す

  • サービスロケータ – を返すための通信エントリポイントです。

キャッシュからのサービス

  • Cache – 後で参照するためにサービス参照を保存するためのオブジェクト

  • Initializer – サービスへの参照を作成して登録します。

キャッシュ

  • サービス – サービスコンポーネントは元のサービスを表します。

それらの実装

元のサービスオブジェクトはロケータによって検索され、要求に応じて返されます。


3実装

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

まず、さまざまな方法でメッセージを送信するための

MessagingService

インターフェイスを作成します。

public interface MessagingService {

    String getMessageBody();
    String getServiceName();
}

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

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<MessagingService> 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();

  • 最初に

    ServiceLocatorから

    EmailServiceを取得したときに、新しいインスタンスが作成されて返されます。その後、それを呼び出した後、

    EmailService

    がキャッシュから返されます。


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

一見すると、サービスロケータパターンは別のよく知られているパターン、すなわち依存性注入に似ているかもしれません。

最初に、Dependency InjectionとService Locatorパターンの両方がInversion of Controlの概念の実装であることに注意することが重要です。

先に進む前に、このリンクでDependency Injectionについて詳しく学んでください。

  • ここでの主な違いは、クライアントオブジェクトがまだ依存関係を作成していることです。そのためにロケーターを使用するだけです。つまり、ロケーターオブジェクトへの参照が必要です。

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

最後に、Service Locatorパターンを使用しないようにするためのいくつかの理由を考えてみましょう。

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

もう1つの問題は、このパターンに基づいてAPIを使用するのが面倒だということです。

これは、依存関係がクラス内に隠されており、実行時にのみ検証されるためです。

にもかかわらず、Service Locatorパターンはコーディングと理解が容易で、小規模なアプリケーションには最適な選択肢となります。


6. 結論

このガイドでは、Service Locatorデザインパターンの使用方法と使用方法について説明します。

Service LocatorのデザインパターンとDependency Injectionの概念の主な違いについて説明します。

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

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

いつものように、完全なコードはhttps://github.com/eugenp/tutorials/tree/master/patterns/design-patterns[Githubプロジェクト]にあります。