Pregunta

¿Cuál es la ventaja de usar getters y setters - que sólo get y set - en lugar de simplemente utilizar campos públicos para esas variables?

Si getters y setters alguna vez hacer algo más que la simple get/set, puedo encontrar esta muy rápidamente, pero no estoy 100% clara sobre cómo:

public String foo;

es peor que:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Mientras que la primera toma mucho menos código repetitivo.

¿Fue útil?

Solución

En realidad, hay muchas buenas razones a considerar el uso de métodos de acceso en lugar de exponer directamente a los campos de una clase - más allá de la discusión de encapsulación y hacer cambios en el futuro más fácil.

Aquí están algunas de las razones por las que soy consciente de:

  • La encapsulación de comportamiento asociado a obtener o establecer la propiedad - esto permite una funcionalidad adicional (como la validación) a añadir más fácilmente más tarde
  • .
  • Cómo ocultar la representación interna de la propiedad, mientras que la exposición de un establecimiento a través de una representación alternativa.
  • El aislamiento de su interfaz pública del cambio -. Permitiendo que la interfaz pública permanezca constante, mientras que los cambios en la implementación sin afectar a los consumidores existentes
  • El control de la administración de la duración y la memoria (disposición) semántica de la propiedad -. Particularmente importante en entornos no gestionados de memoria (como C ++ o Objective-C)
  • Proporcionar un punto de intercepción para la depuración cuando una propiedad cambia en tiempo de ejecución -. Depurar cuando y donde una propiedad cambia a un valor particular, puede ser bastante difícil sin esto en algunos idiomas
  • interoperabilidad mejorada con bibliotecas que están diseñados para operar en contra de propiedades getter / setters -. El imitar, serialización, y WPF vienen a la mente
  • herederos que permite cambiar la semántica de cómo se comporta la propiedad y está expuesto sobreescribiendo los métodos de captador / definidor.
  • Permitir que el captador / definidor a pasar alrededor como expresiones lambda en lugar de valores.
  • Los captadores y definidores se permiten diferentes niveles de acceso - por ejemplo, el get puede ser pública, pero el conjunto podrían ser protegidos
  • .

Otros consejos

Debido a 2 semanas (meses, años) a partir de ahora cuando se da cuenta de que su colocador tiene que hacer más que acaba de establecer el valor, también se dará cuenta de que la propiedad ha sido utilizada directamente en 238 otras clases: -)

Un campo público no es peor que un par de captador / definidor que no hace nada, excepto regresar al campo y asignar a la misma. En primer lugar, está claro que (en la mayoría de los idiomas) no hay diferencia funcional. Cualquier diferencia debe estar en otros factores, como el mantenimiento o la lectura.

Una tan mencionada ventaja de pares de captador / definidor, no lo es. Hay esta afirmación de que se puede cambiar la implementación y sus clientes no tienen que volver a compilar. Supuestamente, los emisores permiten añadir funcionalidades como la validación más adelante y sus clientes ni siquiera necesitan saber acerca de ella. Sin embargo, la adición de validación a un colocador es un cambio en sus condiciones previas, una violación del contrato anterior , que era, simplemente, "se puede poner nada aquí, y usted puede conseguir que el mismo más adelante del captador".

Así que, ahora que se rompió el contrato, el cambio de todos los archivos en el código base es algo que debe querer hacerlo, no evitar. Si evita que estás haciendo la suposición de que todo el código asume el contrato para esos métodos era diferente.

Si eso no debería haber sido el contrato, entonces la interfaz estaba permitiendo a los clientes a poner el objeto en estados no válidos. Eso es exactamente lo contrario de encapsulación Si ese campo no podía ser ajustado en cualquier cosa, desde el principio, ¿por qué no la validación ahí desde el principio?

Este mismo argumento se aplica a otros supuestos ventajas de estos pares de paso a través de captador / definidor: si más adelante decide cambiar está estableciendo el valor, que está rompiendo el contrato. Si anula la funcionalidad por defecto en una clase derivada, de una manera más allá de unas pocas modificaciones inofensivas (como el registro o cualquier otro comportamiento no observable), que está rompiendo el contrato de la clase base. Esa es una violación de la Liskov Sustituibilidad Principio, que es visto como uno de los principios de OO.

