Allen Holub escribió "Nunca debes usar las funciones get/set", ¿es correcto? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Allen Holub escribió lo siguiente,

No puedes tener un programa sin algún acoplamiento. Sin embargo, puede minimizar el acoplamiento considerablemente siguiendo servilmente los preceptos OO (orientados a objetos) (el más importante es que el implementación de un objeto debe estar completamente oculto de los objetos que lo utilizan). Por ejemplo, las variables de instancia de un objeto (campos miembros que no son constantes) siempre deben ser privadas. Periodo. Excepción. Nunca. Lo digo en serio. (Ocasionalmente puede usar métodos protegidos de manera efectiva, pero las variables de instancia protegidas son una abominación.)

Lo cual suena razonable, pero luego continúa diciendo,

Debe nunca usar las funciones get/set para por la misma razón, son formas demasiado complicadas de hacer público un campo (aunque las funciones de acceso que devuelven objetos completos 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 parece una locura.

Entiendo el principio de ocultar información, pero sin accesores y mutadores no se podría utilizar Java beans en absoluto. No se como seguirías un diseño MVC sin accesores en el modelo, ya que el modelo no puede ser responsable de renderizar 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. Tal vez alguien con más experiencia pueda opinar sobre este tema.

Los artículos de Allen Holub para referencia


Preguntas relacionadas:

Author: Community, 2009-06-15

13 answers

No tengo ningún problema con Holub diciéndole que generalmente debe evitar alterar el estado de un objeto, sino que debe recurrir a métodos integrados (ejecución de comportamientos) para lograr este fin. Como señala Corletk, hay sabiduría en pensar largo y duro sobre el más alto nivel de abstracción y no solo programar sin pensar con getters/setters que solo te permiten hacer una encapsulación final.

Sin embargo, tengo muchos problemas con cualquiera que te dice que "nunca" debes usar setters o que" nunca " debes acceder a tipos primitivos. De hecho, el esfuerzo requerido para mantener este nivel de pureza en todos los casos puede y terminará causando más complejidad en su código que el uso de propiedades implementadas adecuadamente. Solo tienes que tener suficiente sentido común para saber cuándo estás eludiendo las reglas para obtener ganancias a corto plazo a expensas del dolor a largo plazo.

Holub no confía en ti para saber la diferencia. Creo que conocer la la diferencia es lo que te hace un profesional.

 38
Author: Mark Brittingham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-16 13:41:19

Creo que lo que Allen Holub trató de decir, reformulado en este artículo, es lo siguiente.

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

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

 31
Author: Suvesh Pratapa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-08 17:27:26

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

El proceso de pensamiento debe ser a lo largo de las líneas; ¿Qué hace este objeto ? ¿Cuáles son sus responsabilidades? ¿Cuáles son sus comportamientos? ¿Qué sabe? Pensar largo y tendido en estas preguntas te lleva naturalmente a diseñar clases que expongan el más alto nivel interfaz posible.

Un coche es un buen ejemplo. Expone una interfaz de alto nivel bien definida y estandarizada. No me preocupo por setSpeed(60)... ¿eso es MPH o km / h? Solo acelero, cruzo, desacelero. No tengo que pensar en los detalles en setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5)), solo turn(-1.5), y los detalles se cuidan bajo el capó.

Se reduce a "Puede y debe averiguar para qué se usará cada clase, qué hace, qué representa y exponer el nivel más alto interfaz posible que cumple con esos requisitos. Los getters y setters suelen ser un cop-out, cuando el programador es demasiado perezoso para hacer el análisis necesario para determinar exactamente qué es y qué no es cada clase, y así vamos por el camino de "puede hacer cualquier cosa". Getters y setters son malos!

A veces los requisitos reales para una clase son incognoscibles antes de tiempo. Eso es genial, solo cop-out y usar getter / setter antipattern por ahora, pero cuando sabes, a través de la experiencia, lo que la clase se está utilizando para, probablemente querrá volver y limpiar la sucia interfaz de bajo nivel. La refactorización basada en" cosas que deseas saber cuando escribes al tonto en primer lugar " es parte del curso. Usted no tiene que saber todo con el fin de hacer un comienzo, es solo que cuanto más se sabe, menos es probable que se requiera un trabajo de repetición en el camino.

Esa es la mentalidad que está promoviendo. Los getters y setters son una trampa fácil de caer.

Sí, frijoles básicamente requieren getters y setters, pero para mí un frijol es un caso especial. Los frijoles representan sustantivos, cosas, objetos tangibles identificables (si no físicos). En realidad, no muchos objetos 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 fusión mental vulcana, para hacer que la flor quiera ser rosa? Hmmm?

