In che modo sono definiti getter e setter?

4

Nota: prima sono state poste domande con titolo simile, ma per favore leggi il testo completo prima di rivendicare che si tratta di un duplicato.

Dato che tutti in OOP usano i termini getter e setter , mi aspetterei che avere un significato ben definito. Ma quello che ho trovato sono fondamentalmente due affermazioni sono in qualche modo contraddittori:

(A) Forniscono accesso in lettura o scrittura a un attributo specifico.

Questo è ciò che praticamente tutti i getter e setter che ho visto nel codice di produzione. Un getter restituisce il valore di un attributo e un setter imposta il valore di un attributo.

D'altra parte:

(B) Permettono di nascondere la rappresentazione interna dei dati all'interno di una classe mentre sono ancora in grado di accedervi e modificarla.

Un esempio in Java:

private double x, y;
public double getX() { return x; }
public double getY() { return y; }

Questo ovviamente è conforme a (A). Ora secondo (B) potremmo cambiare la rappresentazione dei dati:

private double angle, distance;
public double getX() { return distance * Math.cos(angle); }
public double getY() { return distance * Math.sin(angle); }

Questo non è più conforme a (A) perché non ci sono più attributi denominati X e Y ei valori di ritorno sono il risultato di un calcolo. Ma li chiamerei ancora getter.

Altri esempi:

  1. Questo è ovviamente un setter:

    private double length;
    public void setLength(double newLength) {
        length = newLength;
    }
    
  2. La maggior parte delle definizioni consente al setter di effettuare alcuni controlli:

    private double length;
    public void setLength(double newLength) {
        length = (newLength > 0) ? newLength : 0;
    }
    
  3. Non sono sicuro di questo. Nota che potrebbero esserci più setter per un attributo:

    private double length;
    public void setLengthInInches(double newLength) {
        length = 25.4 * newLength;
    }
    
  4. Questo imposta due attributi:

    private double length;
    private UnitType lengthUnit;
    public void setLengthInInches(double newLength) {
        length = newLength;
        lengthUnit = UNIT_INCH;
    }
    
  5. Simile a 4 ma con due argomenti:

    private double length;
    private UnitType lengthUnit;
    public void setLength(double newLength, UnitType newLengthUnit) {
        length = newLength;
        lengthUnit = newLengthUnit;
    }
    
  6. Un'altra variante:

    private double length;
    private UnitType lengthUnit;
    public void setLength(LengthType newLength) {
        length = newLength.getValue();
        lengthUnit = newLength.getUnit();
    }
    
  7. Qui l'attributo non esiste ma può essere calcolato:

    private double start;
    private double end;
    public void setLength(double newLength) {
        end = start + newLength;
    }
    
  8. Che dire di questo:

    private int productId;
    private Price price;
    public void setLength(double newLength) {
        productId = getProductIdByLength(newLength);
        price = BASE_PRICE + PRICE_PER_LENGTH_UNIT * newLength;
    }
    
  9. E questo:

    private double length;
    public void setLength(SomeInput input) {
        length = input.doSomeComplicatedStuffToCalculateLength();
    }
    

Quali di questi sono setter e quali no?

    
posta Frank Puffer 25.05.2017 - 13:39
fonte

4 risposte

3

Mi piacciono i C # / Ruby / Python / etc. terminologia di Proprietà . Penso che questo aiuti a chiarire un po 'il concetto. Le proprietà in C # sono un bel modo per scrivere setter e getter formalizzati. In Java le proprietà sono una questione di convenzione (cioè JavaBeans con la coppia set / get che condivide lo stesso nome).

Le proprietà sono esposte ai valori logici che intendete interagire con altri codici. Come molti dei tuoi esempi hanno dimostrato, la rappresentazione interna non è necessaria per corrispondere alla rappresentazione logica .

