Конструкция, управляемая доменом: доступ к настроенному значению из сущности без использования локатора служб - PullRequest
7 голосов
/ 31 января 2012

У меня есть объект User, у которого есть свойство HasCompletedSecurity, которое указывает, ответил ли конкретный User на число вопросов безопасности, требуемых системой.Количество вопросов безопасности, которые требует система, настраивается и извлекается из файла конфигурации.Как класс User должен получить доступ к сконфигурированной информации?

В настоящее время у меня есть интерфейс IConfigurationService, за которым у меня есть реализации, использующие ConfigurationManager или эквивалент Azure, если он доступен.Я инкапсулировал доступ к своему контейнеру DI через статический класс InjectionService, и в настоящее время разрешаю сконфигурированное значение следующим образом:

public class User
{
    private static readonly IConfigurationService _configurationService = 
        InjectionService.Resolve<IConfigurationService>();

    public bool HasCompletedSecurity
    {
        get
        {
            // Uses the static _configurationService to get the 
            // configured value:
            int numberOfRequiredResponses = 
                GetConfiguredNumberOfRequiredResponses();

            return this.SecurityQuestionResponses.Count()
                >=
                GetConfiguredNumberOfRequiredResponses();
        }
    }
}

Это, конечно, пример антивирусного ServiceLocatorобразец , и мне не нравится это немного.Статическая зависимость затрудняет юнит-тестирование всего, что использует этот класс.

Я использую Entity Framework и принимаю подсказку от здесь Я не хочу передавать свои сущности через DIконтейнер, чтобы дать им их зависимости, так что ... как должен Вместо этого я получаю доступ к сконфигурированному значению?

Редактировать : с этим точным примером в одну сторону (иЯ действительно ценю предложения относительно правильной архитектуры для него), более важный вопрос, который меня интересует, - как вы управляете нестатическими ссылками на сервисы от сущностей?Является ли ответ только на то, чтобы спроектировать сущности таким образом, что вам никогда не понадобится?

Ответы [ 2 ]

5 голосов
/ 31 января 2012

Вот как я бы определил класс User:

public class User
{
    public bool HasCompletedSecurity { get; set; }

    // other members...
}

Серьезно, это лучшее решение, потому что оно разъединяет значение вдоль временного измерения .Подумайте об этом: если пользователь выполнил все вопросы безопасности в 2010 году и позже вы измените бизнес-правило, собираетесь ли вы аннулировать существующего пользователя?

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

1 голос
/ 31 января 2012

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

public interface ISecurityPolicy
{
    public int MinimumSecurityQuestionResponses { get; }
}

public class User
{
    public void HasCompletedSecurity (ISecurityPolicy security_policy)
    {
         return this.SecurityQuestionResponses.Count()
                     >= security_policy.MinimumSecurityQuestionResponses;
    }
}

Это возлагает ответственность за предоставление конкретной политики безопасности, которой должен соответствовать пользователь, на вызывающую сторону , а не на сам класс User.

С этого момента вы можете предоставить этот дополнительный параметр по своему усмотрению, возможно, заключив его в IUserSecurityService, в который ISecurityPolicy будет введен сервис, и т. Д.

Это все еще инверсия управления, но она находится на уровне метода, поскольку этот единственный конкретный метод действительно заботится о политике / конфигурации безопасности.

...