Подтвердить что ты не робот

Реализация лестничной площадки

Я столкнулся с описанием шаблона "Stairway" в книге "Adaptive code via С#", и я действительно не понимаю, как это должно быть реализовано:

Stairway pattern (source)

Итак, у меня есть клиентская сборка:

using ServiceInterface;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            // Have to create service implementation somehow
            // Where does ServiceFactory belong?
            ServiceFactory serviceFactory = new ServiceFactory();
            IService service = serviceFactory.CreateService();
            service.Do();
        }
    }
}

Сборка интерфейса службы:

namespace Service
{
    public interface IService
    {
        void Do();
    }
}

И сборка службы:

using ServiceInterface;

namespace ServiceImplementation
{
    public class PrintService : IService
    {
        public void Do()
        {
            Console.WriteLine("Some work done");
        }
    }
}

И возникает вопрос: как получить объект IService в пространстве имен Client? Где я должен разместить фактическое создание объекта new PrintService()? Это не может быть частью ServiceInterface, поскольку сборка интерфейса не зависит от ServiceImplementation. Но он также не может быть частью Client или ServiceImplementation, потому что Client должен зависеть только от ServiceInterface.

Единственное решение, с которым я пришел, - это иметь сборку Application поверх нее, которая имеет ссылки на все три (Client, ServiceInterface и ServiceImplementation) и вставляет IService в Client. Я что-то пропустил?

4b9b3361

Ответ 1

Точки входа в приложение должны быть корнем композиции, как замечает Марк Земанн в книге "Инъекция зависимостей". Здесь проблема больше связана с инверсией зависимостей, при которой оба клиента и реализация должны зависеть от абстракций.

То, что эта диаграмма не показывает, но, мы надеемся, другие части книги ясно показывают, что точка входа будет естественно и обязательно ссылаться на все, что необходимо для создания любых ваших корней разрешения (контроллеры, службы и т.д.), Но это единственное место, где есть такие знания.

Имейте в виду, что иногда клиентам достаточно "владеть" интерфейсами, от которых они зависят: интерфейс ISecurityService может жить в сборке Controllers, IUserRepository может жить в сборке ServiceImplementations, и так далее. Это нецелесообразно, когдa > 1 клиент нуждается в доступе к интерфейсу, конечно.

Если вы следуете SOLID, вы, естественно, обнаружите, что инъекция зависимостей является необходимой, но контейнеры с инверсией управления не имеют приоритета. Я все чаще использую Pure Dependency Injection (ручное построение разрешающих корней).

Ответ 2

В этом случае проект Client должен содержать ссылки как на Service, так и на ServiceImplementation. Эти ссылки будут использоваться только для создания контейнера IoC, который будет использоваться как DI. При запуске приложения вам необходимо зарегистрировать все реализации интерфейса в контейнере IoC.

Если вы реализуете интерфейс ServiceImplementation против Service, и вы будете кодировать Client на основе Service intereface, тогда не будет зависимости от ServiceImplementation.

Вы также можете увидеть, как шаблон Stairway реализован в образцах для "Adaptive Code via С#":

https://github.com/garymcleanhall/AdaptiveCode/tree/master/Sprints/sample-sprint2-markdown

Ответ 3

Я бы поместил его в ServiceFactory. Вам нужен какой-то параметр, например. передается в конструкторе factory или извлекается из конфигурации и т.д., который определяет, какая реализация IService создается factory.