Является ли хорошей практикой замена констант, используемых вне классов, геттерами?
Как пример, лучше использовать if User.getRole().getCode() == Role.CODE_ADMIN
или if User.getRole().isCodeAdmin()
?
Это привело бы к этому классу:
class Role {
constant CODE_ADMIN = "admin"
constant CODE_USER = "user"
private code
getRoleCode() {
return Role.code
}
isCodeAdmin () {
return Role.code == Role.CODE_ADMIN
}
isCodeUser () {
return Role.code == Role.CODE_USER
}
}
object-oriented
перейти к
источник
источник
User.HasRole(Role.Admin)
.User.getRole().getCode()
это уже неприятное чтение, сравнение Кодекса с Ролью делает его еще более неловким.Ответы:
Прежде всего, обратите внимание, что выполнение чего-то подобного
entity.underlyingEntity.underlyingEntity.method()
считается запахом кода согласно Закону Деметры . Таким образом, вы раскрываете много деталей реализации потребителю. И каждая необходимость расширения или модификации такой системы будет очень больно.Поэтому, учитывая это, я бы порекомендовал вам использовать метод
HasRole
илиIsAdmin
вUser
соответствии с комментарием CodesInChaos. Таким образом, способ реализации ролей для пользователя остается деталью реализации для потребителя. Кроме того, более естественно спрашивать пользователя о его роли, а не спрашивать его о деталях его роли, а затем принимать решение на основе этого.Пожалуйста, также избегайте использования
string
s, если это необходимо.name
хороший примерstring
переменной, потому что ее содержимое неизвестно заранее. С другой стороны, что-то вроде того,role
где у вас есть два разных значения, которые хорошо известны во время компиляции, вам лучше использовать строгую типизацию. Вот где в игру вступает тип перечисления ...сравнить
с
Второй случай дает мне гораздо больше представления о том, что я должен обойти. Это также препятствует тому, чтобы я ошибочно передал инвалид
string
в случае, если я понятия не имел о ваших константах роли.Далее следует решение о том, как будет выглядеть роль. Вы можете использовать enum, который хранится непосредственно у пользователя:
С другой стороны, если вы хотите, чтобы ваша роль имела собственное поведение, она обязательно должна снова скрыть детали того, как определяется ее тип:
Это, однако, довольно многословно, и сложность возрастает с каждым добавлением роли - обычно так заканчивается код, когда вы пытаетесь полностью придерживаться закона Деметры. Вы должны улучшить дизайн, основываясь на конкретных требованиях моделируемой системы.
В соответствии с вашим вопросом, я думаю, вам лучше выбрать первый вариант с включенным enum
User
. Если вам нужно больше логикиRole
, второй вариант следует рассматривать как отправную точку.источник
X
, безусловно, позволит вам создавать строки вызовов функций, напримерX.foo().bar().fee()...
. В этом свободном интерфейсе foo, bar и fee все будут функциями внутри класса,X
возвращающими объект типаX
. Но для instance.property.property.method (), упомянутого в этом примере, эти дваproperty
вызова фактически будут в отдельных классах. Проблема в том, что вы проходите через несколько уровней абстракции, чтобы овладеть деталями низкого уровня.instance.property.property.method()
не обязательно является нарушением или даже запахом кода; это зависит от того, работаете ли вы с объектами или структурами данных.Node.Parent.RightChild.Remove()
Вероятно, не является нарушением LoD (хотя вонючий по другим причинам).var role = User.Role; var roleCode = role.Code; var isAdmin = roleCode == ADMIN;
это почти наверняка нарушение, несмотря на то, что я всегда «использовал только одну точку».instance.property.property.method()
это нарушение LoD, но у OPinstance.method().method()
должно быть все в порядке. В вашем последнем примере есть так много стандартного кода,User
который служит только фасадом дляRole
.Кажется глупым иметь функцию, чтобы проверить, является ли сохраненный код кодом администратора. То, что вы действительно хотите знать, является ли этот человек администратором. Поэтому, если вы не хотите раскрывать константы, вам также не следует раскрывать наличие кода и вызывать методы isAdmin () и isUser ().
Тем не менее, «если User.getRole (). GetCode () == Role.CODE_ADMIN» действительно полезен только для проверки того, что пользователь является администратором. Сколько вещей нужно помнить разработчику, чтобы написать эту строку? Он или она должны помнить, что у пользователя есть роль, у роли есть код, а у класса Role есть константы для кодов. Это много информации, которая просто о реализации.
источник
В дополнение к тому, что уже опубликовали другие, вы должны иметь в виду, что использование константы напрямую имеет еще один недостаток: если что-то изменит то, как вы обрабатываете права пользователя, все эти места тоже нужно изменить.
И это делает ужасным улучшение. Может быть, вы хотели бы иметь суперпользовательский тип в один момент, который, очевидно, также имеет права администратора. С инкапсуляцией, это в основном однострочное добавление.
Он не только короткий и чистый, но и простой в использовании и понимании. И - может быть, больше всего - трудно ошибиться.
источник
Хотя я в значительной степени согласен с предложениями избегать констант и иметь метод
isFoo()
и т. Д., Один возможный контрпример.Если существуют сотни таких констант, а вызовы используются мало, возможно, не стоит затрачивать усилия на написание сотен методов isConstant1, isConstant2. В этом конкретном, необычном случае использование констант является разумным.
Обратите внимание, что использование перечислений или
hasRole()
избавление от необходимости писать сотни методов, так что это лучший из всех возможных в мире.источник
Я не думаю, что любой из представленных вами вариантов в корне неверен.
Я вижу, вы не предложили одну вещь, которую я бы назвал категорически неправильной: жесткое программирование кодов ролей в функциях вне класса Role. То есть:
Я бы сказал, это определенно неправильно. Я видел программы, которые делают это, а затем получают загадочные ошибки, потому что кто-то неправильно записал строку. Я вспоминаю один раз, когда программист писал «сток», когда функция проверяла «сток».
Если бы было 100 разных ролей, я бы очень неохотно написал 100 функций для проверки каждой возможной. Предположительно, вы создали бы их, написав первую функцию, а затем скопировав и вставив ее 99 раз, и сколько бы вы поспорили, что в одной из этих 99 копий вы забудете обновить тест или выйдете на одну из них, когда Вы пробежали по списку, поэтому у вас есть
Лично я бы также избегал цепочек звонков. Я бы лучше написал
тогда
и в этот момент, почему примечание напишите:
Затем сообщите классу User, как проверить роль.
источник