Come regola generale, scoprirai che mantenere l'implementazione delle proprietà nel modo più semplice possibile ti darà la migliore opzione per mantenere il tuo software. Cose che sono perfettamente accettabili in setter / getter:

  • Rappresentazione semplice dello stato interno (es. esposizione di un campo di classe)
  • Vincolare valori (setter forza il valore all'interno di un intervallo)
  • Conversioni semplici da / verso unità interne (ad esempio, ottieni / imposta XInYards puoi convertire la rappresentazione interna in metri in metri)
  • Proprietà di sola lettura calcolata

Le cose che possono metterti nei guai includono:

  • Modifica di più proprietà quando ne imposti uno
  • Esecuzione di azioni che richiedono try / catch semantics in un getter

L'assunto con le proprietà è che l'impostazione e il recupero dei valori è molto semplice, molto veloce e sicura. In più lingue, è possibile associare elementi dell'interfaccia utente direttamente alle proprietà (anche JavaBeans). Se la tua logica è sufficientemente complessa, sarebbe meglio fornire un metodo appropriato per assegnare o recuperare informazioni.

    
risposta data 25.05.2017 - 14:55
fonte
3

La definizione più primitiva è che il getter è un metodo che recupera un valore e un setter è un metodo che modifica un valore. Non è necessario che il valore sia supportato da un campo o persino memorizzato nell'oggetto di implementazione.

Per .net in particolare, ci sono una serie di linee guida da seguire che assicurano che le proprietà (getter e setter in .net) si comportino in modo prevedibile: Progettazione proprietà

Uno dei concetti più importanti è che le proprietà dovrebbero essere ortogonali; l'impostazione di una proprietà non dovrebbe influire su un'altra.

    
risposta data 25.05.2017 - 20:24
fonte
1

Consideriamo la motivazione di essere in grado di far evolvere la tua base di codice che è dietro l'uso (e la promozione popolare) di getter e setter.

L'accesso diretto ai campi limita le nostre capacità di evolvere le nostre classi, ad esempio, potendo notare quando qualcosa cambia.

Inserisci getter e setter, che possono essere semplici come l'accesso al campo o complessi come vorremmo. Una volta che il client utilizza i metodi invece dell'accesso diretto al campo, possiamo evolvere il codice dietro i getter & setter a volontà. Potremmo persino utilizzare metodi virtuali e sostituzioni, e i chiamanti non dovranno ancora cambiare.

Dato che lo scopo di getter e setter è quello di fornire un percorso evolutivo per il mantenimento del codice, in generale, dovremmo aspettarci di trovare getter e setter con una vasta gamma di implementazioni, alcuni dei quali hanno approfittato di questo capacità evolutiva (se non lo facessimo potremmo anche usare l'accesso diretto al campo).

Fondamentalmente, il contratto non dichiarato di getter e setter è che il valore restituito dal getter non cambia fino a quando non viene utilizzato il setter e che una volta che il setter viene utilizzato, il getter restituisce il valore aggiornato. Questo potrebbe essere formalizzato (ad esempio il contratto / comportamento di Lenti nella programmazione funzionale) ma non sono consapevole che ciò sia stato fatto in OOP.

Possiamo anche aggiungere quello che @FrankHileman dice che l'impostazione di una proprietà non dovrebbe influire su un'altra.

Tuttavia, ci sono alcune combinazioni, ad esempio, dove potresti considerare getter e ampover sovraccaricati; setter: un setter per l'impostazione della temperatura in gradi F più uno per l'impostazione della temperatura in gradi C, ci aspettiamo che entrambi i getter restituiscano un valore diverso se viene utilizzato uno dei due setter.

Alla luce di questo, presumerei tutti i tuoi esempi per getter / setter validi, anche se ciò richiede di immaginare un getter corrispondente, poiché la maggior parte dei tuoi esempi non mostra il getter.

(Eppure, sì, ci sono validi motivi per avere un getter senza setter e viceversa.)

    
risposta data 25.05.2017 - 21:27
fonte
1

(A) They provide read or write access to a specific attribute.

(B) They allow hiding the internal representation of data inside a class while still being able to access and modify it.

Poiché si accede all'attributo tramite un metodo, tecnicamente lo fanno entrambi. Se hai modificato la rappresentazione interna dell'attributo, questa modifica può essere nascosta per codificare quel metodo getter chiamato perché hai un metodo per trasformare i dati nel formato previsto.

Ad esempio (scusa lo pseudocodice) dì che in origine hai memorizzato un valore come e intero

class MySillyClass {
  Integer my_number = 39

  Integer myNumber() {
    return my_number
  }
}

ma poi decidi di salvarlo come stringa. Può cambiare la stringa di nuovo in un numero intero nel metodo getter in modo che il codice che si basa su questo valore essendo un numero intero non si rompa

class MySillyClass {
  String my_number = "39"

  Integer myNumber() {
    return my_number.to_integer
  }
}

Va sottolineato che Getters e Setter sono ancora una pessima idea e mancano il punto fondamentale del design orientato agli oggetti. I tuoi oggetti dovrebbero esporre comportamenti specifici relativi a ciò che fanno nel sistema. Un getter o setter è un odore di codice che il tuo oggetto trattiene i dati di qualcun altro e che l'oggetto non è progettato correttamente

    
risposta data 29.05.2017 - 16:38
fonte