¿Es una buena práctica reemplazar las constantes utilizadas fuera de las clases por los captadores?
Como ejemplo, ¿es mejor usar if User.getRole().getCode() == Role.CODE_ADMIN
o if User.getRole().isCodeAdmin()
?
Eso llevaría a esta clase:
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
}
}
User.HasRole(Role.Admin)
.User.getRole().getCode()
ya es una lectura desagradable, comparar un Código con un Rol lo hace aún más desgarbado.Respuestas:
En primer lugar, tenga en cuenta que hacer algo como
entity.underlyingEntity.underlyingEntity.method()
se considera un olor a código según la Ley de Demeter . De esta manera, está exponiendo muchos detalles de implementación al consumidor. Y cada necesidad de extensión o modificación de dicho sistema dolerá mucho.Entonces, dado eso, te recomiendo que tengas un método
HasRole
oIsAdmin
método según elUser
comentario de CodesInChaos. De esta forma, la forma en que se implementan los roles en el usuario sigue siendo un detalle de implementación para el consumidor. Y también se siente más natural preguntarle al usuario cuál es su rol en lugar de preguntarle sobre los detalles de su rol y luego decidir basándose en eso.También evite usar
string
s a menos que sea necesario.name
es un buen ejemplo destring
variable porque los contenidos son desconocidos de antemano. Por otro lado, algo así comorole
donde tiene dos valores distintos que son bien conocidos en el momento de la compilación, será mejor que use una escritura fuerte. Ahí es donde entra en juego el tipo de enumeración ...Comparar
con
El segundo caso me da mucha más idea de lo que debería estar pasando. También me impide pasar erróneamente un inválido
string
en caso de que no tuviera idea de las constantes de su rol.Lo siguiente es la decisión sobre cómo se verá el papel. Puede usar enum directamente almacenado en el usuario:
Por otro lado, si desea que su rol tenga un comportamiento en sí mismo, definitivamente debería ocultar nuevamente los detalles de cómo se decide su tipo:
Sin embargo, esto es bastante detallado y la complejidad aumentaría con cada adición de roles; por lo general, así es como termina el código cuando intenta adherirse completamente a la Ley de Demeter. Debe mejorar el diseño, en función de los requisitos concretos del sistema que se está modelando.
Según su pregunta, supongo que será mejor que elija la primera opción con enum directamente
User
. Si necesita más lógica sobre elRole
, la segunda opción debe considerarse como un punto de partida.fuente
X
sin duda le permitiría hacer cadenas de llamadas a funciones comoX.foo().bar().fee()...
. En esta interfaz fluida, foo, bar y fee serían funciones dentro de la clase queX
devuelven un objeto de tipoX
. Pero para el 'instance.property.property.method () mencionado en este ejemplo, las dosproperty
llamadas en realidad estarían en clases separadas. El problema es que estás pasando por varias capas de abstracción para obtener detalles de bajo nivel.instance.property.property.method()
no es necesariamente una violación o incluso un olor a código; depende de si está trabajando con objetos o estructuras de datos.Node.Parent.RightChild.Remove()
probablemente no sea una violación de LoD (aunque maloliente por otras razones).var role = User.Role; var roleCode = role.Code; var isAdmin = roleCode == ADMIN;
es casi seguro una violación, a pesar del hecho de que siempre "usé solo un punto".instance.property.property.method()
es una violación de la LoD, pero el OP tieneinstance.method().method()
que debería estar bien. En su último ejemplo, hay tanto código repetitivoUser
que solo sirve como fachada para elRole
.Parece una tontería tener una función para verificar si el código que se almacena es el código de administrador. Lo que realmente quieres saber es si esa persona es un administrador. Entonces, si no desea exponer las constantes, tampoco debe exponer que hay un código y llamar a los métodos isAdmin () y isUser ().
Dicho esto, "if User.getRole (). GetCode () == Role.CODE_ADMIN" es realmente un puñado solo para verificar que un usuario es un administrador. ¿Cuántas cosas debe recordar un desarrollador para escribir esa línea? Debe recordar que un usuario tiene un rol, un rol tiene un código y la clase Role tiene constantes para los códigos. Esa es una gran cantidad de información que se trata únicamente de la implementación.
fuente
Además de lo que otros ya han publicado, debe tener en cuenta que usar la constante directamente tiene otro inconveniente: si algo cambia la forma en que maneja los derechos de usuario, todos esos lugares también deben cambiarse.
Y hace que sea horrible mejorarlo. Tal vez le gustaría tener un tipo de superusuario en un punto, que obviamente también tiene derechos de administrador. Con la encapsulación, es básicamente una línea para agregar.
No solo es corto y limpio, también es fácil de usar y comprender. Y, tal vez sobre todo, es difícil equivocarse.
fuente
Si bien estoy en gran medida de acuerdo con las sugerencias para evitar constantes y tener un método
isFoo()
, etc., un posible contraejemplo.Si hay cientos de estas constantes, y las llamadas son poco utilizadas, puede que no valga la pena escribir cientos de métodos isConstant1, isConstant2. En este caso particular e inusual, el uso de las constantes es razonable.
Tenga en cuenta que el uso de enumeraciones o
hasRole()
evita la necesidad de escribir cientos de métodos, por lo que es el mejor de todos los mundos posibles.fuente
No creo que ninguna de las opciones que presentó sea fundamentalmente incorrecta.
Veo que no ha sugerido lo único que llamaría totalmente erróneo: codificar los códigos de función en funciones fuera de la clase Role. Es decir:
Yo diría que definitivamente está mal. He visto programas que hacen esto y luego obtienen errores misteriosos porque alguien escribió mal la cadena. Recuerdo una vez que un programador escribió "stock" cuando la función estaba buscando "Stock".
Si hubiera 100 roles diferentes, sería muy reacio a escribir 100 funciones para verificar cada posible. Presumiblemente los crearía escribiendo la primera función y luego copiándola y pegándola 99 veces, y cuánto desea apostar a que en una de esas 99 copias olvidaría actualizar la prueba o se saldría por una cuando revisaste la lista, así que ahora tienes
Personalmente, también evitaría las cadenas de llamadas. Prefiero escribir
luego
y en ese punto por qué escribir nota:
Luego, deje que la clase Usuario sepa cómo verificar un rol.
fuente