I getter superficiali sono overlake sfacciati?

8

Qualcosa a cui non avevo mai pensato prima (sintassi AS3):

private var m_obj:Object;
protected function get obj():Object
{
    return m_obj;
}

private var m_str:String;
protected function get str():String
{
    return m_str;
}

Almeno le sottoclassi non saranno in grado di impostare m_obj o m_str (sebbene possano ancora modificare m_obj).

La mia domanda: si tratta semplicemente di eccessivo sfruttamento?

Questa domanda del programmatore: Quando o perché dovresti usare getter / setter per le proprietà di classe invece di renderle semplicemente proprietà pubbliche? è stato suggerito come duplicato.

Questa domanda è diversa perché si rivolge solo alle proprietà pubbliche e private e se una proprietà deve essere inclusa con getter e amp; setter. Per la mia domanda, mi sto concentrando sulle variabili protette e su come l'ereditazione delle classi interagirebbe con quelle variabili.

Quindi l'implementazione alternativa sarebbe:

protected var m_obj:Object; //more accessible than a private variable with a protected getter
protected var m_str:String; //more accessible than a private variable with a protected getter

La mia domanda è simile perché sto usando i > banali getter protetti per bloccare sottoclassi dalla scrittura alle variabili, ma per consentire loro tutti gli altri accessi.
In linguaggi come AS3, questo permetterà anche a loro di apportare qualsiasi modifica alle variabili oggetto mutabili, purché i riferimenti stessi non vengano modificati.

    
posta Panzercrisis 24.10.2013 - 14:57
fonte

4 risposte

6

Is this just blatant overkill?

Spesso lo è, a volte non lo è.

Mantenere il m_obj in uno stato buono noto aiuta a proteggere il Principio di sostituzione di Liskov, mantenendo il codice più resiliente e di migliore qualità. A volte puoi avere fiducia che gli eredi rispettino quel comportamento, a volte non puoi (a causa del modello di utilizzo o della sottigliezza del contratto che implementa). Anche se questo codice / domanda incappa anche su alcuni dei motivi per " Perché il codice pulito suggerisce di evitare variabili protette? "

    
risposta data 24.10.2013 - 15:19
fonte
13

I getter protetti trivial hanno almeno due vantaggi pratici su una variabile esposta:

  • Per il debug, sono un posto perfetto per mettere un breakpoint condizionale che si innesca quando "quel buffo valore entra nel tuo programma". È molto più difficile ottenere lo stesso controllo se si accede direttamente al valore.

  • Per deridere un oggetto, se stai usando questo metodo per testare i discendenti.

Il costo dell'utilizzo dei getter è praticamente pari a zero, quindi non esiste un vero motivo per non usarli. C'è?

    
risposta data 24.10.2013 - 15:48
fonte
7

Indipendentemente dal fatto che tu usi getter o accesso al campo, qualsiasi revisore esperto troverà il problema nel tuo progetto e lamentati che i tuoi oggetti espongono i dati anziché il loro comportamento.

Notare che fare appello a "protetto" non aiuterà, perché lo scopo dell'ereditarietà è di permettere alle sottoclassi di regolare / ottimizzare comportamento del genitore ( LSP ), non per giustificare l'uso indiscriminato dei dati dei genitori. Come Bertrand Meyer lo mette,

Neither the Open-Closed principle nor redefinition in inheritance is a way to address design flaws... (The only potential exception for this rule is the case of flawed software which you are not at liberty to modify.)

Il "raggiro è malvagio" il ragionamento si applica indipendentemente dal fatto che si scriva get esplicitamente o lo si maschera dietro il accesso al campo.

see this article or this article by Alan Holub...

You shouldn't use accessor methods (getters and setters) unless absolutely necessary because these methods expose information about how a class is implemented and as a consequence make your code harder to maintain. Sometimes get/set methods are unavoidable, but an experienced OO designer could probably eliminate 99 percent of the accessors currently in your code without much difficulty.

Getter/setter methods often make their way in code because the coder was thinking procedurally. The best way to break out of that procedural mindset is to think in terms of a conversation between objects that have well-defined responsibilities...

Se sei seriamente preoccupato per il problema, la prima cosa da considerare è la riprogettazione del codice per eliminare entrambi i getter e l'accesso al campo non privato , invece di giocare a giochi mentali infruttuosi scegliendo in che direzione è meno inappropriato .

Vale la pena sottolineare ancora una volta, nascondere il fastidioso disegno dietro la cortina fumogena "protetta" non farà scomparire il problema - l'ereditarietà non giustifica trucchi del genere. Parafrasando la tua domanda, sforzati di progettare le cose in un modo che eviti di avere l'ereditarietà delle classi di interagire con quelle variabili affatto, né attraverso i getter o tramite l'accesso al campo. Dillo, non chiedere :

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.

Passare il tempo e gli sforzi per decidere in che modo preferire ottenere informazioni, contro il principio classico che raccomanda di evitare del tutto, ora che suona come un eccessivo .

    
risposta data 06.11.2013 - 14:21
fonte
1

Nel caso di un'implementazione di classe immutabile, rendere le tue variabili interne protette potrebbe rompere il contratto che hai impostato, nel qual caso i getter protetti non sarebbero eccessivi e necessari (anche se dovresti restituire copie della tua variabile, non un puntatore ad esso).

Nelle classi mutabili, continuo a preferire i getter / setter per garantire l'accesso diretto alle mie variabili interne. Questo assicura che puoi cambiare il modo in cui gestisci le variabili interne come desideri, senza temere di violare alcun codice client. Ad esempio, immagina di avere una classe Java come segue:

public abstract class SomeClass {
    protected int[] someVariable;

    // Rest of implementation
}

La classe client che estende SomeClass accederà direttamente a someVariable , manipolandolo come meglio ritengono opportuno. Ora, questo può creare tutti i tipi di problemi se queste classi non lasciano someVariable in uno stato accettabile. Inoltre, se decidi in una versione successiva di modificare la definizione di SomeClass per utilizzare un List<Integers> invece di un array, interromperai la compatibilità con il codice esistente, che prevede SomeClass di avere un array interno di int s, non un elenco di int s.

L'utilizzo di getter protetti in questo caso consente di apportare questa modifica senza violare alcun contratto prestabilito.

public abstract class SomeClass {
    List<Integer> someVariable;

    protected int[] getSomeVariable () {
        // Return int[] version of someVariable
    }

    // Rest of implementation
}
    
risposta data 24.10.2013 - 21:42
fonte