Si una clase tiene estos captadores y definidores mudos para cada campo, entonces es una clase que no tiene invariantes en absoluto, sin contrato . Es que el diseño realmente orientado a objetos? Si toda la clase tiene es los captadores y definidores, es sólo un soporte de datos mudo, y los titulares de datos mudos deben parecerse a los titulares de datos mudos:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Adición de pares de captador / definidor de paso a través de una clase tal no añade valor. Otras clases deben proporcionar operaciones significativas, no sólo las operaciones que ya proporcionan campos. Así es como se puede definir y mantener los invariantes útiles.

  

Cliente : "¿Qué puedo hacer con un objeto de esta clase"
   diseñador "Puede leer y escribir varias variables"
   Cliente : "Oh ... fresco, supongo"

Hay razones para utilizar captadores y definidores, pero si no existen esas razones, haciendo pares de captador / definidor en nombre de dioses falsos de encapsulación no es una buena cosa. Las razones válidas para hacer getters o setters incluyen las cosas a menudo mencionados como los posibles cambios que puede realizar más adelante, como la validación o diferentes representaciones internas. O tal vez el valor debe ser legible por los clientes, pero no se puede escribir (por ejemplo, la lectura del tamaño de un diccionario), por lo que un comprador simple es una buena opción. Pero esas razones deberían estar allí cuando a tomar la decisión, y no sólo como una cosa potencial es posible que desee más tarde. Este es un ejemplo de YAGNI ( No va a necesitar Es ).

Mucha gente habla sobre las ventajas de los captadores y definidores, pero quiero hacer de abogado del diablo. En este momento estoy depuración de un programa muy grande, donde los programadores decidieron hacer todo lo captadores y definidores. Esto puede parecer agradable, pero es una pesadilla de ingeniería inversa.

Digamos que usted está mirando a través de cientos de líneas de código y se encuentra con esto:

person.name = "Joe";

Es una muy simple trozo de código hasta que se da cuenta de que es un colocador. Ahora, que sigue la moda y encontrar que también establece person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName, y llama person.update (), que envía una consulta a la base de datos, etc. Ah, eso es donde se estaba produciendo su pérdida de memoria.

La comprensión de una pieza local del código a primera vista es una propiedad importante de una buena legibilidad de que los captadores y definidores tienden a romperse. Por eso trato de evitarlos cuando puedo, y minimizar lo que hacen cuando los uso.

Hay muchas razones. Mi favorito es cuando se necesita para cambiar el comportamiento o regular lo que se puede establecer en una variable. Por ejemplo, digamos que usted tenía un método SETSPEED (velocidad int). Pero desea que sólo se puede establecer una velocidad máxima de 100. Se podría hacer algo como:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Ahora lo que si todas partes en su código que estaba utilizando el campo público y luego se dio cuenta de que necesita el requisito anterior? Divertirse cazando a cada uso del campo público en lugar de simplemente modificando su colocador.

Mis 2 centavos:)

En un puro captadores y definidores mundo orientado a objetos es un terribles contra el patrón . Lee este artículo: getters / setters. Mal. período. En pocas palabras, animan a los programadores a pensar en los objetos como de estructuras de datos, y este tipo de pensamiento es pura procedimental (como en COBOL o C). En un lenguaje orientado a objetos no existen estructuras de datos, pero sólo los objetos que exponen el comportamiento (no atributos / propiedades!)

Puede encontrar más información sobre ellos en la Sección 3.5 de elegantes objetos (mi libro acerca de la programación orientada a objetos).

Una de las ventajas de los métodos de acceso y mutadores es que se puede realizar la validación.

Por ejemplo, si foo era pública, que podría fácilmente la pusieron a null y luego otra persona podría intentar llamar a un método en el objeto. Pero no hay más! Con un método setFoo, podría asegurar que foo nunca se ha configurado a null.

Los descriptores de acceso y mutadores también permiten la encapsulación - si no se supone que ver el valor una vez que su conjunto (tal vez que está establecido en el constructor y luego utilizados por los métodos, pero nunca supone que debe ser cambiado), que nunca se ha visto Por cualquiera. Pero si se puede permitir que otras clases para ver o cambiarlo, puede proporcionar el descriptor de acceso y / o mutador adecuada.

depende de su idioma. Ha etiquetado este "orientado a objetos" en lugar de "Java", así que me gustaría señalar que la respuesta de ChssPly76 depende del idioma. En Python, por ejemplo, no hay ninguna razón para utilizar captadores y definidores. Si necesita cambiar el comportamiento, puede utilizar una propiedad, la cual se ajusta un getter y setter en torno al acceso básico atributo. Algo como esto:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

