Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Actualmente estoy trabajando en un juego simple en Java con varios modos diferentes. Me he extendido una clase principal del juego para poner la lógica principal dentro de las otras clases. A pesar de esto, la clase principal del juego sigue siendo bastante fuerte.

Después de tomar un rápido vistazo a mi código de la mayoría de que era captadores y definidores (60%) en comparación con el resto que es verdaderamente necesario para la lógica del juego.

Un par de búsquedas de Google han afirmado que los captadores y definidores son malos, mientras que otros han afirmado que son necesarias para la buena práctica OO y grandes programas.

Entonces, ¿qué debería hacer? ¿Qué debería ser? ¿Debo estar cambiando mis captadores y definidores de mis variables privadas, o debería seguir con ellos?

¿Fue útil?

Solución

También existe el punto de vista de que la mayoría de las veces, el uso de fijadores todavía rompe la encapsulación que le permite establecer valores que no tienen sentido. Como un ejemplo muy obvio, si usted tiene un contador de puntuación en el juego que solamente siempre sube, en lugar de

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

debería ser

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

Este es quizás un poco de un ejemplo fácil. Lo que estoy tratando de decir es que la discusión getter / setters vs campos públicos a menudo oculta problemas más grandes con objetos de manipulación de estado internos de los demás de una manera íntima y por lo tanto está demasiado estrechamente acoplados.

La idea es hacer que los métodos que hacen directamente cosas que quiere hacer. Un ejemplo sería cómo establecer el estado 'vivo' enemigos. Usted podría estar tentado a tener un método (booleano vivos) setAlive. En su lugar debe tener:

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

La razón de esto es que si cambia la aplicación que las cosas ya no tienen un booleano "vivo", sino más bien un valor "puntos de golpe", puede cambiar eso por ahí sin romper el contrato de los dos métodos que ha escrito anteriormente:

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }

Otros consejos

  • Muy mal. Campos públicos
  • Un poco mal. Getters y setters donde no son necesarios
  • Buena: captadores y definidores sólo cuando realmente están obligados - a hacer el tipo de exponer el comportamiento "más grande" que pasa a usar su estado, en lugar de tratar sólo el tipo como un repositorio de estado para ser manipulado por otros tipos.

En realidad depende de la situación, aunque - a veces realmente lo sólo quieren un objeto de datos tonto

.

Usted ya ha tenido un montón de buenas respuestas en esto, así que voy a dar a mis dos centavos. Captadores y definidores son muy, muy mal. En esencia, permiten pretender ocultar partes internas de su objeto, cuando la mayoría de las veces todo lo que has hecho se lanza en el código redundante que no hace nada para ocultar el estado interno. Para un simple POJO, no hay razón por la getName () y setName () no pueden ser sustituidos por obj.name = "Tom".

Si la llamada al método limita a sustituir la asignación, entonces todo lo que has ganado al preferir la llamada al método es el código hinchazón. Por desgracia, el idioma ha consagrado el uso de captadores y definidores en la especificación JavaBeans, por lo que los programadores de Java están obligados a usarlos, incluso cuando ello no tiene ningún sentido.

Afortunadamente, Eclipse (y probablemente otros entornos de desarrollo, así) le permite generar automáticamente. Y para un proyecto divertido, una vez construido un generador de código para ellos en XSLT. Pero si hay una cosa que me deshago de en Java, es la excesiva dependencia de captadores y definidores.

Los captadores y definidores cumplir el concepto de encapsulación en la programación orientada a objetos.

Al tener los estados de los objetos ocultos del mundo exterior, el objeto es realmente responsable de sí mismo, y no puede ser alterado de manera que no estén destinados. Las únicas formas en que el objeto se puede manipular son a través de métodos públicos expuestos, tales como captadores y definidores.

Hay algunas ventajas por tener captadores y definidores:

1. Permitiendo cambios futuros sin necesidad de modificar el código que utiliza la clase modificada.

