É uma boa prática substituir constantes usadas fora das classes por getters?
Como exemplo, é melhor usar if User.getRole().getCode() == Role.CODE_ADMIN
ou if User.getRole().isCodeAdmin()
?
Isso levaria a essa classe:
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
vamos para
fonte
fonte
User.HasRole(Role.Admin)
.User.getRole().getCode()
já é uma leitura desagradável, comparando um código a um papel o torna ainda mais desagradável.Respostas:
Primeiro, observe que fazer algo como
entity.underlyingEntity.underlyingEntity.method()
é considerado um cheiro de código de acordo com a Lei de Demeter . Dessa forma, você está expondo muitos detalhes de implementação ao consumidor. E cada necessidade de extensão ou modificação de um sistema desse tipo prejudicará muito.Portanto, eu recomendo que você tenha um método
HasRole
ouIsAdmin
noUser
comentário de CodesInChaos. Dessa maneira, a maneira como as funções são implementadas no usuário permanece sendo o detalhe da implementação para o consumidor. E também parece mais natural perguntar ao usuário qual é o seu papel, em vez de perguntar sobre detalhes de seu papel e decidir com base nisso.Evite também usar
string
s, a menos que seja necessário.name
é um bom exemplo destring
variável porque o conteúdo é desconhecido de antemão. Por outro lado, algo comorole
onde você tem dois valores distintos que são bem conhecidos no momento da compilação, é melhor usar uma digitação forte. É aí que o tipo de enumeração entra em jogo ...Comparar
com
O segundo caso me dá muito mais idéia do que eu deveria estar passando. Também me impede de passar erroneamente um inválido
string
, caso eu não tenha idéia das constantes de sua função.Em seguida, está a decisão sobre como será o papel. Você pode usar enum diretamente armazenado no usuário:
Por outro lado, se você deseja que seu papel tenha um comportamento próprio, ele definitivamente deve ocultar novamente os detalhes de como seu tipo está sendo decidido:
No entanto, isso é bastante detalhado e a complexidade aumentaria a cada adição de função - geralmente é assim que o código termina quando você tenta aderir totalmente à Lei de Demeter. Você deve melhorar o design, com base nos requisitos concretos do sistema que está sendo modelado.
De acordo com sua pergunta, acho melhor você ir com a primeira opção com enum diretamente
User
. Se você precisar de mais lógicaRole
, a segunda opção deve ser considerada como ponto de partida.fonte
X
certamente permitiria que você fizesse sequências de chamadas de funçãoX.foo().bar().fee()...
. Nessa interface fluente, foo, bar e fee seriam funções dentro da classeX
retornando um objeto do tipoX
. Mas para o 'instance.property.property.method () mencionado neste exemplo, as duasproperty
chamadas seriam realmente em classes separadas. O problema é que você está passando por várias camadas de abstração para obter detalhes de baixo nível.instance.property.property.method()
não é necessariamente uma violação ou mesmo um cheiro de código; depende se você está trabalhando com objetos ou estruturas de dados.Node.Parent.RightChild.Remove()
provavelmente não é uma violação do LoD (embora fedorento por outros motivos).var role = User.Role; var roleCode = role.Code; var isAdmin = roleCode == ADMIN;
é quase certamente uma violação, apesar do fato de eu sempre "usar apenas um ponto".instance.property.property.method()
é uma violação do LoD, mas o OP tem oinstance.method().method()
que deve estar bem. No seu último exemplo, há muito código padrãoUser
que serve apenas como fachada para oRole
.Parece idiota ter uma função para verificar se o código armazenado é o código de administrador. O que você realmente quer saber é se essa pessoa é um administrador. Portanto, se você não deseja expor as constantes, também não deve expor que existe um código e chame os métodos isAdmin () e isUser ().
Dito isto, "se User.getRole (). GetCode () == Role.CODE_ADMIN" é realmente um punhado apenas para verificar se um usuário é um administrador. Quantas coisas um desenvolvedor precisa lembrar para escrever essa linha? Ele ou ela deve se lembrar de que um usuário tem uma função, uma função tem um código e a classe Role tem constantes para códigos. Muitas informações são puramente sobre a implementação.
fonte
Além do que outras pessoas já postaram, lembre-se de que o uso direto da constante tem outra desvantagem: se algo mudar a maneira como você lida com os direitos do usuário, todos esses locais também precisam ser alterados.
E torna horrível melhorar. Talvez você queira ter um tipo de superusuário em algum momento, que obviamente também tenha direitos de administrador. Com o encapsulamento, é basicamente uma linha a ser adicionada.
Não é apenas curto e limpo, também é fácil de usar e entender. E - talvez acima de tudo - é difícil errar.
fonte
Embora eu concorde amplamente com as sugestões para evitar constantes e ter um método
isFoo()
etc., um possível contra-exemplo.Se houver centenas dessas constantes e as chamadas forem pouco usadas, pode não valer a pena o esforço de escrever centenas de métodos isConstant1, isConstant2. Nesse caso particular e incomum, o uso das constantes é razoável.
Observe que o uso de enums ou
hasRole()
evita a necessidade de escrever centenas de métodos, por isso é o melhor de todo o mundo possível.fonte
Não acho que nenhuma das opções que você apresentou esteja fundamentalmente errada.
Vejo que você não sugeriu a única coisa que eu chamaria totalmente errada: codificar os códigos de função em funções fora da classe Role. Isso é:
Eu diria que está definitivamente errado. Eu já vi programas que fazem isso e, em seguida, recebem erros misteriosos porque alguém digitou errado a string. Lembro-me de uma vez que um programador escreveu "estoque" quando a função estava verificando "estoque".
Se houvesse 100 funções diferentes, eu ficaria muito relutante em escrever 100 funções para verificar todas as possíveis. Presumivelmente, você os criaria escrevendo a primeira função, copiando e colando 99 vezes, e quanto deseja apostar que em uma dessas 99 cópias você esquecerá de atualizar o teste ou sairá uma quando você percorreu a lista, agora você tem
Pessoalmente, eu também evitaria as ligações. Prefiro escrever
então
e nesse ponto, por que a nota escreve:
Em seguida, informe à classe Usuário como verificar uma função.
fonte