Los getters y setters tienen su ?¿malvado? lugar. Es solo que, como todas las cosas realmente buenas, tendemos a abusar de ellas, porque son seguras y familiares, por no mencionar simples, y por lo tanto podría ser mejor si los noobs no las vieran u oyeran hablar de ellas, al menos hasta que dominaran la fusión mental.

 30
Author: corlettk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-04 19:42:15

(nota que estoy llegando a esto desde un ángulo de "propiedad". NET)

Bueno, simplemente - no estoy de acuerdo con él; hace un gran alboroto sobre el tipo de retorno de propiedades que es una mala cosa porque puede romper su código de llamada - pero exactamente el mismo argumento se aplicaría a los argumentos de método. ¿Y si tampoco puedes usar métodos?

OK, los argumentos del método podrían cambiarse como conversiones de ampliación, pero.... por qué... Además, tenga en cuenta que en C# la palabra clave var podría mitigar este dolor percibido.

Los accesores son no un detalle de implementación; son la API / contrato público. Sí, si rompes el contrato tienes problemas. ¿Cuándo se convirtió eso en una sorpresa? Del mismo modo, no es raro que los accesores no sean triviales, es decir, hacen más que solo campos de wrap; realizan cálculos, comprobaciones lógicas, notificaciones, etc. Y permiten abstracciones de estado basadas en interfaces. Ah, y polimorfismo-etc.

Re la naturaleza detallada de 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. Las propiedades me permiten hacer eso de una forma polimórfica, segura, basada en contratos, verificable, extensible, gracias. ¿Por qué tengo que" arreglar " esto?

 10
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 13:56:42

Los getters y 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 deben representar el comportamiento y no solo el estado.

 8
Author: cletus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 13:49:15

Hice algunas búsquedas adicionales en Google en Allen Holub, parece que tiene su cuota de oponentes por ahí 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 accessor porque no solo devuelve un campo. Devuelve un complejo objeto que tiene un comportamiento razonable

Oh, pero espera... entonces, ¿está bien usar accesores siempre y cuando devuelvas objetos en lugar de tipos primitivos? Esa es una historia diferente, pero es igual de 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 uses accessors" no sufrió ni una sola salvedad. Tal vez se dio cuenta después de unos años que los accesores sirven a un propósito después de todo...

Tenga en cuenta que en realidad no he puesto ningún código de interfaz de usuario en la lógica de negocio. He escrito la capa de interfaz de usuario en términos de AWT (Abstract Window Toolkit) o Swing, que son ambas capas de abstracción.

Buena. ¿Qué pasa si está escribiendo su solicitud en SWT? ¿Qué tan "abstracto" es realmente AWT en ese caso? Solo acéptalo: este consejo simplemente te lleva para escribir código de interfaz de usuario en su lógica de negocio. 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 puedes tomar en un proyecto.

Mi problema es que un programador novato a veces se tropieza con artículos en Internet y les da más crédito de lo que debería. Tal vez este sea uno de esos casos.

 8
Author: James McMahon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 13:56:02

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

Por ejemplo, aunque algunos no estarán de acuerdo, me gusta la API Estándar de Java. También me gusta el Marco de Primavera. Mirando las clases en estas bibliotecas, notará que muy rara vez hay setters y getters que están allí solo para exponer alguna variable interna. Hay métodos llamados getX, pero eso no significa que sea un getter en el sentido convencional.

Por lo tanto, creo que tiene un punto, y es este: cada vez que presione elegir "Generar getters/setters" en Eclipse (o su IDE de elección), debe dar un paso atrás y preguntarse qué está haciendo. ¿Es realmente apropiado exponer esta representación interna, o arruiné mi diseño en algún momento?

 5
Author: waxwing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-04 20:57:07

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

Si se usa get/set, limita la ocultación de información de OO, lo que potencialmente puede bloquearlo en una interfaz defectuosa.

En el ejemplo anterior, Name es una cadena; ¿qué pasa si queremos cambiar el diseño más tarde para agregar varios nombres? La interfaz expuso solo una sola cadena por lo que no se puede 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 Add(string name), internamente podría procesar name singularmente o add to a list o what not y externamente llamar al método Add 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.

Lo más probable es que si acabas de envolver un tipo primitivo con un get / set has roto este principio.

Por supuesto, esto es si crees en los objetivos de OO; me parece que la mayoría no, no realmente, solo usan Objetos como una forma conveniente de agrupar código funcional.

 2
Author: Rick64,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 14:13:54

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, realmente elemental (como una clase de punto). En general, si hay alguna variable en una clase que piensas 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 getters y setters tienen sentido cuando reflejan algún tipo de coherencia idea. En una clase de polígono, por ejemplo, las coordenadas x e y de vértices dados tienen un significado fuera del límite de la clase. Probablemente tiene sentido tener getters, y probablemente tiene 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 getter. Si tiene un setter, necesita tener el registro incorporado para preservar la auditabilidad.