Una de las grandes ventajas de utilizar un getter y setter es que una vez que los métodos públicos se definen y llega un momento en que la implementación subyacente necesita ser cambiado (por ejemplo, la búsqueda de un error que debe ser corregido, usando un algoritmo diferente para mejorar el rendimiento, etc.), haciendo que los captadores y definidores ser la única manera de manipular el objeto, permitirá que el código para no romper, y el trabajo existente como se esperaba, incluso después del cambio.

Por ejemplo, digamos que hay un método setValue que establece la variable privada value en un objeto:

public void setValue(int value)
{
    this.value = value;
}

Pero entonces, había un nuevo requisito que necesita para realizar un seguimiento del número de veces que value fue cambiado. Con el colocador en su lugar, el cambio es bastante trivial:

public void setValue(int value)
{
    this.value = value;
    count++;
}

Si el campo value eran públicos, no existe una manera fácil de volver más tarde y añadir un contador que lleva la cuenta del número de veces que se ha cambiado el valor. Por lo tanto, tienen captadores y definidores son una forma de "a prueba de futuro" la clase de cambios que puede venir más adelante.

2. La aplicación de los medios por los que el objeto puede ser manipulado.

Otra forma de captadores y definidores son útiles es hacer cumplir las maneras en que el objeto puede ser manipulado, por lo tanto, el objeto está en control de su propio estado. Con las variables públicas de un objeto a la vista, que puede ser fácilmente dañado.

Por ejemplo, un objeto ImmutableArray contiene una matriz int llamado myArray. Si la matriz eran un campo público, simplemente no será inmutable:

ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10;      // Oops, the ImmutableArray a's contents have been changed.

Para implementar una matriz de verdad inmutable, un captador para la matriz (método getArray) debe ser escrito de modo que devuelve una copia de su matriz:

public int[] getArray()
{
    return myArray.clone();
}

E incluso si ocurre lo siguiente:

ImmutableArray a = new ImmutableArray();
int[] b = a.getArray();
b[0] = 10;      // No problem, only the copy of the array is affected.

El ImmutableArray es de hecho inmutable. La exposición de las variables de un objeto le permitirá ser manipulada de manera que no se pretende, pero sólo exponer ciertas maneras (captadores y definidores), el objeto puede ser manipulado en formas destinadas.

supongo que tienen captadores y definidores serían más importantes para las clases que forman parte de una API que va a ser utilizado por otros, ya que permite mantener la API intacto y sin cambios mientras que permite cambios en la implementación subyacente.

Con todas las ventajas de captadores y definidores dijo, si el comprador no es más que devuelve el valor de la variable privada y la incubadora no es más que aceptar un valor y asignarlo a una variable privada, parece que los getters y setter son sólo extraños y realmente un desperdicio. Si la clase va a ser sólo para uso interno de una aplicación que no va a ser utilizado por otros, el uso de captadores y definidores extensivamente puede no ser tan importante como cuando se escribe una API pública.

Ellos son absolutamente mal.

@coobird por desgracia absolutamente no "hacer cumplir el concepto de encapsulación", lo único que hacen es hacer que usted piensa que está encapsulando los datos cuando en realidad se está exponiendo datos a través de una propiedad con delirios de grandeza método. Cualquier cosa que un captador / definidor hace un campo público hace mejor.

En primer lugar, si desea que los datos públicos, hacen que sea pública, deshacerse de los métodos getter y setter para reducir el número de métodos que el cliente tiene que vadear y que sea cognitivamente más sencillo para el cliente para cambiar su valor por ej.

object.field = value;

en lugar de la más intensa cognitivamente

object.setField(value);

donde el cliente ahora debe comprobar el método getter / setter para ver si tiene algún efecto secundario.

En segundo lugar, si usted realmente necesita hacer algo más en el método, ¿por qué lo llaman un método get / set cuando se tiene más responsabilidades que simplemente conseguir o el ajuste? O bien seguir la SRP o llamar al método algo que realmente le dice lo que el toda método tiene como ejemplos de Zarkonnen que mencionó por ejemplo.

