Evite getters y setters, mostrando información del usuario

10

Antecedentes

Estoy leyendo el "Libro de código limpio" y, paralelamente, estoy trabajando en objetos calisténicos Kata como la cuenta bancaria, y estoy atascado en esa regla:

La novena regla de los objetos calisténicos es que no usamos getter o setters.

Parece bastante divertido, y estoy de acuerdo con este principio. Además, en la página 98-99 de Clean Code, el autor explica que los captadores / establecedores rompen la abstracción, y que no tenemos que preguntarle a nuestro objeto, sino que debemos decirle a nuestro objeto.

Esto tiene mucho sentido en mi mente, y estoy totalmente de acuerdo con este principio. El problema viene en la práctica.

Contexto

Por ejemplo, tengo una aplicación en la que tengo que enumerar algunos usuarios y mostrar los detalles del usuario.

Mi usuario está compuesto por:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

Problema

¿Cómo puedo hacer o qué puedo hacer para evitar captadores cuando solo necesito mostrar una información simple ( y tengo que confirmar que no necesito una operación adicional en ese campo en particular ) para mostrar el valor de Nombre en un simple ( aleatorio) soporte de salida?

Lo que viene a mi mente

Una solución es hacer:

user.getName().getFirstName().getStringValue()

Lo cual es terriblemente terrible, que rompe muchas reglas de objetos calisténicos y viola la Ley Demeter.

Otro sería algo como:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

Pero no me siento cómodo con esta solución, que solo parece ser un "acceso de orden superior", como evitar el captador / configurador estándar con un método que solo tiene como objetivo coincidir con la ley de Demeter ...

Alguna idea ?

mfrachet
fuente

Respuestas:

17

La idea errónea común sobre la idea de evitar captadores y establecedores es evitarlos en todas partes, lo cual es imposible cuando se llega a la superficie de su arquitectura interactuando con el usuario.

Debe evitar usar getters y setters en la parte de lógica de negocios de su aplicación, donde los objetos deben protegerse utilizando agregados que proporcionen contexto, y los métodos deben actuar como comandos.

Para evitar captadores y establecedores, puede diseñar una solución similar a la programación reactiva , implementando un sistema de informes a través de entidades observables, pero esto complica extremadamente la arquitectura y no tiene sentido en el nivel CRUD de su aplicación, a pesar de que el diseño es realmente bueno para las interfaces de usuario.

Si debe considerar el uso de getters / setters depende completamente de la parte de la aplicación en la que está trabajando actualmente. Si su preocupación es que la interfaz de usuario que usa getters esté completamente bien, para lógica de negocios, donde ejecutaría una parte de un código basado en un valor recuperado a través de un getter, no tanto (esto grita que la lógica debería haberse encapsulado realmente dentro de la clase a la que está llamando el captador).

Además, la ley de demeter no se trata de contar puntos, sino simplemente de separar una clase que proporciona contexto mediante el uso de getters en la clase para obtener sus componentes a los que no debería tener acceso por sí mismo.

Si cree que su interfaz de usuario es demasiado profunda dentro de sus modelos de negocio, puede pensar en introducir los modelos de vista en su sistema, siendo responsable de transformar partes específicas de los modelos en representaciones visuales.

Andy
fuente
Bien, pienso en esa sugerencia como un mapeador entre mi entidad de dominio, a un DTO personalizado para mi capa de presentación que tendría algunos accesores ¿verdad?
mfrachet
@Margin Bastante, sí.
Andy
Todo esto en cascada suena muy bien y suave, gracias por la respuesta;)
mfrachet
2

Una dirección para pensar sería proporcionar una función de miembro de formato de cadena genérica, en lugar de proporcionar acceso a los datos sin procesar. Algo como esto:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

Verá, con este enfoque, no está limitado a proporcionar los datos completos tal como están, sino que puede proporcionar medios para transformar los datos de manera conveniente y significativa. Por ejemplo, es posible que deba jugar trucos con mayúsculas y minúsculas:

String accountName = user.formatDescription("$(firstname).$(lastname)");

También podría definir algunos formatos comúnmente utilizados, posiblemente complejos, una vez, por lo que podría decir, por ejemplo

String fullAddress = user.formatDescription(User.kAddressFormat);

La belleza de este enfoque es que mantiene las cadenas individuales internas de la Userclase, al tiempo que proporciona una funcionalidad significativamente mayor al código de llamada. Sin embargo, la desventaja es que debe implementar el mecanismo de plantilla dentro del formatDescription()cual habrá algunas líneas de código.

Como tal, esto podría ser una exageración total: nunca olvide que los principios de programación son solo pautas. Y siempre que seguir otro principio viole el principio de KISS, lo mejor es hacerlo de la manera más sencilla. Entonces, a menos que tenga al menos alguna necesidad de un miembro de formato de este tipo, no me molestaría en implementarlo por simplicidad, utilizando el enfoque basado en el descriptor de acceso.

cmaster - restablecer monica
fuente
55
Esto, sin embargo, me parece una violación de SRP. ¿Es realmente responsabilidad de un Userobjeto analizar y compilar / interpretar un lenguaje de plantillas?
Jörg W Mittag
@ JörgWMittag No necesariamente. Como dije, el principio KISS tiene prioridad. Y no dije en ninguna parte que la Userclase tiene que implementar esta funcionalidad por sí misma. Si solo tuviera dos clases que necesitaran dicha funcionalidad, podría apostar a que factorice el mecanismo de reemplazo de plantilla en su propia clase. Esto está destinado a ser un ejemplo de cómo puede elevar la abstracción que Userproporciona a un nivel en el que en realidad es más que un simple contenedor de datos. Y creo que de eso se trata evitar los accesos: hacer OOP en lugar de manejar un montón de structs.
cmaster - reinstalar a monica el
¿Sabes que KISS es totalmente subjetivo y objetivo de SRP? KISS no te dice nada sobre QUÉ hacer. Y lo que es "simple" para usted puede no ser "simple" para mí. Veo una diferencia real en la calidad si discutimos con KISS o SRP.
oopexpert