Service Locator 패턴 정보

회사에서 「Service Locator 패턴」이라는 단어를 듣고 「?」가 되었으므로, 계명도 포함해 조사해 본 메모.

갑자기 결론



결론에서 말하면 Service Locator 패턴도 Dependency Injection (이른바 DI ) 과 같이 클래스 간의 밀접한 결합도를 완화하기 위한 것이라고 생각해도 좋을 것 같다.

라고 할까, 여기 에 초참고가 되는 기술이 있으므로, 이것을 비망록으로서 남겨 둔다.

개요



DDD 또는 Repository 패턴에서 DI를 사용할 수 있지만 동일한 목적으로 사용할 수 있습니다.

무슨 샘플 코드



여기서는 도메인 계층이 인프라 계층에 의존하지 않도록 Repository 패턴을 사용하는 경우의 DI 버전과 Service Locator 버전을 각각 생각해 보자.

DI를 사용할 때 리포지토리 패턴





애플리케이션 계층
// アプリケーション層は、インフラ層とドメイン層の両方に依存
namespace ApplicationLayer
{
    using DomainLayer;
    using InfrastractureLayer;

    class BookSearchService
    {
        public string[] SearchByTitle(string title)
        {
            // リポジトリの実体を生成
            var bookRepositoryImpl = new BookRepositoryImpl();

            // ドメインオブジェクトを生成
            var bookLibrary = new BookLibrary(bookRepositoryImpl);

            // 検索結果取得
            return bookLibrary.Search(title);
        }
    }
}

도메인 계층
// ドメイン層はどの層にも依存しない
namespace DomainLayer
{
    // Repositoryのインターフェイス
    public interface IBookRepository
    {
        string[] GetBooksByTitle(string title);
    }

    public class BookLibrary
    {
        IBookRepository bookRepository;

        // DIによりリポジトリの実装を注入してもらう
        public BookLibrary(IBookRepository bookRepository)
        {
            this.bookRepository = bookRepository;
        }

        public string[] Search(string title)
        {
            // ありえないロジックになってるけど、サンプルなので・・・
            return bookRepository.GetBooksByTitle(title);
        }
    }
}

인프라 층
// インフラ層はドメイン層のみに依存する
namespace InfrastractureLayer
{
    using DomainLayer;

    // ドメイン層で定義されているRepositoryインターフェイスの実装
    public class BookRepositoryImpl : IBookRepository
    {
        public string[] GetBooksByTitle(string title)
        {
            // 処理内容省略。例えばSQLとかが記述される。
            string[] books;

            ...

            return books;
        }
    }
}

Service Locator를 사용할 때 리포지토리 패턴





↑ 귀찮게 되었기 때문에 , Repository 의 기저 인터페이스 및 기저 클래스를 생략.
어쩌면 클래스도 봐도 텐야 완야이므로, 소스 보는 편이 빠르다.
요점은, 종속성을 리스트화해 다른 클래스 ( ServiceLocator )로 보관 유지하고 있다.

애플리케이션 계층
// アプリケーション層は、インフラ層とドメイン層の両方に依存
namespace ApplicationLayerSL
{
    using DomainLayerSL;
    using InfrastractureLayerSL;

    class BookSearchService
    {
        public string[] SearchByTitle(string title)
        {
            // リポジトリを生成
            var bookRepositoryImpl = new BookRepositoryImpl();

            // ドメインオブジェクトを生成(あらかじめGenerateServiceLocatorメソッドでリポジトリに実装を登録していることが前提)
            var bookLibrary = new BookLibrary(ServiceLocator.Resolve<IBookRepository>());

            // 検索結果取得
            return bookLibrary.Search(title);
        }
    }

    class Generator
    {
        // ServiceLocatorにリポジトリのインターフェイスと実装の対を登録
        public void GenerateServiceLocator()
        {
            ServiceLocator.Register<IBookRepository, BookRepositoryImpl>();
        }
    }

    static class ServiceLocator
    {
        static readonly IDictionary<Type, Type> dictionary = new Dictionary<Type, Type>();

        // リポジトリのインターフェイスと実装の対を登録する
        public static void Register<TKey, TValue>()
            where TKey : IRepository
            where TValue : RepositoryImpl
        {
            dictionary.Add(typeof(TKey), typeof(TValue));
        }