Bueno, yo sólo quiero añadir que, aunque a veces son necesarias para la encapsulación y la seguridad de sus variables / objetos, si queremos codificar un objeto real programa orientado, entonces tenemos que STOP uso excesivo de los descriptores de acceso , porque a veces dependemos mucho en ellos cuando no es realmente necesario y que hace casi lo mismo que si ponemos las variables público.

Gracias, que realmente aclaró mi pensamiento. Ahora aquí es (casi) 10 (casi) buenas razones para no usar captadores y definidores:

  1. Cuando se da cuenta de que tiene que hacer algo más que establecer y obtener el valor, sólo puede hacer que el campo privado, que le dirá al instante en el que ha accedido directamente a la misma.
  2. Cualquier validación se realiza allí sólo puede ser independiente del contexto, que la validación es rara vez en la práctica.
  3. Puede cambiar el valor que se está establecido -. Esto es una pesadilla absoluta cuando la persona que llama se pasa un valor que [el horror de choque] quieren que le permite almacenar COMO ESTÁ
  4. Puede ocultar la representación interna - fantástico, por lo que está asegurándose de que todas estas operaciones son simétricas derecha
  5. Usted ha aislamiento de su interfaz pública de cambios bajo las sábanas - si estuviera diseñando una interfaz y no estaban seguros si el acceso directo a algo que estaba bien, el diseño, entonces debería haber mantenido
  6. .
  7. Algunas bibliotecas esperan esto, pero no muchos - la reflexión, la serialización, objetos simulados todos trabajan muy bien con campos públicos
  8. .
  9. La herencia de esta clase, se puede anular la funcionalidad por defecto -. En otras palabras, puede confundir a las personas que llaman por REALMENTE no sólo ocultar la aplicación, pero lo que es incompatible

Los tres últimos sólo estoy dejando (N / D o D / C) ...

Sé que es un poco tarde, pero creo que hay algunas personas que están interesadas en su rendimiento.

He hecho un poco de prueba de rendimiento. Escribí una clase "NumberHolder", que, además, posee un número entero. Se pueden leer de ese entero utilizando el método getter anInstance.getNumber() o accediendo directamente el número utilizando anInstance.number. Mi Programm lee el número 1.000.000.000 de veces, a través de las dos maneras. Ese proceso se repite cinco veces y se imprime el tiempo. Tengo el siguiente resultado:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(Tiempo 1 es la forma directa, Time 2 es el getter)

Usted ve, el captador es (casi) siempre un poco más rápido. Luego probé con diferentes números de ciclos. En lugar de 1 millón, utilicé 10 millones y 0,1 millones. Los resultados:

10 millones de ciclos:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

Con 10 millones de ciclos, los tiempos son casi los mismos. Aquí son 100 mil (0,1 millones) ciclos:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

También con diferentes cantidades de ciclos, el captador es un poco más rápido que la forma habitual. Espero que esto le ayudó.

No utilice métodos get set menos que sean necesarios para su suministro de corriente es decir, No piense demasiado acerca de lo que sucedería en el futuro, si alguna cosa para cambiar su una solicitud de cambio en la mayoría de las aplicaciones, los sistemas de producción.

Piense simple, fácil, añadir complejidad cuando sea necesario.

No me aprovecharse de la ignorancia de los propietarios de negocios de un profundo conocimiento de cómo sólo porque creo que es correcta o me gusta el enfoque.

Tengo sistema masivo escrito sin captadores set únicamente con modificadores de acceso y algunos métodos para validar n realizar la lógica biz. Si es absolutamente necesario el. Utilizar cualquier cosa.

pasé bastante tiempo pensando sobre esto para el caso de Java, y creo que las verdaderas razones son:

  1. Código de la interfaz, no a la aplicación
  2. Interfaces sólo especifican métodos, no los campos

En otras palabras, la única forma en que puede especificar un campo en una interfaz es proporcionando un método para escribir un nuevo valor y un método para leer el valor actual.

Esos métodos son el famoso getter y setter ....

Utilizamos captadores y definidores:

  • para reutilización
  • debe realizarse la validación en etapas posteriores de la programación

Los métodos getter y setter son interfaces públicas de acceso a miembros de la clase privadas.


mantra encapsulación

El mantra encapsulación es hacer que los campos privados y métodos pública.

  

Métodos Getter:. Podemos obtener acceso a variables privadas

     

