Возврат определенных пользователем объектов с использованием внедрения зависимостей

1

Я использую Ninject для инъекции зависимостей, и у меня он хорошо работает при передаче основных типов, но я не уверен в том, как лучше всего структурировать приложение, когда начну передавать пользовательские типы объектов.

Вот простой пример. У меня есть 4 проекта: Main, Project A, Project B и Interfaces. Основные ссылки ProjectA, ProjectB и интерфейсы, а также интерфейсы Project A и ProjectB refrence.

В интерфейсах я определил интерфейс IClassA, который имеет единственный метод, который возвращает int.

public interface IClassA
{
    int ReturnFundamental();
}

В ProjectA у меня есть ClassA, который реализует IClassA.

public class ClassA : IClassA
{
    public int ReturnFundamental()
    {
        return 1;
    }
}

ProjectB содержит ClassB, который принимает IClassA как инъекцию зависимостей на основе конструктора. Он также предоставляет метод, который позволяет мне вызвать метод, определенный в IClassA и реализованный в ClassA.

public class ClassB
{
    private readonly IClassA classA;
    public ClassB(IClassA classA)
    {
        this.classA = classA;
    }
    public void GetObject()
    {
        Console.WriteLine(classA.ReturnFundamental());
    }
}

Основной проект устанавливает Ninject, привязывает IClassA к ClassA, создает экземпляр класса ClassB и вызывает метод в ClassB.

static void Main(string[] args)
{
    IKernel kernel = new StandardKernel();
    kernel.Bind<IClassA>().To<ClassA>();
    var classB = kernel.Get<ClassB>();
    classB.GetObject();
    Console.Read();
}

Все это отлично работает, ClassB может вызывать метод в ClassA и возвращает значение. Однако, если я не хочу возвращать базовый тип, но вместо этого хочу вернуть настраиваемый объект, который я определил, какой самый лучший способ сделать это?

Если я не ошибаюсь, тогда IClassA, ClassA и ClassB будут нуждаться в ссылке на этот объект, и определение его в том же проекте, что и ClassA или ClassB, вызывает связь, которая использовалась для инъекций зависимостей.

Поэтому единственное решение, о котором я могу думать, это либо:

  1. Объявить все объекты в проекте "Интерфейсы"

  2. Создайте еще один проект, чтобы поместить все объекты, которые используются для передачи данных между интерфейсами.

  3. Создайте новый проект, содержащий все объекты, необходимые для одного взаимодействия между классами, где каждое взаимодействие имеет собственный проект, он ссылается на все объекты, которые он требует.

Проблема, которую я вижу с первым вариантом, заключается в том, что неясно, какие объекты используются для каких классов, и я опасаюсь, что проект "Интерфейсы" станет слишком большим, содержащий слишком много информации в одном месте.

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

Третий вариант, по крайней мере, дает понять, какие взаимодействия классов требуют, какие объекты будут объединены вместе, однако это приведет к созданию множества проектов.

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

Теги:
architecture
dependency-injection
ninject

1 ответ

1
Лучший ответ

Нет необходимости создавать проект интерфейса. То, что обычно делает, это объявить реализацию (-details) как внутреннюю и интерфейсы как общедоступные. Например.

public class PersonInfo
{
    string FirstName { get; set; }
    string Surname { get; set; }
    Address Address { get; set; }
}

public interface IPersonSearchService
{
    IEnumerable<PersonInfo> Search(string keyword);
}

internal class PersonSearchService : IPersonSearchService
{
    ....
}

теперь вы добавляете NinjectModule:

public class PersonSearchServiceModule : NinjectModule 
{
    public override void Load()
    {
        this.Bind<IPersonSearchService>().To<PersonSearchService>();
    }
}

и в корне композиции (Application Project, Main Project,.. whatchamacallit) вы загружаете модуль, либо явно с помощью kernel.Load<PersonSearchServiceModule>() либо весь Module одной (или нескольких) сборки с помощью kernel.Load(IEnumerable<Assembly>).

Использование Feature-Namespaces также является хорошей идеей.

  • 0
    Но тогда каждый проект, который должен вызывать этот интерфейс, должен ссылаться на весь проект, включая сам класс. Разве это не разрушает точку DI для разъединения? В случае, если это уместно, моя идея разделения интерфейсов на их собственный проект была взята из этого руководства Microsoft .
  • 0
    Какой момент именно побежден этим? ;-) Конечно, я согласен, что это не совсем то же самое, что поместить интерфейсы в отдельные проекты, и иногда это может быть необходимо или разумно, но в подавляющем большинстве случаев это не так. Пример, в котором полезно иметь интерфейс в отдельном проекте, - это когда вы определяете интерфейс точки расширения, реализация которой неизвестна приложению и может быть добавлена позже (-> плагин!).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню