Che senso ha rendere le variabili private o protette in Java? [duplicare]

-2

Esiste davvero un reale utilizzo per variabili private e momenti specifici in cui sarebbero l'unica opzione possibile? O puoi semplicemente impostare tutte le variabili come pubbliche senza alcuna modifica effettiva al programma? Sembra una pratica inutile che non cambia molto, dal mio punto di vista, quindi mi chiedo se sto trascurando qualcosa.

    
posta GiraffeKey 21.09.2018 - 18:38
fonte

1 risposta

2

Questo è stato chiesto molte volte prima, quindi segui i collegamenti forniti nella sezione commenti sotto la tua domanda, e riceverai un sacco di risposte. Ma lascia che li inserisca nel contesto.

Se (1) le persone potessero scrivere perfettamente anche un software leggermente complesso al primo tentativo, e se (2) il codice non cambierà mai, allora le variabili private sono inutili. Ma (1) & & (2) insieme non sono praticamente mai il caso nel mondo reale. Per scrivere codice che può essere modificato e mantenuto, è necessario controllare le interdipendenze tra diverse pars di esso, in modo che sia possibile modificare ciascuna parte in un modo che non richiede modifiche o modifiche minime alle altre parti. Uno dei modi per farlo è nascondere i dettagli di implementazione delle classi interagenti. Questo è chiamato incapsulamento, ed è per questo che hai membri privati. Tuttavia, il punto è non per rendere questi membri privati e poi esporli comunque con getter e setter corrispondenti. Questa mappatura 1-a-1 tra membri e getter ha poca utilità (sì, ci sono alcuni vantaggi, c'è qualche livello di incapsulamento, ma non è così che lo fai , anche se è così che lo vedrai descritto nei corsi di programmazione). Quello che fai è fornire un insieme di funzioni membro (metodi) che espone pochissimo (se mai) sulla struttura interna della classe al mondo esterno (le altre classi che chiamano questo codice). Questi metodi sono formulati in modo che il codice esterno non chieda alla classe i suoi dati interni per fare qualcosa con quei dati, ma chiede invece alla classe di completare alcune attività per esso. Ciò consente quindi di modificare completamente l'implementazione della classe senza influire sul codice esterno, a condizione che non si modifichi la firma delle funzioni "rivolte verso l'esterno". E se la tua classe implementa un'interfaccia Java e la logica esterna è codificata su quella interfaccia, puoi anche scambiare la classe con un'altra completamente (anche in fase di esecuzione).

Considera questo esempio (abbastanza forzato):

class Main {
  public static void main(String[] args) {
    Grower1 g1 = new Grower1();
    g1.value += 1;                    // must change
    if (g1.value < 10) {              // must change
      System.out.println(g1.value);   // prints out: 1
    }

    Grower2 g2 = new Grower2();
    g2.grow();
    if (g2.getValue() < 10) {                // must change
      System.out.println(g2.getValue());     // prints out: 1
    }

    Grower3 g3 = new Grower3();
    g3.grow();
    if (g3.isAlive()) {
      System.out.println(g3.toString());    // prints out: 1
    }
  }
}

class Grower1 {
  public int value = 0;
}

class Grower2 {
  private int value = 0;

  public int getValue() {
    return this.value;
  }

  public void grow() {
    this.value += 1;
  }
}

class Grower3 {
  private int value = 0;

  public void grow() {
    this.value += 1;
  }

  public boolean isAlive() {
    return this.value < 10;
  }

  public String toString() {
    return Integer.toString(this.value);
  }
}

Qui, un "Coltivatore" è una classe che può "crescere" in un certo senso e ha fino a 10 cicli di crescita. Se ti chiedessi di cambiare Grower1 in modo che invece di incrementare un numero cresca aggiungendo il carattere 'a' alla stringa iniziale "a" (così, va "a" - > "aa" - > " aaa ", ecc.), dovresti cambiare il codice in Main. Se provassi a fare lo stesso con Grower2, sarebbe un po 'più semplice, ma dovresti comunque cambiare il codice in Main, anche se in meno punti. Se lo hai fatto con Grower3, nulla in Main deve cambiare (perché i membri pubblici di Grower3 non rivelano in alcun modo che value è un intero):

class Main {
  public static void main(String[] args) {

    // omitted code related to Grower1 & Grower2...

    // still works with no changes
    Grower3 g3 = new Grower3();
    g3.grow();
    if (g3.isAlive()) {
      System.out.println(g3.toString());    // prints out: aa
    }
  }
}

// omitted Grower1 & Grower2 classes...

class Grower3 {
  private String value = "a";

  public void grow() {
    this.value += "a";
  }

  public boolean isAlive() {
    return this.value.length() < 10;
  }

  public String toString() {
    return this.value;
  }
}

Il trucco è capire come progettare i metodi pubblici in modo da poter fare questo genere di cose.

    
risposta data 21.09.2018 - 20:09
fonte

Leggi altre domande sui tag