Внедрить зависимость от карты классов утилит - PullRequest
0 голосов
/ 08 июля 2019

У меня есть класс утилиты / констант, который содержит Map<String, Authorizer>, где Authorizer - это интерфейс с несколькими различными реализациями.Я использую карту в разных потоках, чтобы взять объект, который содержит String (название подхода авторизации), который затем сопоставляется с конкретным Authorizer, который затем завершает некоторую авторизацию.

Яиспользуя Guice для соединения классов Authorizer, но этот подход не позволяет мне сделать класс утилит (который содержит Map) настоящим классом утилит с пустым приватным конструктором.У меня есть причудливое решение, которое нравится и Guice, и Checkstyle, но я хочу знать, есть ли лучший способ.

Мой класс утилит:

public final class Constants {
  @Inject
  private Constants() {}

  public static final String AUTH_METHOD_ONE = "Auth1";
  public static final String AUTH_METHOD_TWO = "Auth2";

  @Singleton
  @Inject
  @Getter // For Checkstyle, as AUTH_METHODS isn't a true static final constant
  private static Map<String, Authorizer> authMethods;
}

Модуль моих констант:

public class ConstantsModule extends AbstractModule {
  @Override
  public void configure() {
    requestStaticInjection(Constants.class);
    final MapBinder<String, Authorizer> mapBinder = MapBinder.newMapBinder(binder(), String.class, Authenticator.class);
    mapBinder.addBinding(AUTH_METHOD_ONE).to(MethodOneAuthorizer.class);
    mapBinder.addBinding(AUTH_METHOD_TWO).to(MethodTwoAuthorizer.class);
  }
}

И пример использования:

public class AuthorizationOrchestrator {
  private static Authorizer getAuthorizer(final AuthorizationState state) {
    return state.getMethods().stream()
      .map(AuthorizationApproach::getAuthorizationApproachName)
      .filter(Constants.getAuthMethods().keySet()::contains)
      .findFirst()
      .map(Constants.getAuthMethods()::get)
      .orElse(null);
  }
}

Этот подход также требует некоторого использования PowerMock в модульных тестах.Есть ли лучший способ:

  • Сопоставить имена подходов авторизации с классом Authorizer, сохраняя сопоставление в одном месте?
  • Используйте класс Constants какнастоящий служебный класс с public static final Map<String, Authorizer> AUTH_METHODS, в то же время способный внедрить авторизаторы в Map?

1 Ответ

1 голос
/ 09 июля 2019

Не имеет смысла вводить что-то, что должно быть константой.

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

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

  • Используйте состав, чтобы избежать необходимости в служебном классе. Создайте реализацию Authorizer, состоящую из нескольких Authorizer s. Составной Authorizer может внутренне делегировать правильную «реальную» реализацию. Тогда вы можете просто ввести один Authorizer в любое место, где это необходимо. Это может быть невозможно в зависимости от того, как определен контракт Authorizer.

  • Сохранить логику без какого-либо состояния в служебном классе. Измените сигнатуру статического метода на getAuthorizer(AuthorizationState state, Map<String, Authorizer> availableAuthorizersByName). Затем вставьте карту AUTH_METHODS непосредственно в классы, которые будут вызывать ваш статический метод getAuthorizer, и передайте карту в качестве одного из аргументов методу.

  • Сделать getAuthorizer() не статичным. И внедрить карту непосредственно в экземпляр AuthorizationOrchestrator.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...