public void kill(){
    isAlive = false;
    removeFromWorld(this);
}

en lugar de

public void setAlive(boolean isAlive){
    this.isAlive = isAlive;
    if (isAlive)
        addToWorld(this);
    else
        removeFromWorld(this);
}

¿de dónde viene el método setAlive (booleano) decirle al cliente que como un efecto secundario que va a eliminar el objeto del mundo? ¿Por qué debe el cliente tiene ningún conocimiento sobre el campo isAlive? Además de lo que sucede cuando se vuelve a agregar el objeto al mundo, que debe ser re-inicializado? ¿por qué el cuidado del cliente en nada de eso?

En mi humilde opinión la moral es a métodos de nombres para decir exactamente lo que hacen, seguir la SRP y deshacerse de getters / setters. Si hay problemas sin getters / setters, contar objetos para hacer su propio trabajo sucio dentro de su propia clase en lugar de tratar de hacer cosas con ellos en otras clases.

Aquí termina mi perorata, lo siento por eso;)

Es una pendiente resbaladiza.

Un objeto simple de transferencia (o un objeto Parameter) pueden tener el único propósito de la celebración de algunos campos y proporcionar sus valores bajo demanda. Sin embargo, incluso en ese caso degenerado se podría argumentar que el objeto debe ser inmutable -. Configurado en el constructor y exponiendo solamente get ... métodos

También está el caso de una clase que expone algunos "botones de control"; La interfaz de usuario de la radio del coche, probablemente, se puede entender como la exposición de algo así como getVolume, setVolume, getChannel y setChannel, pero su funcionalidad real está recibiendo señales y emitir sonido. Pero esos mandos no exponen mucho detalle de implementación; usted no sabe de esas características de la interfaz si la radio de transistores, sobre todo en software, o tubos de vacío.

Cuanto más se empieza a pensar en un objeto como un participante activo en una tarea de problemas de dominio, más se va a pensar en términos de pedir a hacer algo en lugar de pedirle que dicen usted acerca de su estado interno, o pidiendo que por sus datos a fin de otro código puede hacer algo con esos valores.

Así que ... "mal"? Realmente no. Pero cada vez que estás inclinado a poner en un valor y exponer tanto get ... y ... set métodos en ese valor, preguntarse por qué, y qué reponsibility ese objeto es en realidad. Si la única respuesta que puede darse es: "Para mantener este valor para mí", entonces tal vez OO algo más que está pasando aquí.

Su clase de juegos es probablemente siguiendo el objeto antipatrón si se expone a que muchas variables. No hay nada malo con captadores y definidores (aunque su nivel de detalle en Java puede ser un poco molesto); en una aplicación bien diseñada, donde cada clase tiene una funcionalidad claramente separados, no necesitará decenas de ellos en una sola clase.

Editar Si el punto principal de los captadores y definidores es "configurar" la classe juego (entiendo tu comentario de esa manera), entonces su probablemente no necesita los captadores (que es perfectamente bien para una clase para acceder a sus propias variables privadas sin necesidad de utilizar métodos get), y es probable que pueda colapsar muchos de los emisores en "set" de grupos que establecen diversas variables que pertenecen juntos conceptualmente.

La presencia de getter y setters tiende a indicar (un "olor" si usted está en ese tipo de lenguaje de la escuela primaria) que hay un problema de diseño. captadores y definidores triviales apenas se distinguen de los campos públicos. Normalmente, el código que opera sobre los datos estará en una clase diferente -. Encapsulación pobres, y lo que se puede esperar de los programadores no a gusto con OO

En algunos casos captadores y definidores están bien. Pero por regla general un tipo con dos captadores y definidores indica problemas de diseño. Compuestos absorbentes funcionan para inmutabilidad; set trabajan para "decir no preguntar". Tanto la inmutabilidad y "dicen que no piden" son buenas opciones de diseño, siempre y cuando no se apliquen de un estilo de superposición.

