Практический вопрос о синдроме и зависимости от инъекций
Скажем, у меня есть класс под названием PermissionManager, который должен существовать только один раз для моей системы и в основном выполняет функцию управления различными разрешениями для различных действий в моем приложении. Теперь у меня есть некоторый класс в моем приложении, который должен иметь возможность проверять определенное разрешение в одном из своих методов. Этот конструктор классов в настоящее время является общедоступным, т.е. Используется пользователями API.
До тех пор, пока пару недель назад я просто попросил бы мой класс вызвать следующий псевдокод:
PermissionManager.getInstance().isReadPermissionEnabled(this)
Но так как я заметил, что все здесь, ненавидящие одиночные пары + подобную связь, мне было интересно, какое лучшее решение было бы, так как аргументы, которые я прочитал против синглетов, кажутся имеющими смысл (не проверяемый, высокая связь и т.д.),.
Итак, нужно ли мне на самом деле требовать от пользователей API передать экземпляр PermissionManager в конструкторе класса? Хотя мне нужен только один экземпляр PermissionManager для моего приложения?
Или я все об этом ошибаюсь и должен иметь непубличный конструктор и factory где-нибудь, что передается мне в экземпляр PermissionManager?
Дополнительная информация Обратите внимание, что когда я говорю "Injection Dependency", я говорю о DI Pattern... Я не использую никаких рамок DI, таких как Guice или Spring. (... пока)
Ответы
Ответ 1
Если вы используете фреймворк зависимостей, тогда общий способ справиться с этим состоит в том, чтобы либо передать объект PermissionsManager в конструкторе, либо иметь свойство типа PermissionsManager, которое устанавливает для вас инфраструктура.
Если это невозможно, то получение пользователями этого класса через factory является хорошим выбором. В этом случае factory передает конструктору PermissionManager в конструктор, когда он создает класс. При запуске приложения сначала создайте единственный PermissionManager, затем создайте свой factory, пройдя в PermissionManager.
Вы правы, что для клиентов класса обычно неудобно знать, где найти правильный экземпляр PermissionManager и передать его (или даже заботиться о том, что ваш класс использует PermissionManager).
Одно компромиссное решение, которое я видел, - дать вашему классу свойство типа PermissionManager. Если свойство было установлено (например, в unit test), вы используете этот экземпляр, иначе вы используете singleton. Что-то вроде:
PermissionManager mManager = null;
public PermissionManager Permissions
{
if (mManager == null)
{
return mManager;
}
return PermissionManager.getInstance();
}
Конечно, строго говоря, ваш PermissionManager должен реализовывать какой-то интерфейс IPermissionManager и , что ваш другой класс должен ссылаться, так что фиктивная реализация может быть легче заменена во время тестирования.
Ответ 2
Вы действительно можете начать с ввода PermissionManager. Это сделает ваш класс более подверженным тестированию.
Если это вызывает проблемы для пользователей этого класса, вы можете использовать их с помощью метода factory или абстрактного factory. Или вы можете добавить конструктор без параметров, который для их вызова, который вводит PermissionManager, в то время как ваши тесты используют другой конструктор, который вы можете использовать, чтобы высмеять PermissionManager.
Разделение ваших классов еще больше повышает гибкость ваших классов, но также может затруднить их использование. Это зависит от ситуации, в которой вы будете нуждаться. Если у вас есть только один PermissionManager и нет проблем с тестированием классов, которые его используют, тогда нет причин использовать DI. Если вы хотите, чтобы люди могли добавлять свою собственную реализацию PermissionManager, тогда DI - это путь.
Ответ 3
Если вы подписываетесь на способ инъекции зависимостей, какие бы классы ни нуждались в вашем PermissionManager
, он должен был быть введен как экземпляр объекта. Механизм, который контролирует его создание (для обеспечения синергетического характера), работает на более высоком уровне. Если вы используете инфраструктуру инъекций зависимостей, такую как Guice, она может выполнять работу по обеспечению соблюдения. Если вы проводите проводку объектов вручную, инъекция зависимостей помогает группировать код, который делает экземпляр (новую работу оператора) подальше от вашей бизнес-логики.
В любом случае, классический синглтон Capital-S обычно рассматривается как анти-шаблон в контексте инъекции зависимостей.
Эти сообщения были проницательны для меня в прошлом:
Ответ 4
Итак, нужно ли мне на самом деле требовать от пользователей API передать экземпляр PermissionManager в конструкторе класса? Хотя мне нужен только один экземпляр PermissionManager для моего приложения?
Да, это все, что вам нужно сделать. Независимо от того, является ли зависимость одиночной/на каждый запрос/на поток или метод factory, несет ответственность за ваш контейнер и конфигурацию. В мире .net мы в идеале должны были бы зависеть от интерфейса IPermissionsManager для дальнейшего уменьшения связи, я полагаю, что это тоже лучшая практика на Java.
Ответ 5
Одноэлементный шаблон не плох сам по себе, что делает его уродливым - это то, как он обычно используется, как требование только для того, чтобы иметь только один экземпляр определенного класса, который, по моему мнению, является большой ошибкой.
В этом случае я сделаю PermissionManager статическим классом, если по какой-либо причине вам не понадобится его тип.