Métodos Setter:. podemos modificar los campos privados

A pesar de que los métodos getter y setter no añaden nuevas funcionalidades, podemos cambiar nuestra mente volver más tarde para hacer que el método

  • mejor;
  • más seguro; y
  • más rápido.

En cualquier lugar un valor puede ser utilizado, un método que devuelve dicho valor puede ser añadido. En lugar de:

int x = 1000 - 500

uso

int x = 1000 - class_name.getValue();

En términos sencillos

Representación de "Persona" clase

Supongamos que necesitamos para almacenar los detalles de este Person. Este Person tiene los campos name, age y sex. Hacer esto implica la creación de métodos para name, age y sex. Ahora bien, si tenemos que crear otra persona, se hace necesaria la creación de los métodos para name, age, sex todo de nuevo.

En lugar de hacer esto, podemos crear un class(Person) frijol con métodos get y set. Así que mañana se acaba de crear objetos de esta class(Person class) frijol cada vez que tenemos que añadir una nueva persona (ver la figura). Por lo tanto estamos reusando los campos y métodos de la clase de frijol, que es mucho mejor.

Puede ser útil para lazy-loading. Digamos que el objeto en cuestión se almacena en una base de datos, y no quiere ir a buscar a menos que lo necesite. Si el objeto es recuperado por un captador, entonces el objeto interno puede ser nulo hasta que alguien se lo pide, entonces usted puede ir a por él en la primera llamada al comprador.

Yo tenía una clase de página de base en un proyecto que fue entregado a mí que estaba cargando algunos datos de un par de diferentes llamadas de servicio web, pero los datos de esas llamadas de servicio web no siempre se utilizó en todas las páginas hijas. servicios web, por todos los beneficios, pionera en las nuevas definiciones de "lento", por lo que no quieren hacer una llamada de servicio web, si usted no tiene que hacerlo.

Me mudé de campos públicos de captadores, y ahora los captadores comprobar la memoria caché, y si no hay llama al servicio web. Así que con un poco de envoltura, se impidiera a una gran cantidad de llamadas de servicio web.

Así que el comprador me salva de tratar de averiguar, en cada página niño, lo que necesitaré. Si lo necesito, llamo al comprador, y va a encontrarlo para mí si no lo tiene.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

Uno de los aspectos que me perdí en las respuestas hasta el momento, la especificación de acceso:

  • para los miembros que tienen sólo una especificación de acceso tanto para establecer y obtener
  • para incubadoras y captadores se puede ajustar con precisión y definirlo por separado

En lenguajes que no soportan "Propiedades" (C ++, Java) o requerir recopilación de clientes al cambiar los campos a propiedades (C #), utilizando métodos set GET / es más fácil de modificar. Por ejemplo, añadiendo la lógica de validación a un método setFoo no requerirá el cambio de la interfaz pública de una clase.

En los lenguajes que soportan propiedades "reales" (Python, Ruby, tal vez Smalltalk?) No hay punto de conseguir / métodos set.

EDITAR:He contestado a esta pregunta porque hay un montón de gente de aprendizaje de programación preguntando esto, y la mayoría de las respuestas son técnicamente muy competente, pero no es tan fácil de entender si eres un novato.Todos fuimos novatos, así que pensé en probar mi mano en el más novato amable respuesta.

Los dos principales son el polimorfismo y la validación.Incluso si es sólo un estúpido estructura de datos.

Supongamos que tenemos esta clase simple:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Una clase muy simple que contiene la cantidad de líquido que hay en él, y lo que su capacidad es de (en mililitros).

¿Qué sucede cuando hago:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

Bien, usted no esperaría que trabajar, ¿verdad?Quiere que haya algún tipo de comprobación de validez.Y peor, ¿qué pasa si nunca se especifica la máxima capacidad?Oh, querido, tenemos un problema.

Pero hay otro problema también.¿Qué pasa si las botellas eran sólo un tipo de envase?Lo que si hemos tenido varios contenedores, todos con capacidades y cantidades de líquido lleno?Si tan sólo pudiéramos hacer una interfaz, podemos dejar que el resto de nuestro programa de aceptar que la interfaz, y botellas, bidones y todo tipo de cosas que sólo el trabajo de manera intercambiable a través.¿No sería mejor?Desde las interfaces de la demanda de métodos, esta también es una buena cosa.

Nos gustaría terminar con algo como:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

Genial!!!Y ahora acabamos de cambiar la Botella a esto:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Voy a dejar la definición de los BottleOverflowException como ejercicio para el lector.

Ahora observe cómo mucho más robusto que es esto.Podemos manejar cualquier tipo de contenedor en nuestro código mediante la aceptación de LiquidContainer en lugar de la Botella.Y cómo estas botellas lidiar con este tipo de cosas todo puede ser diferente.Usted puede tener las botellas que escribir su estado para el disco, cuando cambia, o botellas que guardar en bases de datos de SQL o GNU sabe qué más.

Y todos estos pueden tener diferentes maneras de manejar diversos whoopsies.El Biberón de cheques y si es desbordante lanza una RuntimeException.Pero que podría ser la cosa incorrecta a hacer.(Hay un debate muy útil que se tenía sobre el manejo de errores, pero me estoy guardando muy sencillo aquí a propósito.La gente en los comentarios es probable que señalan los defectos de este enfoque simplista.;) )

