Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Por favor, perdona la longitud, pero aquí hay dos programas, ambos exactamente el mismo, pero una con y otra sin Reguladores, captadores y constructores.

Me he tomado una clase básica de C ++ antes y no recuerdo ninguno de ellos de él, y por el momento no estoy viendo el punto de ellos, si alguien puede explicar en términos de Lamen Yo más aprecian ... que en el momento en que parece ser nada más que factores de pérdida de espacio para hacer mi código se vea más largo, pero el maestro dice que son importantes (y hasta ahora eso es todo).

Gracias de antemano! Y ahora aquí está el código: Mileage.java:

package gasMileage;

import java.util.Scanner; //program uses class Scanner

public class Mileage 
{
    public int restart;
    public double miles, gallons, totalMiles, totalGallons, milesPerGallon;
    public Mileage(int newRestart, double newMiles, double newGallons, 
                   double newTotalMiles, double newTotalGallons, double newMilesPerGallon)
    {
        setRestart(newRestart);
        setMiles(newMiles);
        setGallons(newGallons);
        setTotalMiles(newTotalMiles);
        setTotalGallons(newTotalGallons);
        setMilesPerGallon(newMilesPerGallon);
    }
    public void setRestart(int newRestart)
    {
        restart = newRestart;
    }
    public int getRestart()
    {
        return restart;
    }
    public void setMiles(double newMiles)
    {
        miles = newMiles;
    }
    public double getMiles()
    {
        return miles;
    }
    public void setGallons(double newGallons)
    {
        gallons = newGallons;
    }
    public double getGallons()
    {
        return gallons;
    }
    public void setTotalMiles(double newTotalMiles)
    {
        totalMiles = newTotalMiles;
    }
    public double getTotalMiles()
    {
        return totalMiles;
    }
    public void setTotalGallons(double newTotalGallons)
    {
        totalGallons = newTotalGallons;
    }
    public double getTotalGallons()
    {
        return totalGallons;
    }
    public void setMilesPerGallon(double newMilesPerGallon)
    {
        milesPerGallon = newMilesPerGallon;
    }
    public double getMilesPerGallon()
    {
        return milesPerGallon;
    }
    public void calculateMileage()
    {
        Scanner input = new Scanner(System.in);
        while(restart == 1)
        {
            System.out.print("Please input number of miles you drove: ");
            miles = input.nextDouble();
            totalMiles = totalMiles + miles;
            System.out.print("Please input number of gallons you used: ");
            gallons = input.nextDouble();
            totalGallons = totalGallons + gallons;
            milesPerGallon = miles / gallons;
            System.out.printf("Your mileage is %.2f MPG.\n", milesPerGallon);
            System.out.print("Would you like to try again? 1 for yes, 2 for no: ");
            restart = input.nextInt();
        }
        milesPerGallon = totalMiles / totalGallons;
        System.out.printf("Your total mileage for these trips is: %.2f.\nYour total gas consumed on these trips was: %.2f.\n", totalMiles, totalGallons);
        System.out.printf("Your total mileage for these trips is: %.2f MPG", milesPerGallon);
    }
}

Mileagetest.java:

package gasMileage;

public class Mileagetest 
{
    public static void main(String[] args) 
    {
        Mileage myMileage = new Mileage(1,0,0,0,0,0);
        myMileage.calculateMileage();
    }
}

Y ahora, para el que no tiene setters y getters:

Testmileage.java:

package gasMileage;

import java.util.Scanner;

