Pregunta

Esta pregunta ya tiene una respuesta aquí:

Allen Holub escribió lo siguiente,

No puede tener un programa sin algún acoplamiento. No obstante, puede minimizar el acoplamiento considerablemente siguiendo los preceptos OO (orientados al objeto) (lo más importante es que la implementación de un objeto debe estar completamente oculta de los objetos que lo usan). Por ejemplo, las variables de instancia de un objeto (campos miembros que no son constantes) siempre deben ser privadas. Período. Sin excepciones. Alguna vez. Lo digo en serio. (Ocasionalmente puede usar métodos protegidos de manera efectiva, pero las variables de instancia protegidas son una abominación).

Que suena razonable, pero luego continúa diciendo

Debería Nunca use funciones get/set Por la misma razón: son formas demasiado complicadas de hacer público un campo (aunque las funciones de acceso que devuelven objetos en toda regla en lugar de un valor de tipo básico son razonables en situaciones en las que la clase del objeto devuelto es una abstracción clave en el diseño ).

Lo cual, francamente, me suena loco.

Entiendo el principio de esconder información, pero sin accesorios y mutantes no podrías usar frijoles java. No sé cómo seguirías un diseño de MVC sin accesorios en el modelo, ya que el modelo no puedo ser responsable de representar la vista.

Sin embargo, soy un programador más joven y aprendo más sobre el diseño orientado a objetos todos los días. Quizás alguien con más experiencia puede evaluar este tema.

Los artículos de referencia de Allen Holub


Preguntas relacionadas:

¿Fue útil?

Solución

No tengo ningún problema con Holub que te diga que generalmente debes evitar alterar el estado de un objeto, pero en cambio recurre a métodos integrados (ejecución de comportamientos) para lograr este fin. Como señala Corletk, hay sabiduría en pensar mucho en el nivel más alto de abstracción y no solo programar sin pensar con getters/setters que solo le permiten hacer un final de encapsulación.

Sin embargo, tengo muchos problemas con cualquiera que le diga que debe "nunca" usar setters o que "nunca" acceder a los tipos primitivos. De hecho, el esfuerzo requerido para mantener este nivel de pureza en todos Los casos pueden y terminarán causando más complejidad en su código que usar propiedades implementadas adecuadamente. Solo tiene que tener el sentido suficiente para saber cuándo está esquivando las reglas para la ganancia a corto plazo a expensas del dolor a largo plazo.

Holub no confía en que sepas la diferencia. Creo que saber la diferencia es lo que te convierte en un profesional.

Otros consejos

Lea ese artículo cuidadosamente. Holub está presionando el punto de que los obtentadores y los setters son un "antipatrón predeterminado" malvado, un mal hábito en el que nos deslizamos al diseñar un sistema; porque podemos.

El proceso de pensamiento debe estar en la línea; ¿Qué hace este objeto? hacer? ¿Cuáles son sus responsabilidades? ¿Cuáles son sus comportamientos? ¿Qué sabe? Pensar mucho y duro en estas preguntas lo lleva naturalmente hacia el diseño de clases que exponen la interfaz de más alto nivel posible.

Un coche es un buen ejemplo. Expone una interfaz de alto nivel estandarizada bien definida. No me preocupo por setSpeed(60)... ¿Eso es MPH o KM/H? Acabo de acelerar, navegar, desacelerar. No tengo que pensar en los detalles en setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5)), Yo solo turn(-1.5), y los detalles se cuidan bajo el capó.

Se reduce a "Puede y debe averiguar para qué se utilizará cada clase, qué hace, qué representa, y expone la interfaz de más alto nivel posible que cumple con esos requisitos. El programador es solo perezoso para hacer el análisis requerido para determinar exactamente qué es cada clase y no, por lo que avanzamos por el camino de "puede hacer cualquier cosa". ¡Los captadores y los setters son malvados!

A veces, los requisitos reales para una clase son incognoscibles con anticipación. Eso es genial, solo se está agotando y use el antipatrón Getter/Setter por ahora, pero cuando sabes, a través de la experiencia, para qué se está utilizando la clase, probablemente querrás regresar y limpiar la interfaz sucia de bajo nivel. La refactorización basada en "cosas que desearías saber cuando escribes el tonto en primer lugar" es la par del curso. No tiene que saber todo para comenzar, es solo que cuanto más sepa, es probable que se requiera más reelaboración en el camino.

Esa es la mentalidad que está promoviendo. Getters y Setters son una trampa fácil de caer.