Mi opinión es que los captadores y definidores son un requisito para los buenos programas. Seguir con ellos, pero no escribir innecesarios getters / setters -. Que no siempre es necesario tratar directamente con todas las variables

Realmente no creo que están mal. Pero me gustaría vivir en un mundo donde nunca tuve que use a menos que realmente necesitaba.

Un ejemplo leí de arriba se future-proofing su código. Por ejemplo:

public void setValue(int value)
{
    this.value = value;
}

A continuación, los requisitos cambian y es necesario realizar un seguimiento de las veces que se estableció el valor.

Así que:

public void setValue(int value)
{
    this.value = value;
    count++;
}

Esto es hermoso. Lo entiendo. Sin embargo, en Ruby, que los siguientes no tienen el mismo propósito?

someobject.my_value = 100

Más tarde, es necesario realizar un seguimiento se estableció el número de veces my_value. Pues bien, es posible que no acaba de anular el colocador ENTONCES y sólo ENTONCES

def my_value=(value)
    @my_value = value
    @count++
end

Estoy a favor de código hermosa pero tengo que admitir, mirando a través de las montañas de clases Java que tenemos y ver literalmente miles y miles de líneas de código que no son más que getter / setters básicos es feo y molesto.

Cuando yo estaba desarrollando en C # tiempo completo, utilizamos las propiedades públicas todo el tiempo y lo hicimos getters / setters personalizados sólo cuando sea necesario. Trabajó como un encanto y no ha roto nada.

Como siempre, la única respuesta es: depende. Si usted es una persona los únicos que tocan el código, puede hacer cualquier cosa que se sienta cómodo, incluyendo tomar atajos.

Uno de los beneficios del uso de los emisores es que los controles deben realizarse en una sola ubicación en el código.

Es posible que desee prestar atención más cerca de lo que realmente está siendo obtener y establecer por estos métodos. Si estás usando ellos para proporcionar acceso a valores constantes que es probablemente mejor mediante el uso de constantes.

Esto depende del lenguaje de programación en cuestión. Su pregunta se enmarca en el contexto de Java, donde parece que los captadores y definidores son generalmente considerados como una buena cosa.

Por el contrario, en el mundo de Python, que son considerados generalmente como mal estilo: añaden líneas al código sin tener que añadir funcionalidad. Cuando los programadores de Python necesitan, ellos pueden usar para atrapar metaprogramming conseguir y / o el ajuste de atributos de los objetos.

En Java (al menos la versión de Java que aprendieron un poco hace una década), que no era posible. Por lo tanto, en Java por lo general es mejor utilizar captadores y definidores religiosamente, por lo que si es necesario, se puede anular el acceso a las variables.

(Esto no hace necesariamente mejor que Python Java, simplemente diferente.)

Para su información: Además de todas las excelentes respuestas en este tema, recuerda que de todas las razones que puede llegar a favor o en contra getters / setters, el rendimiento no es uno (como algunos pueden creer). La JVM es lo suficientemente inteligente como para inline getters / setters triviales (incluso no final, siempre y cuando de hecho no están anulados).

Es posible que desee para reemplazar algunas de las clases de clases de valores. Esto le permitirá quitar el captador y evitar problemas cuando el contenido se cambia de debajo de ti.

Si necesita acceso externo a los valores individuales de los campos de captadores, uso y / o emisores. Si no es así, no lo hacen. Nunca utilice campos públicos. ¡Es tan simple como eso! (Ok, nunca es que simple, pero es una buena regla del pulgar).

En general también se debe encontrar que usted necesita para suministrar un regulador mucho menos a menudo que un captador - especialmente si usted está tratando de hacer que sus objetos inmutables - que es una buena cosa (pero no siempre es la mejor opción) - pero incluso en caso contrario.

He sido la programación en java para hace unos meses, y he aprendido que debemos usar getters y setters sólo cuando es necesario para la aplicación

divertirse:)

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