public class Testmileage 
{
    int restart = 1;
    double miles = 0, milesTotal = 0, gas = 0, gasTotal = 0, mpg = 0;
    Scanner input = new Scanner(System.in);
    public void testCalculate()
    {
        while(restart == 1)
        {
            System.out.print("Please input miles: ");
            miles = input.nextDouble();
            milesTotal = milesTotal + miles;
            System.out.print("Please input gas: ");
            gas = input.nextDouble();
            gasTotal = gasTotal + gas;
            mpg = miles/gas;
            System.out.printf("MPG: %.2f", mpg);
            System.out.print("\nContinue? 1 = yes, 2 = no: ");
            restart = input.nextInt();
        }
            mpg = milesTotal / gasTotal;
            System.out.printf("Total Miles: %.2f\nTotal Gallons: %.2f\nTotal MPG: %.2f\n", milesTotal, gasTotal, mpg);
    }
}

Testmileagetest.java:

package gasMileage;

public class Testmileagetest 
{

    /**
     * @param args
     */
    public static void main(String[] args) 
    {
        Testmileage test = new Testmileage();
        test.testCalculate();
    }

}

Gracias de nuevo!

¿Fue útil?

Solución

El punto de captadores y definidores, , independientemente del idioma , es ocultar la variable subyacente. Esto le permite añadir la lógica de verificación cuando se trata de establecer un valor - por ejemplo, si usted tenía un campo para una fecha de nacimiento, es posible que desee permitir el establecimiento de ese campo para algún momento en el pasado. Esto no se puede hacer cumplir si el campo es de acceso público y modifyable - que necesita los captadores y definidores

.

Aunque no es necesario ningún tipo de verificación, sin embargo, que debe de estar en el futuro. Escritura de los captadores y definidores ahora significa la interfaz se mantiene constante, por lo que el código existente no se romperá cuando se cambie.

Otros consejos

Las otras respuestas generalmente dan una buena idea de algunas de las razones para el uso de captadores y definidores, pero yo quiero dar un ejemplo un tanto completa de por qué son útiles.

Tomemos, por ejemplo, un archivo (haciendo caso omiso de la existencia de una clase File en Java). Esta clase File tiene un campo para almacenar el tipo de archivo (.pdf, .exe, .txt, etc.) ... vamos a ignorar todo lo demás.

Inicialmente decide guardar como un String sin captadores y definidores:

public class File {
   // ...
   public String type;
   // ...
}

Aquí hay algunos problemas con el no uso captadores y definidores.

No hay control sobre cómo se establece el campo:

Cualquier cliente de su clase pueden hacer lo que quieran con él:

public void doSomething(File file) {
   // ...
   file.type = "this definitely isn't a normal file type";
   // ...
}

más adelante decide que es probable que no quiere que hagan eso ... pero ya que tienen acceso directo al campo en su clase, no hay manera de prevenirlo.

incapacidad de cambiar fácilmente representación interna:

Más tarde, decide que desea almacenar el tipo de archivo como una instancia de un FileType interfaz llamada, lo que le permite asociar un comportamiento con diferentes tipos de archivos. Sin embargo, muchos clientes de su clase ya están recuperación y configuración de tipos de archivos como Strings. Por lo que tendría un problema allí ... que le rompe un montón de código (incluso código en otros proyectos que no se puede solucionar usted mismo, si se trata de una biblioteca) si usted acaba de cambiar el campo de un String a un FileType .

¿Cómo captadores y definidores resuelven este

Ahora imagina que en lugar habían hecho los de private campo de tipo y ha creado

public String getType() {
   return this.type;
}

public void setType(String type) {
   this.type = type;
}

El control sobre el establecimiento de la propiedad:

Ahora, cuando se desea implementar un requisito de que sólo ciertas cadenas son tipos de archivo válidos y prevenir otras cadenas, sólo podría escribir:

public void setType(String type) {
   if(!isValidType(type)) {
       throw new IllegalArgumentException("Invalid file type: " + type);
   }
   this.type = type;
}

private boolean isValidType(String type) {
   // logic here
}

Posibilidad de cambiar fácilmente representación interna:

Cambio de la representación String del tipo es relativamente fácil. Imagine que tiene un enum ValidFileType que implementa FileType y contiene los tipos válidos de archivos.