        // リポジトリのインターフェイスから、リポジトリの実装を取得する
        public static TKey Resolve<TKey>()
            where TKey : IRepository
        {
            return (TKey)Activator.CreateInstance(dictionary[typeof(TKey)]);
        }
    }
}

도메인 계층(DI의 경우 Irepository를 추가하는 경우에만)
// ドメイン層はどこにも依存しない
namespace DomainLayerSL
{
    // リポジトリの基底インターフェイス
    public interface IRepository { }

    // 本のリポジトリ
    public interface IBookRepository : IRepository
    {
        string[] GetBooksByTitle(string title);
    }

    public class BookLibrary
    {
        IBookRepository bookRepository;

        // DIによりリポジトリの実装を注入してもらう
        public BookLibrary(IBookRepository bookRepository)
        {
            this.bookRepository = bookRepository;
        }

        public string[] Search(string title)
        {
            // ありえないロジックになってるけど、サンプルなので・・・
            return bookRepository.GetBooksByTitle(title);
        }
    }
}

인프라 계층(DI의 경우 RepositoryImpl 추가만)
// インフラ層はドメイン層のみに依存する
namespace InfrastractureLayerSL
{
    using DomainLayerSL;

    // リポジトリ実装の基底クラス
    public abstract class RepositoryImpl : IRepository { }

    // ドメイン層で定義されている本のリポジトリインターフェイスの実装
    public class BookRepositoryImpl : RepositoryImpl
    {
        public string[] GetBooksByTitle(string title)
        {
            // 処理内容省略。例えばSQLとかが記述される。
            string[] books;

            ...

            return books;
        }
    }
}

개인적인 해석



개인적으로는 Service Locator 패턴을 이하와 같이 이해해도 좋을까라고 생각하고 있다.

목적


  • DI와 동일하며 클래스 간의 종속성을 완화하는 데 사용됩니다.

    DI와 다른 점


  • Service Locator 패턴에서 인터페이스와 구현 쌍을 컬렉션으로 참조를 저장하고 필요할 때 생성하고 검색합니다.

    DI에 비해 우수한 점


  • 사용 방법에 따라 다르지만 전 세계적으로 액세스 할 수 있으므로 재사용 가능성이 높습니다

  • DI에 비해 떨어지는 점


  • 사용 방법에 따라 다르지만 전역 액세스로 인해 종속성이 보이지 않습니다
  • DI 의 경우는 의존 주입하는 인터페이스에만 의존하지만 Service Locator 패턴은 Service Locator 의 콜렉션 그 자체에 의존하기 때문에, 의존도가 높다 (그러나 Service Locator 에 의존해도 그렇게 문제 없습니까?)
  • 어쩌면 테스트에서 Mock을 준비 할 때 DI가 직관적이고 쉽습니다

  • 요약



    최초의 결론에도 썼지만, 목적으로서는 DI 를 사용하는 것과 같고, 클래스간을 느슨하게 결합하기 위해서 사용한다고 생각해 좋을 것 같다.
    지금 생각해내는 유효한 사용법으로서는, Repository 가 복수 있어, 그것을 Repository 의 Service Locator 로서 컬렉션으로 해 두어, 사용해 돌릴 수 있게 한다든가? 글쎄, 나쁘지 않습니까 ...
    우선 「Service Locator 패턴이~」라고 하는 대화로 「?」가 되는 것은 싫기 때문에, 비망록으로서 남긴다.

    참고로 한 사이트



  • Service Locator 및 Dependency Injection 패턴 및 DI Container
  • 여기에는 DI 컨테이너에 대한 추가 정보가 있습니다. Service Locator 패턴이나 DI 패턴을 조사하고 있는 분은, 절대로 이쪽을 보는 편이 좋습니다.


  • 보충



    조사해 보면, Service Locator 패턴은 안티 패턴으로서 들려지고 있는 경우가 상당히 있는 것 같다.
    비슷한 개념으로 DI 컨테이너가 있으므로, 시간이 있으면 이번에는 그쪽을 정리해 보고 싶다.

    좋은 웹페이지 즐겨찾기