Sí, los frijoles básicamente requieren getters y setters, pero para mí un frijol es un caso especial. Los frijoles representan sustantivos, cosas, objetos de identificación tangible (si no físico). No muchos objetos realmente tienen comportamientos automáticos; La mayoría de las veces las cosas son manipuladas por fuerzas externas, incluidos los humanos, para hacerlas cosas productivas.

daisy.setColor(Color.PINK) tiene mucho sentido. ¿Qué más puedes hacer? Tal vez una vulcana mentalidad, para hacer la flor desear ser rosa? ¿Mmm?

Los captadores y los setters tienen su malvado? lugar. Es simplemente, como todas las cosas realmente buenas, tendemos a usarlas en exceso, porque son seguras y familiarizadas, sin mencionar que son simples y, por lo tanto, podría ser mejor si los novatos no vieran o escuchen sobre ellos, al menos hasta que ellos '' D dominó la cosa mental.

Creo que lo que Allen Holub intentó decir, reformado en este Artículo, es el siguiente.

Getters y Setters pueden ser útiles para variables que desea específicamente encapsular, pero no tiene que usarlas para todas las variables. De hecho, usarlos para todas las variables es un olor a código desagradable.

Los programadores de problemas tienen, y Allen Holub tenía razón al señalarlo, es que a veces usan getters/setters para todas las variables. Y se pierde el propósito de la encapsulación.

(Tenga en cuenta que vengo a esto desde un ángulo de "propiedad" .net)

Bueno, simplemente, no estoy de acuerdo con él; Hace un gran alboroto que el tipo de devolución de propiedades es algo malo porque puede romper su código de llamadas, pero exactamente El mismo argumento se aplicaría a los argumentos del método. ¿Y si no puede usar métodos?

Ok, los argumentos del método podrían cambiarse como conversiones ampliantes, pero ... solo por qué ... también, tenga en cuenta que en C# el var La palabra clave podría mitigar mucho de este dolor percibido.

Los accesorios son no un detalle de implementación; Son la API / contrato pública. Sí, si rompes el contracft, tienes problemas. ¿Cuándo se convirtió en una sorpresa? Del mismo modo, no es raro que los accesorios no sean triviales, es decir, hacen más que sólo envolver campos; Realizan cálculos, verificaciones lógicas, notificaciones, etc. y permiten abstracciones de estado basadas en interfaz. Ah, y polimorfismo, etc.

Re la naturaleza detallada de los accesorios (P3? 4?) - En C#: public int Foo {get; private set;} - trabajo hecho.

En última instancia, todo el código es un medio para expresar nuestra intención al compilador. Propiedades Permítanme hacer eso de una manera polimórfica de una manera polimórfica a prueba, basada en contrato, verificable, extensible, gracias. ¿Por qué necesito "arreglar" esto?

Los getters y los setters se usan como poco más que una máscara para hacer pública una variable privada.

No tiene sentido repetir lo que Holub ya dijo, pero el quid de esto es que las clases deberían representar el comportamiento y no solo el estado.

Hice google adicional en Allen Holub, parece que tiene su parte de oponentes en la comunidad de Java.

El último es particularmente puntiagudo. El texto del comentarista está en cursiva.

Aunque GetIdentity comienza con "Get", no es un accesor porque no solo devuelve un campo. Devuelve un objeto complejo que tiene un comportamiento razonable

Oh, pero espera ... entonces está bien usar accesorios siempre que devuelva objetos en lugar de tipos primitivos? Ahora esa es una historia diferente, pero es tan tonta para mí. A veces necesitas un objeto, a veces necesitas un tipo primitivo.

Además, noto que Allen ha suavizado radicalmente su posición desde su columna anterior sobre el mismo tema, donde el mantra "nunca usa accesorios" no sufrió una sola excepción. Tal vez se dio cuenta después de unos años que los accesorios tienen un propósito después de todo ...

Tenga en cuenta que en realidad no he puesto ningún código de IU en la lógica de negocios. He escrito la capa de interfaz de usuario en términos de AWT (kit de herramientas de ventana abstracta) o swing, que son capas de abstracción.

Bueno. ¿Qué pasa si está escribiendo su aplicación en SWT? ¿Qué tan "abstracto" es realmente AWT en ese caso? Solo enfréntalo: este consejo simplemente lo lleva a escribir código de interfaz de usuario en su lógica de negocios. Qué gran principio. Después de todo, solo han pasado al menos diez años desde que identificamos esta práctica como una de las peores decisiones de diseño que puede tomar en un proyecto.