Desde aquí se puede cambiar la representación interna del tipo de archivo en la clase como esta:

public class File {
   // ...
   private FileType type;
   // ...
   public String getType() {
      return type.toString();
   }

   public void setType(String type) {
      FileType newType = ValidFileType.valueOf(type);

      if(newType == null) {
         throw new IllegalArgumentException("Invalid file type: " + type);
      }

      this.type = newType;
   }
}

Ya que los clientes de la clase han estado llamando y getType() setType() todos modos, nada cambia desde su perspectiva. Sólo la parte interna de la clase cambian, no la interfaz que otras clases están utilizando.

Encapsulación

métodos de acceso ( "incubadoras y getters") intento de ocultar los detalles sobre cómo se almacenan los datos en un objeto. En la práctica, son un medio glorificado para almacenar y recuperar datos de un modo no orientado a objetos. Los descriptores de acceso no se encapsulan efectivamente cualquier cosa en que hay poca diferencia práctica entre las dos piezas de código:

Person bob = new Person();
Colour hair = bob.getHairColour();
hair.setRed( 255 );

Y esto:

Person bob = new Person();
Colour hair = bob.hairColour;
hair.red = 255;

Los dos fragmentos de código exponen la idea de que una persona está estrechamente unida al pelo. Este acoplamiento apretado entonces se revela en toda la base de código, lo que resulta en el software frágil. Es decir, se hace difícil cambiar la forma de almacenar el cabello de una persona.

En lugar de ello:

Person bob = new Person();
bob.setHairColour( Colour.RED );

Esto sigue la premisa de "decir, no le pregunte." En otras palabras, los objetos deben ser instruidos (por otros objetos) para realizar una tarea específica. Este es el punto central de la programación orientada a objetos. Y muy pocas personas parecen conseguirlo.

La diferencia entre los dos escenarios es la siguiente:

  • En la primera situación, Bob no tenía control sobre lo que se convertiría en el color de su pelo. Grande para un estilista con una inclinación por las pelirrojas, no tan grande para Bob que desprecia ese color.
  • En la segunda situación, Bob tiene un control completo sobre qué color se convertirá en el pelo, porque ningún otro objeto en el sistema se le permite cambiar ese color sin el permiso de Bob.

Otra forma de evitar este problema es para devolver una copia del color del pelo de Bob (como una nueva instancia), que ya no está acoplado a Bob. Me parece que para ser una solución poco elegante, ya que significa que hay un comportamiento que otros deseos de clase, utilizando el cabello de una persona, que ya no se asocian a la propia persona. Esto reduce la posibilidad de reutilizar el código, lo que conduce a código duplicado.

Ocultación de tipos de datos

En Java, que no puede tener dos firmas de los métodos que se diferencian sólo por el tipo de retorno, lo que realmente no oculta el tipo de datos subyacente utilizada por el objeto. Rara vez, o nunca, vea lo siguiente:

public class Person {
  private long hColour = 1024;

  public Colour getHairColour() {
    return new Colour( hColour & 255, hColour << 8 & 255, hColour << 16 & 255 );
  }
}

Normalmente, las variables individuales tienen su tipo de datos expuesto verbatim mediante el uso del descriptor de acceso correspondiente, y requiere refactorización para cambiarlo:

public class Person {
  private long hColour = 1024;

  public long getHairColour() {
    return hColour;
  }

  /** Cannot exist in Java: compile error. */
  public Colour getHairColour() {
    return new Colour( hColour & 255, hColour << 8 & 255, hColour<< 16 & 255 );
  }
}

A pesar de que ofrece un nivel de abstracción, es un fino velo que no hace nada por la articulación flexible.

Tell, no preguntar

Para obtener más información sobre este enfoque, lea Tell, no preguntar .

Ejemplo de archivo

Considere el siguiente código, ligeramente modificada de la respuesta de ColinD:

public class File {
   private String type = "";

   public String getType() {
      return this.type;
   }

