Избегайте циклических ссылок со службами и DI - PullRequest
3 голосов
/ 15 апреля 2011

У меня есть сервисная сборка с несколькими классами обслуживания. Каждый класс группирует набор связанных методов обслуживания. Эти службы создаются с использованием IoC и инжекторов конструктора.

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

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

public class UserService
{
    public void RegisterUser(User user)
    {
        // Do a bunch of stuff needed to register a user

        // Now call out to permission service to set up basic permissions
        _permissionService.SetUpBasicPermissions(user);
    }
}

public class PermissionService
{
    public void GrantPermission(User user, int PermissionId)
    {
        // Add user permission to database

        // Now call out to user service to do some other stuff on the user
        _userService.TakeActionsOnUserAccount(user);
    }
}

Вот варианты, которые я вижу:

  1. Учитывая, что функциональность должна быть разделена между двумя, это признак того, что классы обслуживания должны быть объединены в один класс. Если это так, могу ли я в конечном итоге получить один гигантский класс обслуживания? Что определяет, как они должны быть разделены?

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

  3. Любые действия, необходимые из одного сервиса в другой, должны быть перенесены в вызывающий код. Это кажется проблематичным для меня, так как я бы убрал потенциально зависимую логику и сделал бы ее проблемой другого уровня. Другими словами, где бы я ни вызывал _userService.RegisterUser (), теперь мне всегда придется вызывать _permissionService.SetUpBasicPermissions () сразу после каждого вызова.

  4. Разрешить одной службе вызывать другую, но не обе. Если это так, какой из них выбрать? Что мне делать с логикой для одного, который не может вызвать другого?

  5. Использование делегатов для внедрения зависимых методов обслуживания в вызываемые методы обслуживания. Блин, это звучит ужасно.

Это те, о которых я могу думать, но я уверен, что есть некоторые, которые я пропускаю.

Мысли

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 15 апреля 2011
  1. Принципы SRP states that every object should have a single responsibility, поэтому объединять классы нельзя.
  2. Это способ, которым придумано наследование, используйте абстрактные классы для общего кода и специализируйтесь после (не используйте ссылки)
  3. Логика зависимостей плохая, RegisterUser должен делать только этот регистр, а не давать разрешения. Можно переместить зависимость в вызывающий слой.
  4. Делайте это только в том случае, если вы должны, это должно быть немного понятно после того, как вы создадите класс abstrat. Попробуйте составить объект, хотя.
  5. Он называется контейнером, и вам следует лучше понять его после прочтения: http://www.potstuck.com/2009/01/08/php-dependency-injection

Что касается циклических ссылок, принципы ООП говорят только об избежании циклических ссылок между абстрактными и конкретными классами (Голливудский принцип), что не так. Можно использовать их, как и вы.

Однако вы очень хорошо используете Dependency Injection, так что вы можете извлечь SetUpBasicPermissions и поместить его вне класса.

objUser = new User();
objUserService.RegisterUser(objUser);
objPermissionService.SetUpBasicPermissions(objUser);
1 голос
/ 15 апреля 2011

Если вы хотите, чтобы обе службы ссылались друг на друга, вам нужно использовать Property Injection (или метод), а не конструктор, чтобы их можно было полностью создать до того, как он будет передан другому классу.

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

...