Qual è l'utilità delle variabili private? [duplicare]

6

Anche se non ho mai usato un linguaggio che includeva la privacy variabile integrata, un libro che sto leggendo da Douglas Crockford spiega un modo per creare privacy in JavaScript, tuttavia non ha senso per me. Il termine "privato" non è qualcosa che penso sia addirittura possibile in un ambiente di programmazione, dal momento che tutti quelli che lavorano sul codice possono potenzialmente modificare qualsiasi oggetto o metodo mutevole, giusto?

Quindi le due cose che non hanno senso per me sono

  • come la privacy è utile
  • come viene definita la privacy - fondamentalmente uno sviluppatore non può mantenere qualcosa nel codice sorgente assolutamente privato ("intoccabile", come lo comprendo io) da un altro sviluppatore, quindi dove si considera la variabile "privato"? Quando è difficile da raggiungere?

Qualcuno può spiegarlo, possibilmente con un esempio di "mondo reale"?

    
posta Viziionary 22.09.2015 - 17:28
fonte

6 risposte

37

All'interno dello sviluppo del software, la privacy (delle entità software) viene solitamente definita come limitante l'accesso a tale variabile / funzione / metodo. Se una variabile è privata, solo le funzioni oi metodi che appartengono alla stessa classe o modulo possono / devono accedere a tale variabile.

Come vedi, la privacy qui non è completamente correlata a quello che lo sviluppatore sta scrivendo il codice, ma piuttosto riguarda quali parti del codice hanno accesso a quali altre parti del codice.

Il vantaggio delle variabili o delle funzioni private è che, limitando le parti del codice che hanno accesso, puoi più facilmente ragionare su come la variabile viene utilizzata e chi sarà interessato se la cambi.

    
risposta data 22.09.2015 - 17:55
fonte
15

Certo, uno sviluppatore con accesso al codice sorgente potrebbe iniziare a manipolare ciò che vuole. E nel processo rende qualcosa di molto fragile e non gestibile.

Rendendo il più privato possibile, rispettando questo, e mostrando solo interfacce ben definite, puoi semplificare il cambiamento delle cose dietro la scena, per esempio, correggere bug o migliorare le prestazioni. Se un altro codice fa casino con le variabili, allora le modifiche sono piuttosto difficili, perché causeranno l'interruzione dell'altro codice.

Non sono sicuro di come Javascript gestisca la privacy, ma in linguaggi come Java e C ++ c'è un supporto per il compilatore per rafforzare la privacy.

Considera una classe che rappresenta un indirizzo IP:

public class IpAddress {

  public string ipAddress;

}

Al momento, chiunque può inserire qualsiasi cosa in ipAddress (è un campo pubblico).

IpAddress ia = new IpAddress();
ia.ipAddress = "weeeee!";

Ultimo controllo, weeeee! non era un indirizzo IP valido. Ma, rendendolo privato, possiamo assicurarci che gli indirizzi non validi vengano buttati fuori. Naturalmente, avremo ancora bisogno di un modo per accedervi e aggiornarlo. Quindi creiamo metodi pubblici:

public class IpAddress {

  private string ipAddress;

  public string toString() {
    return ipAddress;
  }

  public boolean setipAddress(string newIp) {

    if (isValid(newIp)) {
      ipAddress = newIp;

      return true;

    } else {
      return false;
    }
  }

}

Nota che ora abbiamo ancora accesso al valore dell'indirizzo IP e possiamo aggiornarlo, ma ora possiamo essere sicuri che quando viene aggiornato, il nuovo valore è un valore valido, invece di qualcosa come weeeee! .

ia.ipAddress = "this won't compile";
ia.setipAddress("This won't update the address");
ia.setipAddress("192.168.0.1"); // works

Allo stesso modo, se decidessimo che string è un modo scadente di memorizzare un indirizzo IP? Forse un quartetto di int s sarebbe meglio. Prima, quando il campo ipAddress era pubblico, qualsiasi codice che lo utilizzava, o semplicemente per visualizzarlo o per modificarlo, si interrompeva se provassimo a modificare il nostro schema di archiviazione. Ma dal momento che stiamo usando metodi pubblici per l'accesso invece di accedere direttamente al campo, possiamo farlo senza rompere nulla:

public class IpAddress {

  private int part1;
  private int part2;
  private int part3;
  private int part4;

  public string toString() {
    return "" + part1 "." + part2 + "." + part3 + "." + part4;
  }

  public boolean setipAddress(string newIp) {

    if (isValid(newIp)) {
      part1 = extractOct(newIp,1);
      part2 = extractOct(newIp,2);
      part3 = extractOct(newIp,3);
      part4 = extractOct(newIp,4);

      return true;

    } else {
      return false;
    }
  }

}

Dal punto di vista di chiunque usi questa classe, sembra che questo stia memorizzando l'indirizzo IP come string o quattro int s:

public class IpAddress {

  public string toString()

  public boolean setIpAddress(string newIp)

}

e non hanno bisogno di sapere, o si preoccupano che le cose siano cambiate dietro le quinte. *

* In generale. Alcuni casi rari potrebbero interessare. Per esempio. i sistemi in tempo reale possono essere sensibili ai cambiamenti delle prestazioni, sia più veloci che più lenti.

    
risposta data 22.09.2015 - 17:35
fonte
9

Immagina di scrivere una libreria javascript e hai definito una variabile size in cui hai archiviato una certa dimensione. Dal momento che non la incapsula, essa entra nello spazio dei nomi globale.

Ora qualcuno arriva e assegna un valore a size , non sapendo che lo hai già definito. Oh caro. Ha appena rotto la tua biblioteca. E quando assegni nuovamente a size , interrompi il suo codice.