   public void setType( String type ) {
      if( type = null ) {
        type = "";
      }

      this.type = type;
   }

   public boolean isValidType( String type ) {
      return getType().equalsIgnoreCase( type );
   }
}

El getType() método en este ejemplo es redundante y, inevitablemente, (en la práctica) conducen a código duplicado tales como:

public void arbitraryMethod( File file ) {
  if( file.getType() == "JPEG" ) {
    // Code.
  }
}

public void anotherArbitraryMethod( File file ) {
  if( file.getType() == "WP" ) {
    // Code.
  }
}

Temas:

  • Tipo de datos. El atributo type no puede cambiar fácilmente de una cadena a un entero (o de otra clase).
  • Protocolo implícita. Es mucho tiempo para abstraer el tipo de lo específico (PNG, JPEG, TIFF, EPS) a lo general (IMAGE, DOCUMENT, SPREADSHEET).
  • Presenta errores. Cambiar el protocolo implícito no generará un error de compilación, que puede conducir a errores.

Evitar el problema por completo mediante la prevención de otras clases de pidiendo para datos:

public void arbitraryMethod( File file ) {
  if( file.isValidType( "JPEG" ) ) {
    // Code.
  }
}

Esto implica cambiar el método get de acceso a private:

public class File {
   public final static String TYPE_IMAGE = "IMAGE";

   private String type = "";

   private String getType() {
      return this.type;
   }

   public void setType( String type ) {
      if( type == null ) {
        type = "";
      }
      else if(
        type.equalsIgnoreCase( "JPEG" ) ||
        type.equalsIgnoreCase( "JPG" ) ||
        type.equalsIgnoreCase( "PNG" ) ) {
        type = File.TYPE_IMAGE;
      }

      this.type = type;
   }

   public boolean isValidType( String type ) {
      // Coerce the given type to a generic type.
      //
      File f = new File( this );
      f.setType( type );

      // Check if the generic type is valid.
      //
      return isValidGenericType( f.getType() );
   }
}

Ningún otro código en el sistema se romperá cuando la clase File transiciones el protocolo implícita de tipos específicos (por ejemplo, JPEG) a tipos genéricos (por ejemplo, imagen). Todo el código en el sistema debe utilizar el método isValidType, que no da el tipo con el objeto de llamar, pero dice laclase File para validar un tipo.

La idea es que si sus clases de cliente llaman funciones get / set, puede cambiar lo que hacen las personas que llaman más tarde y están aisladas. Si usted tiene una variable pública, y acceder a él directamente, no hay manera para que usted agregue un comportamiento más tarde, cuando se accede a ella o conjunto.

A pesar de su sencillo ejemplo, se podría sacar más provecho de ella.

En lugar de utilizar:

milesPerGallon = miles / gallons;

en calculateMileage ()

Se puede cambiar setMiles () y setGallons () para actualizar milesPerGallon cuando fueron llamados. A continuación, retire setMilesPerGallon () para indicar que se trata de una propiedad de sólo lectura.

El punto es que una clase no se debe permitir el acceso directo a sus campos, porque esto es específico de la implementación. Es posible que desee cambiar la clase más adelante con el fin de utilizar otro almacenamiento de datos, pero mantener a la clase de la misma por sus "usuarios", o es posible que desee crear una interfaz que no se pueden incluir campos tampoco.

Tener un vistazo a la artículo de Wikipedia sobre el tema.

Proporcionan una interfaz pública para su clase, y un cierto grado de encapsulación. Considere cómo se accede a los datos públicos sin captadores y definidores.

Mileage m = new Mileage();
m.miles = 5.0;
m.gallons = 10.0;
...

Ahora bien, si usted decide que quiere añadir un poco de validación a su clase, usted tiene que cambiar su código en todas partes que se accede directamente a los campos. Si sólo utiliza captadores y definidores desde el principio ( sólo cuando se necesitan ) se puede evitar que el esfuerzo, y sólo cambiar el código en un solo lugar.

