Getters and Setters un esempio poco chiaro

2

So che i gettoni e i setter autocratici sono considerati cattivi in quanto tendono a rompere l'incapsulamento dell'oggetto. Spostano anche il lavoro che avrebbe dovuto essere svolto all'interno dell'oggetto all'esterno.

Allen Holub è un grande sostenitore di evitarli. In una delle sue presentazioni dà questo esempio come cattivo design:

QuilaconversionedivalutaavvienealdifuoridellaclasseMoneyesidiffondeattraversol'applicazioneovunquesianecessarialaconversione.

Comeunacorrezioneintroducequesto:

Per me è logico che un oggetto Money ora usi l'oggetto Currency e che gli aritmetici Money vengano eseguiti all'interno della classe Money, ma questa riga m=currency.convertToYourCurrency(m) non capisco.

In che modo il metodo di valuta public Money convertToYourCurrency(Money money); sa qual è la valuta dell'argomento? Utilizzerà un getter? Se delega a Money per la conversione, perché preoccuparsi di chiamarlo da Money per cominciare?

Il signor Holub ha fatto un errore di battitura sul suo vetrino o mi manca qualcosa di ovvio?

Link alla classe: link questo è da ~ 44: 22

    
posta Weltschmerz 05.12.2014 - 23:42
fonte

3 risposte

4

L'esempio è un po 'incasinato, e mi sembra che non sia stato pensato.

Le valute non sono come le misurazioni scientifiche, non è necessario convertirle implicitamente su richiesta. Il valore di una valuta cambierà nel giorno. Devi davvero convertire solo tra le valute con l'autorizzazione esplicita degli utenti finali, certamente non implicitamente ovunque.

La classe tiene i soldi come un doppio. NON FARLO MAI. Vedi Ciò che ogni scienziato informatico dovrebbe sapere sul punto mobile . Il denaro dovrebbe sempre essere tenuto in un tipo integrale o decimale. Se usi il doppio, riceverai errori di arrotondamento e le persone si arrabbieranno molto se raddoppi il loro denaro.

Allo stato attuale, esiste una dipendenza circolare tra denaro e valuta. Il denaro contiene una valuta, ma la valuta funziona anche con il denaro. Questo non è necessariamente sbagliato, ma è sospetto.

La riga in questione:

m=currency.convertToYourCurrency(m)

Hai ragione. Come scritto, richiederebbe un getter o qualcosa di simile. Invece dovrebbe essere

m = m.convertToCurrency(currency)

Dove convertToCurrency è definito

Money convertToCurrency(Currency currency) {
   return new Money(currency, this.currency.convertTo(currency, this.value));
}
    
risposta data 06.12.2014 - 18:44
fonte
1

How will the Currency method public Money convertToYourCurrency(Money money); know what's the argument's currency? Is it going to use a getter?

Si potrebbe dire che, vagamente parlando, la correzione è un modello di visitatore molto semplicistico. L'oggetto Currency è il visitatore che, per definizione del modello, esegue operazioni sugli oggetti Money . Per necessità, il visitatore deve sapere \ avere accesso alla struttura della classe Money in ordine alla sua cosa.

If it delegates to Money for conversion why bother calling it from within Money to begin with?

  • Il punto più grande è l'incapsulamento della conversione di valuta - non facendo il codice client Money fallo.
  • il codice di conversione della valuta è ora riutilizzabile, ogni Money client non deve scrivere il proprio codice di conversione.
  • Principio della singola responsabilità. Si può sostenere che per l'intento progettuale la conversione appartiene alla classe Money .
risposta data 06.12.2014 - 05:58
fonte
1
  • Penso che il suo primo esempio sia un po 'forzato. Se ti sei davvero appassionato a questo sottaceto, probabilmente non hai pensato abbastanza sul problema in primo luogo.

  • I metodi "largerThan" e "addTo" hanno senso perché piuttosto che portare due valori & imponendo un po 'di semantica al di fuori della classe sui valori separati, sta definendo le operazioni sul valore / valuta coppia attraverso le operazioni di classe. E questa è una buona cosa, perché il significato di "largerThan" o "addTo" è incapsulato nella classe. Che è (probabilmente) meglio che lasciare la definizione (e il possibile uso improprio) al client.

  • Ma un approccio alternativo potrebbe essere quello di esprimere tutti i valori monetari in alcune valute canoniche, fare tutte le operazioni in quella valuta comune e poi convertirle nella valuta desiderata all'ultimo minuto.

  • La parte in cui dispensa con il getter in favore di una scrittura su metodo è ... qualcosa. Si potrebbe sostenere che introduce una dipendenza dall'interfaccia di Writer piuttosto che consentire al client di ottenere il valore e farlo con quello che vuole.

L'ho già fatto prima, ma non come pratica generale.

Ad esempio, se dovessi serializzare Money in JSON, introdurrai un metodo "toJSON" che accetta un oggetto "serializzatore"? Ora quella classe ha un'altra dipendenza e amp; una semantica più da gestire. C'è il potenziale per far esplodere l'interfaccia con tutti i diversi punti di integrazione.

... per esempio. per forzare, come si salva un denaro in un database come parte di una transazione?

Quindi sta facendo un punto interessante, e penso che il suo esempio di mettere le operazioni logiche nella classe sia un buon esempio. Ma l'idea di rinunciare completamente ai getter è un interessante refactoring, ma non uno che vedo comunemente.

...

Penso che l'idea principale qui sia che ha un esempio in cui le operazioni sono distribuite su 4 classi: Money, Currency, CurrencyConverter e qualsiasi altro client lo stia mettendo insieme.

Ma in realtà, la classe Currency ha un utilizzo più serrato se elimini CurrencyConverter e muovi la sua logica all'interno di Currency in modo che il tipo di valuta e le operazioni su quel tipo siano raggruppate insieme & nascosto dal mondo esterno.

Quindi tira le operazioni sul valore / valuta coppia e raggruppa quelli all'interno della classe Money, e li nasconde dal mondo esterno.

Quindi IMHO mi sembra più un esempio di miglioramento dell'incapsulamento povero o debole più che una condanna dei getter: qui i getter sono più come accessori per il crimine piuttosto che per le menti. ;)

    
risposta data 06.12.2014 - 01:06
fonte