Mi problema es que un programador novato a veces está tropezando con artículos en Internet y darles más crédito de lo que debería. Quizás este es uno de esos casos.

Cuando se me presentan ideas como estas, me gusta echar un vistazo a las bibliotecas y marcos que uso y que me gusta usar.

Por ejemplo, aunque algunos no estarán de acuerdo, me gusta la API estándar Java. También me gusta el marco de primavera. Mirando las clases en estas bibliotecas, notará que rara vez hay setters y obtienen que están allí solo para exponer una variable interna. Hay métodos nombrada GetX, pero eso no significa que sea un obtenido en el sentido convencional.

Entonces, creo que tiene un punto, y es este: cada vez que presionas elige "Generar Getters/Setters" en Eclipse (o tu IDE de elección), debes dar un paso atrás y preguntarte qué estás haciendo. ¿Es realmente apropiado exponer esta representación interna, o arruiné mi diseño a algún paso?

No creo que esté diciendo que nunca use Get/Set, sino que usar GET/SET para un campo no es mejor que simplemente hacer que el campo (por ejemplo, el nombre de la cadena pública vs. Nombre de cadena pública {get; set;}).

Si se usa GET/SET, limita la información oculta de OO que potencialmente puede encerrarlo en una interfaz mala.

En el ejemplo anterior, el nombre es una cadena; ¿Qué pasa si queremos cambiar el diseño más tarde para agregar múltiples nombres? La interfaz expuso solo una sola cadena, por lo que no podemos agregar más sin romper la implementación existente.

Sin embargo, si en lugar de usar get/set, inicialmente tenía un método como agregar (nombre de cadena), internamente podría procesar el nombre singularmente o agregar a una lista o lo que no y llamar externamente el método Agregar tantas veces como desee agregar Más nombres.

El objetivo de OO es diseñar con un nivel de abstracción; No expongas más detalles de los que tienes que hacerlo.

Lo más probable es que si acaba de envolver un tipo primitivo con un Get/Set, ha roto este principio.

Por supuesto, esto es si crees en los objetivos OO; Encuentro que la mayoría no, en realidad no, solo usan los objetos como una forma convienable de agrupar el código funcional.

Las variables públicas tienen sentido cuando la clase no es más que un paquete de datos sin coherencia real, o cuando es realmente, muy elemental (como una clase de puntos). En general, si hay alguna variable en una clase que cree que probablemente no debería ser pública, eso significa que la clase tiene cierta coherencia, y las variables tienen una cierta relación que debe mantenerse, por lo que todas las variables deben ser privadas.

Los captadores y los setters tienen sentido cuando reflejan algún tipo de idea coherente. En una clase de polígono, por ejemplo, las coordenadas X e Y de los vértices dados tienen un significado fuera del límite de la clase. Probablemente tenga sentido tener Getters, y probablemente tenga sentido tener setters. En una clase de cuenta bancaria, el saldo probablemente se almacena como una variable privada, y casi seguramente debería tener un obtonente. Si tiene un setter, necesita tener el registro incorporado para preservar la auditabilidad.

Hay algunas ventajas de Getters y Setters en las variables públicas. Proporcionan cierta separación de la interfaz e implementación. Solo porque un punto tiene un .getX() la función no significa que tenga que haber una X, ya que .getX() y .setX() Se puede hacer que funcione bien con coordenadas radiales. Otra es que es posible mantener invariantes de clase, haciendo lo que sea necesario para mantener la clase consistente dentro del setter. Otra es que es posible tener una funcionalidad que se desencadena en un conjunto, como el registro para el saldo de la cuenta bancaria.

Sin embargo, para clases más abstractas, las variables miembros pierden importancia individual y solo tienen sentido en el contexto. No necesita conocer todas las variables internas de una clase de transmisión C ++, por ejemplo. Necesita saber cómo obtener elementos dentro y fuera y cómo realizar varias otras acciones. Si contó con la estructura interna exacta, estaría empantanado en detalle que podría variar arbitrariamente entre compiladores o versiones.

Entonces, diría que usa variables privadas casi exclusivamente, obtiene y setters donde tienen un significado real en el comportamiento de los objetos, y no de otra manera.

El hecho de que los getters y los setters con frecuencia se usen en exceso no significa que sean inútiles.

El problema con Getters/Setters es que intentan fingir encapsulación, pero en realidad lo rompen exponiendo sus partes internas. En segundo lugar, están tratando de hacer dos cosas separadas, proporcionando acceso y controlando su estado, y terminan haciendo tampoco muy bien.