El uso de captadores y definidores le da la flexibilidad para cambiar la posterior implementación. Es posible que no cree necesario que, pero a veces hacer. Por ejemplo, es posible que desee utilizar el patrón Proxy para la carga perezosa un objeto que es caro para el uso:

class ExpensiveObject {
    private int foo;

    public ExpensiveObject() {
       // Does something that takes a long time.
    }

    public int getFoo() { return foo; }
    public void setFoo(int i) { foo = i; }
}

class ExpensiveObjectProxy extends ExpensiveObject {
    private ExpensiveObject realObject;

    public ExpensiveObjectProxy() { ; }

    protected void Load() {
       if ( realObject == null ) realObject = new ExpensiveObject();
    }

    public int getFoo() { Load(); return realObject.getFoo(); }
    public void setFoo(int i) { Load(); realObject.setFoo(i); }
}

class Main {
    public static void main( string[] args ) {
         // This takes no time, since ExpensiveOjbect is not constructed yet.
         ExpensiveObject myObj = new ExpensiveObjectProxy();

         // ExpensiveObject is actually constructed here, when you first use it.
         int i = myObj.getFoo();
    }
}

Cuando esto viene a menudo a jugar es cuando se tiene objetos asignados a las bases de datos a través de un ORM. Sólo se carga el material que necesita, a continuación, volver a la base de datos para cargar el resto si / cuando se utiliza realmente.

En definidores generales y captadores eran un mal corte por los constructores GUI tempranas (Borland) para moverse por el hecho de que todas las variables deben ser privadas (En realidad, esto es absolutamente necesario)

Algunas personas los llaman una abstracción, pero no lo son. Un repetitivo setter / getter no es mejor que un miembro del público. Todavía se permite el pleno acceso a la variable, a veces la clase no puede controlar y restringir aún cambios en su clase (si la variable es un entero, que todavía tiene que cambiar todo lo que llama el setter y getter para cambiar la variable a una cadena )

captadores y definidores favorecerán un acceso a los datos de una clase desde fuera de la clase. Cualquier código que accede a un miembro de una clase, probablemente, debe existir dentro de esa clase (como sus estados de diseño) y por lo tanto no debería necesitar set o captadores. Deben ser innecesaria.

También obligando a un organismo en todas sus clases es horrible, significa que sus clases simplemente no pueden ser inmutables mientras que en realidad se debe tener una buena razón para hacer una clase mutable.

Dicho esto, que son una especie de utilidad para cuestiones transversales como los motores de persistencia y constructores GUI donde pueden obtener y configurar los valores y la clase pueden monitorear lo que se obtuvo o se cambia y modificar o validarlo.

Una mejor patrón para aquellos sistemas que necesitan el transversales de acceso variable sería para acceder a la variable directamente a través de la reflexión que llamar a una incubadora o getter si existe -. Hacer que el setter y getter privada si es posible

Esto permitiría la no-OO código transversales para que funcione correctamente, permitiría a su clase para modificar conjuntos y obtiene cuando se necesita y permitir captadores (que a veces son muy útiles) cuando sea necesario.

El punto de métodos de acceso, es decir. captadores y definidores es proporcionar información de encapsulación También conocido como escondite. Es uno de los principios básicos de la programación orientada a objetos.

métodos de acceso

ocultación de la información / encapsulación

La respuesta en una palabra es las interfaces .

Las interfaces permiten a los métodos, no los campos, por lo que la convención establecida es tener métodos getX y setX para este propósito.

(e interfaces es la manera de desvincular la funcionalidad de la aplicación en Java)

Su ejemplo es extremo al punto de lo absurdo. Sí, todos los captadores y definidores hinchan el código y añadir ningún valor en ese caso. Pero la idea subyacente de encapsulación es para sistemas más grandes compuestas de muchos componentes que interactúan, no para programas pequeños y autónomos.