Hay algunas ventajas de los getters y setters sobre las variables públicas. Proporcionan cierta separación entre interfaz e implementación. El hecho de que un punto tenga una función .getX() no significa que tenga que haber una x, ya que .getX() y .setX() pueden funcionar 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 activa en un conjunto, como el registro de la cuenta bancaria equilibrio.

Sin embargo, para clases más abstractas, las variables miembro pierden significado individual, y solo tienen sentido en contexto. No necesita conocer todas las variables internas de una clase de flujo de C++, por ejemplo. Usted necesita saber cómo conseguir elementos dentro y fuera, y cómo realizar varias otras acciones. Si contaras con la estructura interna exacta, estarías atascado en detalles que podrían variar arbitrariamente entre compiladores o versiones.

Entonces, yo diría que use privado variables casi exclusivamente, getters y setters donde tienen un significado real en el comportamiento del objeto, y no de otra manera.

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

 2
Author: David Thornley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 15:33:44

El problema con los getters/setters es que intentan falsificar la encapsulación, pero en realidad la rompen exponiendo sus componentes internos. En segundo lugar, están tratando de hacer dos cosas separadas - proporcionar acceso y controlar su estado - y terminan haciendo ninguna de las dos muy bien.

Rompe la encapsulación porque cuando llamas a un método get/set primero necesitas saber el nombre (o tener una buena idea) del campo que quieres cambiar, y segundo tienes que saber su tipo eg. no pudiste call

setPositionX("some string");

Si conoce el nombre y el tipo del 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, así que por qué no simplificarlo y convertirlo en 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 simplemente confunde las cosas y termina siendo inútil, o engañoso, al no hacer realmente lo que dice que lo hace al tener efectos secundarios que el usuario no podría esperar. Si se necesita comprobació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, necesitar getters/setters para hacer que algo funcione es a menudo un síntoma de un mal diseño. Haga uso del principio "diga, no pregunte", o vuelva a pensar por qué un objeto necesita enviar sus datos de estado en primer lugar. Exponer 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.

Mencionas MVC también y dices que un modelo no puede ser responsable de su vista, para ese caso Allen Holub da un ejemplo de hacer una capa de abstracción al tener una "give-me-a-JComponent-that-represents-your-identity class" que dice que "aislaría la forma en que se representan las identidades del resto del sistema."No tengo la experiencia suficiente para comente si eso funcionaría o no, pero en la superficie suena una idea decente.

 2
Author: nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-08 22:05:25

Los getters/setters públicos son malos si proporcionan acceso a los detalles de implementación. Sin embargo, es razonable proporcionar acceso a las propiedades del objeto y usar getters/setters para esto. Por ejemplo, si Car tiene la propiedad color, es aceptable dejar que los clientes la "observen" usando un captador. Si algún cliente necesita la capacidad de cambiar el color de un coche, la clase puede proporcionar un setter ('cambiar el color' es un nombre más claro). Es importante no dejar que los clientes sepan cómo se almacenan las propiedades en los objetos, cómo se mantienen, y así sucesivamente.

 1
Author: Corwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-04 20:22:56

Ummmm...nunca ha oído hablar del concepto de Encapsulación. Los métodos Getter y Setter se implementan para controlar el acceso a los miembros de una Clase. Haciendo que todos los campos sean visibles públicamente...cualquiera podría escribir cualquier valor que quisiera para ellos invalidando completamente el objeto entero.

En caso de que alguien esté un poco confuso sobre el concepto de Encapsulación, lea sobre él aquí:

Encapsulación (Informática)

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

EDITAR

El artículo menciona la encapsulación:

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

El uso de este método llevará a que sea extremadamente difícil mantener el código en a largo plazo. Si descubres a mitad de un proyecto que abarca años que un campo necesita ser Encapsulado, vas a tener que actualizar CADA REFERENCIA de ese campo en todas partes de tu software para obtener el beneficio. Suena mucho más inteligente usar la encapsulación adecuada por adelantado y protegerse el dolor de cabeza más tarde.

 0
Author: Justin Niessner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-15 13:55:51

Creo que los getters y setters solo deben usarse para variables a las que uno necesita acceder o cambiar fuera de una clase. Dicho esto, no creo que las variables deban ser públicas a menos que sean estáticas. Esto se debe a que hacer públicas las variables que no son estáticas puede llevar a que se cambien de forma indeseable. Digamos que tienes un desarrollador que está usando variables públicas descuidadamente. Luego accede a una variable de otra clase y sin querer, la cambia. Ahora tiene un error en su software como resultado de este percance. Es por eso que creo en el uso adecuado de getters y setters, pero no los necesitas para cada variable privada o protegida.

 0
Author: mnuzzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-19 06:05:24