Y sí, parece que vamos a partir de una idea muy sencilla para conseguir mejores respuestas rápidamente.

Por favor, tenga en cuenta también que no se puede cambiar la capacidad de una botella.Ahora se establece en la piedra.Usted puede hacer esto con un int por la declaración final.Pero si esto era una lista, podría vacío, añadir cosas nuevas, y así sucesivamente.Usted no puede limitar el acceso a tocar las entrañas.

También hay una tercera cosa que no todo el mundo ha abordado:getters y setters uso de las llamadas de método.Eso significa que se parecen a los métodos normales en todas partes los demás.En lugar de tener extraña sintaxis específica para DTOs y esas cosas, que tienen la misma cosa en todas partes.

Uno de los principios básicos de diseño orientado a objetos: La encapsulación

Se le da muchos beneficios, uno de los cuales es que se puede cambiar la implementación del captador / definidor detrás de las escenas, pero cualquier consumidor de ese valor continuará trabajando siempre y cuando el tipo de datos sigue siendo la misma.

Debe utilizar captadores y definidores cuando:

  • Usted está tratando con algo que es conceptualmente un atributo, pero:
    • Su lengua no tiene propiedades (o algún mecanismo similar, al igual que las huellas variables de Tcl), o
    • característica de propiedades de su idioma no es suficiente para este caso de uso, o
    • de su idioma (o, a veces de su marco) convenciones idiomáticas animan getters o setters para este caso de uso.

Así que esto es muy rara vez una pregunta OO general; se trata de una cuestión específica del idioma, con diferentes respuestas para diferentes idiomas (y diferentes casos de uso).


Desde un punto de vista de la teoría OO, captadores y definidores son inútiles. La interfaz de su clase es lo que hace, no lo que su estado es. (Si no es así, usted ha escrito la clase equivocada.) En casos muy sencillos, en lo que hace a una clase es justo, por ejemplo, representar un punto en coordenadas rectangulares, * los atributos son parte de la interfaz; captadores y definidores acaba de nube que. Sin embargo, en casos muy simples, pero nada, ni los atributos ni los captadores y definidores son parte de la interfaz.

Dicho de otra manera: Si usted cree que los consumidores de la clase no debería ni siquiera sabe que tiene un atributo spam, y mucho menos ser capaz de cambiar de cualquier manera, a continuación, dándoles un método set_spam es la última cosa que quiere hacer.

* Incluso en el caso de que la clase sencilla, es posible que no necesariamente quiere permitir el establecimiento de los valores x y y. Si esto es realmente una clase, ¿no debería tener métodos como translate, rotate, etc.? Si es sólo una clase porque su idioma no tiene registros / estructuras / tuplas con nombre, entonces esto no es realmente una cuestión de OO ...


Pero nadie está haciendo cada vez diseño general OO. Están haciendo el diseño y puesta en práctica, en un idioma específico. Y en algunos idiomas, captadores y definidores están lejos de ser inútil.

Si su idioma no tiene propiedades, entonces la única manera de representar algo que es conceptualmente un atributo, pero en realidad es calculado, o validado, etc., es a través de captadores y definidores.

Aunque su lenguaje tiene propiedades, puede haber casos donde son insuficientes o inadecuados. Por ejemplo, si desea permitir subclases para controlar la semántica de un atributo, en idiomas que no tienen acceso dinámico, una subclase no puede sustituir una propiedad calculada para un atributo.