Características de los usos útiles, sensibles de captadores y definidores:

  • Una clase que es utilizado por muchas otras clases (ocultar detalles de implementación hace que sea más fácil para los clientes)
  • Los captadores y definidores solamente para los campos para los que en realidad son necesarios - los menos posibles, la mayoría de los campos deben ser privadas y utilizados exclusivamente en su clase
  • Muy pocos emisores en general: campos variables hacen que sea mucho más difícil hacer un seguimiento del estado del programa de campos de sólo lectura
  • Los captadores y definidores que realmente hacer algo además de acceder a una cado, por ejemplo, setters que generen excepciones para los valores no válidos o actualizar una marca de tiempo "última modificación", o un captador que calcula un valor sobre la marcha en lugar de depender de un campo subyacente

Un avance rápido de unos meses. Tal vez su profesor le pide a implementar una versión remota de la clase kilometraje. Tal vez como un servicio web, tal vez algo más.

Sin los captadores / definidores, que tendría que cambiar todos los códigos de todas partes que un acccesses Kilometraje, con los captadores / definidores que más o menos (en un mundo perfecto al menos) solo hay que cambiar la creación de un tipo de kilometraje.

Los captadores y definidores permiten crear accesos directos útiles para el acceso y la mutación de datos dentro de un objeto. Generalmente, esto puede ser visto como una alternativa a tener dos funciones con un objeto que se utilizan para obtener y establecer un valor, así:

{
    getValue: function(){
        return this._value;
    },
    setValue: function(val){
        this._value = val;
    }
}

La ventaja obvia para escribir JavaScript de esta manera es que se puede usar valores oscuros que no desee el usuario para acceder directamente. Un resultado final buscando algo como lo siguiente (utilizando un cierre para almacenar el valor de un campo de nueva construcción):

function Field(val){
    var value = val;

    this.getValue = function(){
        return value;
    };

    this.setValue = function(val){
        value = val;
    };
}

Adición Setter y métodos de captador Para hacer que el estado del bean gestionado accesible, es necesario agregar métodos setter y getter para ese estado. El método createSalutation llama al método bean'sgreet, y el método getSalutation recupera el resultado. Una vez que se han añadido los métodos setter y getter, el grano se ha completado. El código final es el siguiente: saludos del paquete;

import javax.inject.Inject;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class Printer {

    @Inject @Informal Greeting greeting;

    private String name;
    private String salutation;

    public void createSalutation() {
        this.salutation = greeting.greet(name);
    }

    public String getSalutation() {
        return salutation;
    }
    public String setName(String name) {
       this.name = name;
    }

    public String getName() {
       return name;
    }
}

La encapsulación y código de reutilización de capacidad es la belleza de la programación orientada a objetos. Si estamos tratando con algunos datos sensibles en nuestro código entonces declaran como campos de datos privados, es decir, encapsulamos nuestros datos para que nadie pueda acceder a ella directly.Now cualquiera que quiera acceder a los datos de los campos deben hacer uso de incubadoras y captadores es decir, un mecanismo de acceso controlado para hacer frente a los campos de datos sensibles. Siguiendo el ejemplo puede ser útil para comprender la ventaja y la importancia de la moda y captadores.

  • Me han puesto en marcha una clase en la que estoy haciendo uso de días variable.
  • En mi clase no se puede establecer el valor de más de 365 días.
  • Alguien quiere heredar de mi clase. (Código de reutilización).
  • Ahora cuando entra en el valor de más de 365 días, a continuación, toda la funcionalidad de mi clase se producirá un error.
  • Por lo tanto yo debería haber declarado las variables días como campo de datos privados.
  • Ahora bien, si yo había declarado días de campo de datos como privado, nadie podía establecer el valor de días más de 365 como me hubiera puesto en marcha un setter funciones con limitaciones mencionadas sobre la entrada.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top