Evitare getter e setter, visualizzando le informazioni dell'utente


10

sfondo

Sto leggendo il "Clean Code book" e, in parallelo, sto lavorando su oggetti calistenici Kata come il conto del banchiere, e sono bloccato su quella regola:

La nona regola degli oggetti calistenici è che non usiamo getter o setter.

Sembra abbastanza divertente e sono d'accordo con questo principio. Inoltre, a pagina 98-99 di Clean Code, l'autore spiega che i getter / setter rompono l'astrazione e che non dobbiamo chiedere al nostro oggetto, ma dobbiamo dirlo al nostro oggetto.

Questo ha perfettamente senso nella mia mente e sono pienamente d'accordo con questo principio. Il problema si presenta in pratica.

Contesto

Ad esempio, sto avendo un'applicazione in cui devo elencare alcuni utenti e visualizzare i dettagli dell'utente.

Il mio utente è composto da:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

Problema

Come posso fare o cosa posso fare per evitare i getter quando ho solo bisogno di visualizzare una semplice informazione ( e devo confermare che non ho bisogno di ulteriori operazioni su quel particolare campo ) per visualizzare il valore Nome in un semplice ( casuale) supporto output?

Cosa mi viene in mente

Una soluzione è fare:

user.getName().getFirstName().getStringValue()

Il che è totalmente terribile, infrangendo molte regole di oggetti calistenici e infrangendo la Legge Demetra.

Un altro sarebbe qualcosa del tipo:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

Ma non mi sento a mio agio con questa soluzione, che sembra essere solo un "accessorio di ordine superiore" come bypassare il getter / setter standard con un metodo che mira solo ad abbinare la legge di Demetra ...

Qualche idea ?

Risposte:


17

L'idea sbagliata comune sull'idea di evitare getter e setter è di evitarli ovunque, il che è impossibile quando si arriva alla superficie della propria architettura interagendo con l'utente.

È necessario evitare l'uso di getter e setter nella parte della logica aziendale dell'applicazione, in cui gli oggetti devono essere protetti utilizzando aggregati che forniscono il contesto e i metodi devono fungere da comandi.

Per evitare getter e setter, è possibile progettare una soluzione simile alla programmazione reattiva , implementando il sistema di reporting attraverso entità osservabili, ma ciò complica enormemente l'architettura e non ha senso nel livello CRUD dell'applicazione, anche se il design è davvero buono per le interfacce utente.

La possibilità di considerare l'utilizzo di getter / setter dipende interamente dalla parte dell'applicazione a cui si sta attualmente lavorando. Se la tua preoccupazione è che l'interfaccia utente che utilizza i getter è completamente a posto, per la logica aziendale, in cui eseguiresti una parte di un codice basato su un valore recuperato attraverso un getter, non così tanto (questo grida che la logica avrebbe dovuto essere effettivamente incapsulata all'interno la classe su cui stai chiamando il getter).

Inoltre, la legge di demeter non riguarda il conteggio dei punti, ma semplicemente lo smantellamento di una classe che fornisce il contesto usando getter sulla classe per ottenere i suoi componenti ai quali non si dovrebbe avere accesso da soli.

Se ritieni che la tua interfaccia utente stia andando troppo in profondità nei tuoi modelli di business, puoi pensare di introdurre modelli di visualizzazione nel tuo sistema, essendo responsabile della trasformazione di parti specifiche dei modelli in rappresentazioni visive.


Ok, penso a quel suggerimento proprio come un mappatore tra la mia entità di dominio, a un DTO personalizzato per il mio livello di presentazione che avrebbe alcuni accessori giusto?
mfrachet,

@Margin Praticamente, sì.
Andy,

Tutta questa roba a cascata suona davvero bene e senza intoppi, grazie per la risposta;)
mfrachet

2

Una direzione da pensare sarebbe quella di fornire una funzione membro di formattazione stringa generica, piuttosto che fornire accesso ai dati grezzi. Qualcosa come questo:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

Vedete, con questo approccio, non siete limitati a fornire i dati completi così come sono, potete fornire mezzi per trasformare i dati in modi convenienti e significativi. Ad esempio, potresti aver bisogno di giocare brutti scherzi a caso:

String accountName = user.formatDescription("$(firstname).$(lastname)");

Potresti anche definire alcuni formati comunemente usati, forse complessi, una volta, per esempio, per esempio

String fullAddress = user.formatDescription(User.kAddressFormat);

Il bello di questo approccio è che mantiene le singole stringhe interne alla Userclasse, fornendo in realtà significativamente più funzionalità al codice chiamante. Tuttavia, il rovescio della medaglia è che è necessario implementare il meccanismo di template all'interno del formatDescription()quale saranno presenti alcune righe di codice.

In quanto tale, questo potrebbe essere un eccesso eccessivo: non dimenticare mai che i principi di programmazione sono solo linee guida. E ogni volta che seguire un altro principio è in violazione del principio KISS, è probabilmente meglio farlo semplicemente. Quindi, a meno che tu non abbia almeno qualche bisogno di un tale membro di formattazione, non mi preoccuperei di implementarlo per motivi di semplicità, usando l'approccio basato sull'accessor.


5
Questa, tuttavia, mi sembra una violazione dell'SRP. È davvero responsabilità di un Useroggetto analizzare e compilare / interpretare un linguaggio esemplare?
Jörg W Mittag

@ JörgWMittag Non necessariamente. Come ho detto, il principio KISS ha la precedenza. E non ho detto da nessuna parte che la Userclasse deve implementare questa funzionalità stessa. Se avessi solo due classi che avevano bisogno di tale funzionalità, potresti scommettere su di me prendendo in considerazione il meccanismo di sostituzione del modello nella sua stessa classe. Questo vuole essere un esempio di come è possibile sollevare l'astrazione che Userfornisce a un livello in cui è in realtà più di un semplice contenitore di dati. E credo che questo sia evitare gli accessor: fare OOP invece di gestire un sacco di messaggi struct.
cmaster - ripristina monica il

Sai che KISS è totalmente soggettivo e obiettivo SRP? KISS non ti dice nulla su COSA fare. E ciò che è "semplice" per te potrebbe non essere "semplice" per me. Vedo una vera differenza nella qualità se litigo con KISS o SRP.
oopexpert,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.