En cuanto al "¿y si quiero cambiar mi implementación más adelante?" cuestión (que se repite varias veces en una redacción diferente, tanto en la pregunta del PO y la respuesta aceptada): Si realmente es un cambio aplicación pura, y que comenzó con un atributo, se puede cambiar a una propiedad sin afectar la interfaz. A menos que, por supuesto, su idioma no soporta eso. Así que este es en realidad el mismo caso de nuevo.

Además, es importante seguir los modismos de la lengua (o marco) que está utilizando. Si se escribe hermosa estilo código de Ruby en C #, cualquier experimentado desarrollador de C # que no sea usted va a tener problemas para leerlo, y eso es malo. Algunas lenguas tienen culturas más fuertes alrededor de sus convenciones que otros.-y no puede ser una coincidencia que Java y Python, que están en los extremos opuestos del espectro de cómo se captadores idiomática, sucede que tiene dos de las culturas más fuertes.

Más allá de los lectores humanos, habrá bibliotecas y herramientas que esperan que usted siga las convenciones, y hacer su vida más difícil si no lo hace. El enganchar los widgets Interface Builder a cualquier cosa menos propiedades ObjC, o el uso de ciertas bibliotecas burlones Java sin captadores, es sólo hacer la vida más difícil. Si las herramientas son importantes para usted, no luchar contra ellos.

Desde el punto de vista de diseño orientación a objetos ambas alternativas pueden ser perjudiciales para el mantenimiento del código por el debilitamiento de la encapsulación de las clases. Para una discusión se puede mirar en este excelente artículo: http://typicalprogrammer.com/?p=23

Los métodos getter y setter son métodos de acceso, lo que significa que son por lo general una interfaz pública para cambiar miembros de la clase privados. Se utilizan los métodos get y set para definir una propiedad. Se accede a los métodos getter y setter como propiedades fuera de la clase, a pesar de que los define dentro de la clase como métodos. Esas propiedades fuera de la clase pueden tener un nombre diferente del nombre de la propiedad en la clase.

Hay algunas ventajas de utilizar métodos getter y setter, tales como la capacidad que le permita crear miembros con funcionalidad sofisticada que se puede acceder a propiedades similares. También le permiten crear de sólo lectura y sólo escritura propiedades.

A pesar de que los métodos getter y setter son útiles, hay que tener cuidado de no abusar de ellos porque, entre otras cuestiones, que pueden hacer el mantenimiento del código más difícil en ciertas situaciones. Además, proporcionan acceso a la implementación de la clase, al igual que miembros del público. POO práctica desalienta acceso directo a las propiedades dentro de una clase.

Cuando se escribe clases, que está siempre anima a hacer el mayor número posible de sus variables de instancia privada y añadir métodos getter y setter. Esto se debe a que hay varios momentos en los que es posible que no desea que los usuarios cambien ciertas variables dentro de sus clases. Por ejemplo, si usted tiene un método estático privada que realiza un seguimiento del número de instancias creadas para una clase específica, que no desea que un usuario modifique el contador utilizando el código. Sólo la sentencia constructora debe incrementar esa variable cada vez que se llama. En esta situación, es posible crear una variable de instancia privada y permitir que un método getter sólo para la variable de contador, lo que significa que los usuarios son capaces de recuperar el valor actual sólo mediante el uso del método de obtención, y no será capaz de establecer nuevos valores utilizando el método setter. La creación de un captador sin colocador es una forma sencilla de hacer ciertas variables en la clase de sólo lectura.

Código evoluciona . private es ideal para cuando que necesitan protección miembro de datos . Con el tiempo todas las clases deben ser una especie de "miniprograms" que tienen una interfaz bien definida que no se puede simplemente tornillo con la parte interna de .

Dicho esto, desarrollo de software no es acerca de la configuración por esa versión final de la clase como si estuviera presionando una estatua de hierro fundido en el primer intento. Mientras trabaja con él, el código es más parecido a la arcilla. Evoluciona a medida que desarrolla y aprende más sobre el dominio del problema que está resolviendo. Durante las clases de desarrollo pueden interactuar entre sí de lo que deberían (dependencia va a factorizar), se fusionan juntos, o partirse. Así que creo que el debate se reduce a las personas que no quieren escribir religiosamente

int getVar() const { return var ; }

Por lo que tiene:

doSomething( obj->getVar() ) ;

En lugar de

doSomething( obj->var ) ;