Rompe la encapsulación porque cuando llama un método Get/Set, primero necesita saber el nombre (o tiene una buena idea) del campo que desea cambiar, y segundo debe saber su tipo, por ejemplo. No pudiste llamar

setPositionX("some string");

Si conoce el nombre y el tipo de campo, y el setter es público, entonces cualquiera puede llamar al método como si fuera un campo público de todos modos, es solo una forma más complicada de hacerlo, entonces, ¿por qué no simplificarlo y hacerlo? Es un campo público en primer lugar.

Al permitir el acceso a su estado, pero tratando de controlarlo al mismo tiempo, un método Get/Set solo confunde las cosas y termina siendo una placa de caldera inútil o engañosa, al no hacer lo que dice que hace al tener un lado- Efectos el usuario podría no esperar. Si se necesita verificación de errores, podría llamarse algo como

public void tryPositionX(int x) throws InvalidParameterException{
    if (x >= 0)
        this.x = x;
    else
        throw new InvalidParameterException("Holy Negatives Batman!");
}

o si se necesita código adicional, podría llamarse un nombre más preciso basado en lo que hace todo el método, por ejemplo.

tryPositionXAndLog(int x) throws InvalidParameterException{
    tryPositionX(x);
    numChanges++;
}

En mi humilde opinión, necesita obtener Getters/Setters para que algo funcione a menudo es un síntoma de mal diseño. Utilice el principio "decir, no preguntar", o repensar por qué un objeto necesita enviar sus datos de estado en primer lugar. Exponga métodos que cambian el comportamiento de un objeto en lugar de su estado. Los beneficios de eso incluyen un mantenimiento más fácil y una mayor extensibilidad.

Usted menciona también MVC y dice que un modelo no puede ser responsable de su opinión, de ese caso Allen Holub ofrece un ejemplo de hacer una capa de abstracción al tener una "clase dada-me-jcomponent-that-representantes, tu clase de identidad" que dice "aislaría la forma en que las identidades se representan del resto del sistema". No tengo la experiencia suficiente para comentar si eso funcionaría o no, pero en la superficie suena una idea decente.

Los compradores/setters públicos son malos si proporcionan acceso a los detalles de implementación. Sin embargo, es razonable proporcionar acceso a las propiedades de Object y usar Getters/Setters para esto. Por ejemplo, si el automóvil tiene la propiedad de color, es aceptable permitir que los clientes lo "observen" usando un Getter. Si algún cliente necesita la capacidad de recolorar un automóvil, la clase puede proporcionar un setter ('Recolor' es un nombre más claro). Es importante no informar a los clientes cómo se almacenan las propiedades en los objetos, cómo se mantienen, y así sucesivamente.

Ummmm ... nunca ha oído hablar del concepto de encapsulación. Se establecen métodos de Getter y Setter para controlar el acceso a los miembros de una clase. Al hacer que todos los campos sean visibles públicamente ... cualquiera podría escribir cualquier valor que les quisiera invalidar por completo todo el objeto.

En caso de que alguien sea un poco confuso en el concepto de encapsulación, lea aquí:

Encapsulación (informática)

... y si son realmente malvados, ¿el concepto de propiedad construiría el concepto de propiedad en el idioma? (Métodos de Getter y Setter que se ven un poco más bonitos)

EDITAR

El artículo menciona la encapsulación:

"Getters y Setters pueden ser útiles para variables que desea específicamente encapsular, pero no tiene que usarlas para todas las variables. De hecho, usarlos para todas las variables es un olor a código desagradable."

El uso de este método conducirá a un código extremadamente difícil de mantener a largo plazo. Si se entera a la mitad de un proyecto que abarca años que un campo debe estar encapsulado, tendrá que actualizar cada referencia de ese campo en todas partes en su software para obtener el beneficio. Suena mucho más inteligente para usar la encapsulación adecuada en la parte delantera y seguro el dolor de cabeza más tarde.

Creo que los compradores y los setters solo deben usarse para variables a las que se necesita acceder o cambiar fuera de una clase. Dicho esto, no creo que las variables sean públicas a menos que sean estáticas. Esto se debe a que hacer que las variables sean públicas que no son estáticas pueden hacer que se cambien indeseablemente. Supongamos que tiene un desarrollador que usa descuidadamente variables públicas. Luego accede a una variable de otra clase y sin significado, la cambia. Ahora tiene un error en su software como resultado de este accidente. Es por eso que creo en el uso adecuado de Getters y Setters, pero no los necesita para cada variable privada o protegida.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top