Ora bevi un brindisi per l'incapsulamento.

    
risposta data 22.09.2015 - 17:50
fonte
2

È importante non confondere due cose diverse. Non puoi garantire che nessuno cambierà la fonte della tua classe e non puoi garantire che funzionerà come previsto se qualcuno la modifica. Ma ciò che puoi fare è rendere molto più facile scrivere codice che funziona come previsto adesso , in tutti i possibili casi d'uso.

Ad esempio, supponiamo di voler creare un Fraction . Ha bisogno di alcune funzionalità. Diciamo che deve essere in grado di verificare l'uguaglianza con un'altra frazione. (Realisticamente probabilmente avrebbe bisogno di molto di più, ma cerchiamo di mantenerlo semplice). Vogliamo anche una regola: una frazione può sempre essere ridotta (2/4 = 1/2).

Proviamo (userò la sintassi C # -ish piuttosto che javascript ma dovrebbe essere abbastanza leggibile):

public class Fraction
{
    public int Numerator;
    public int Denominator;

    public Fraction(int numerator, int denominator)
    {
        Numerator = numerator;
        Denominator = denominator;
        Reduce();
    }

    public void Reduce()
    {
        //Some implementation here to reduce this fraction
    }

    public bool Equals(Fraction other)
    {
        return Numerator == other.Numerator && Denominator == other.Denominator;
    }
}

Funziona? Beh no. Cosa succede se qualcuno lo fa:

var aHalf = new Fraction(1,2);
var anotherHalf = new Fraction(2,4);
var same = aHalf.Equals(anotherHalf);  // This is true

anotherHalf.Numerator = 2;
anotherHalf.Denominator = 4;
same = aHalf.Equals(anotherHalf);  // This is false!

Forse potresti provare a mettere una chiamata a Reduce() all'interno di Equals . Ma allora cosa succede se lo fai:

var aHalf = new Fraction(1,2);
var anotherHalf = new Fraction(2,4);
anotherHalf.Denominator = 2;
anotherHalf.Equals(aHalf);

anotherHalf.Numerator = 1;
var same = anotherHalf.Equals(aHalf); // This is false!

A causa della modifica inaspettata all'interno di Equals , questo codice che dovrebbe apparire in anotherHalf è 1/2, in realtà è 1/1. Ancor più previsto, se avessi fatto aHalf.Equals(anotherHalf) , avresti il risultato opposto.

Che situazione confusa e complicata abbiamo creato per noi stessi! E perché? Se guardi indietro, l'unica funzionalità che abbiamo deciso per Fraction è di esporre Equals . Quindi, perché abbiamo anche esposto Numerator e Denominator e rendiamo così difficile implementare correttamente il comportamento di cui abbiamo effettivamente bisogno? Tutto quello che devi fare è renderli private e la nostra implementazione iniziale funziona senza ulteriori problemi.

    
risposta data 22.09.2015 - 18:15
fonte
1

Supponi di modellare una persona e, nel far ciò, vuoi monitorare l'età della persona. È possibile utilizzare un numero intero per rappresentare l'età della persona. Vorresti che il codice cliente fosse in grado di modificare l'età di una persona su un valore negativo?

In questo esempio, rendendo l'età qualcosa di privato e fornendo funzioni pubbliche che operano su quel valore, puoi fare certe garanzie sul valore della variabile.

Generalmente, le variabili private consentono di separare il codice client dalla rappresentazione della soluzione, in modo che la rappresentazione possa cambiare senza costringere il client a cambiare.

    
risposta data 22.09.2015 - 17:48
fonte
1

Per quanto ho capito, "incapsulamento" riguarda principalmente la protezione dello stato interno del sistema che stai sviluppando.

Supponiamo che tu stia sviluppando una classe con alcuni campi e metodi:

class Arithmetic
{
    private int j;
    private int k;

    public Arithmetic(int j, int k)
    {
        this.j = j;
        this.k = k;
    }

    public int returnProduct()
    {
        return this.j * this.k;
    }

    public int returnSum()
    {
        return this.j + this.k
    }
}

In questo esempio l'unico punto di ingresso per cambiare lo stato all'interno della classe è attraverso il costruttore. Quindi quando crei un oggetto di tipo Aritmetico, sai oltre ogni dubbio cosa sono j e k quando vai a chiamare returnProduct e returnSum.

Ora guardiamolo di nuovo ma con un setter su una delle variabili:

class Arithmetic
{
    private int j;
    private int k;

    public Arithmetic(int j, int k)
    {
        this.j = j;
        this.k = k;
    }

    public setj(int j)
    {
        this.j = j;
    }

    public int returnProduct()
    {
        return this.j * this.k;
    }

    public int returnSum()
    {
        return this.j + this.k
    }
}

Ora se qualcuno istanzia un oggetto di tipo Aritmetico, e poi qualcuno in seguito prende lo stesso oggetto e aggiorna uno dei suoi campi con il setter, l'oggetto può restituire un comportamento inaspettato.

Quindi per generalizzare lo scopo della privatizzazione o "incapsulamento" (uno dei tre pilastri della programmazione OO), nel primo esempio ciò che stiamo facendo è ridurre al minimo la capacità di un programmatore di mutare lo stato dell'oggetto.

Quanto più codifichiamo in questo stile, tanto più siamo sicuri dello stato del nostro sistema in un dato momento, e meno errori saranno soggetti al nostro codice.

Quindi la regola generale è questa:

Quando stai codificando, permetti a un programmatore o utente la minima visibilità nel sistema che permetta comunque loro di usare il sistema o continuare a sviluppare il sistema.

    
risposta data 22.09.2015 - 21:54
fonte

Leggi altre domande sui tag