No sólo se getVar() visualmente ruidoso, que da la ilusión de que gettingVar() de alguna manera es un proceso más complejo de lo que realmente es. ¿Cómo usted (como el escritor de clase) consideran la santidad de var es particularmente confuso para un usuario de la clase si tiene un colocador de tránsito - entonces parece que usted está poniendo a estas puertas para "proteger" a algo que insiste es valiosa , (la santidad de var) pero aún incluso le conceda la protección de var no vale la pena tanto por la posibilidad de que cualquiera acaba de entrar y set var a cualquier valor que quiera, sin que ni siquiera mira a escondidas en lo que están haciendo.

Así programo de la siguiente manera (asumiendo un enfoque tipo "ágil" - es decir, cuando escribo código sin saber exactamente lo que va a hacer / no tienen tiempo o la experiencia para planificar un elaborado cascada juego de estilo de interfaz):

1) Comience con todos los miembros del público para los objetos básicos con los datos y el comportamiento. Por eso, en toda mi C ++ "ejemplo" código que se fije en mí usando struct en lugar de class todas partes.

2) Cuando el comportamiento interno de un objeto de un miembro de datos llega a ser bastante compleja, (por ejemplo, le gusta mantener un std::list interna en algún tipo de orden), funciones de tipo de acceso se escriben. Porque soy la programación por mí mismo, no siempre se establece la private miembro de inmediato, pero en algún lugar de la evolución de la clase el miembro será "ascendido" a cualquiera protected o private.

3) Las clases que se plasmen plenamente y tienen reglas estrictas acerca de sus elementos internos (es decir, que saben exactamente lo que están haciendo, y que no han de "fuck" (término técnico) con sus componentes internos ) se les da la designación class, por defecto los miembros privados, y sólo unos pocos miembros se les permite ser public.

Me parece que este enfoque me permite evitar sentarse allí y religiosamente escribir getter / setters cuando una gran cantidad de miembros de datos consigue migrar a cabo, cambian de lugar, etc., durante las primeras etapas de la evolución de una clase.

Hay una buena razón para considerar el uso de métodos de acceso es que no hay herencia de propiedades. Véase el siguiente ejemplo:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Salida:

0
0
4

Getters y set se utilizan para poner en práctica dos de los aspectos fundamentales de la programación orientada a objetos que son:

  1. abstracción
  2. Encapsulación

Supongamos que tenemos una clase de empleados:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

A continuación, los detalles de implementación de nombre completo es ocultas para el usuario y no se puede acceder directamente al usuario, a diferencia de un atributo público.

Uno otro uso (en idiomas que apoyan propiedades) es que las incubadoras y getters pueden implican que una operación es no trivial. Por lo general, se quiere evitar hacer cualquier cosa que sea computacionalmente caro en una propiedad.

Una de las ventajas relativamente moderno de getters / setters es que se hace más fácil navegar por el código en la etiqueta (indexado) editores de código. P.ej. Si desea ver quién establece un miembro, puede abrir la jerarquía de llamada del colocador.

Por otro lado, si el miembro es pública, las herramientas no permiten que se filtre el acceso de lectura / escritura en el miembro. Así que hay que caminar penosamente a pesar de todos los usos del miembro.

En un lenguaje orientado a objetos los métodos, y sus modificadores de acceso, declaran la interfaz para ese objeto. Entre el constructor y el descriptor de acceso y métodos de mutador es posible para el desarrollador para controlar el acceso al estado interno de un objeto. Si las variables son simplemente declararon pública, entonces no hay manera de regular dicho acceso. Y cuando estamos usando los emisores podemos restringir al usuario para la entrada que necesitamos. La media de la alimentación para que muy variables vendrá a través de un canal adecuado y el canal está predefinido por nosotros. Por lo que es más seguro de usar emisores.

Además, esto es "a prueba de futuro" de su clase. En particular, al pasar de un campo a una propiedad es una ruptura ABI, por lo que si más adelante decide que necesita más lógica que sólo "Establecer / obtener el campo", entonces usted necesita para romper ABI, que por supuesto crea problemas para nada los demás ya compilado en contra de su clase.

Me gustaría lanzar la idea de anotación: @getter y @setter. Con @getter, usted debe ser capaz de obj = class.field pero no class.field = obj. Con @setter, viceversa. Con @getter y @setter usted debería ser capaz de hacer ambas cosas. Esto preservaría la encapsulación y reducir el tiempo al no llamar a los métodos triviales en tiempo de ejecución.

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