"Evitare il problema yo-yo" è un motivo valido per consentire l '"ossessione primitiva"?


42

Secondo Quando l'ossessione primitiva non è un odore di codice? , Dovrei creare un oggetto ZipCode per rappresentare un codice postale anziché un oggetto String.

Tuttavia, nella mia esperienza, preferisco vedere

public class Address{
    public String zipCode;
}

invece di

public class Address{
    public ZipCode zipCode;
}

perché penso che quest'ultimo richieda che io passi alla classe ZipCode per capire il programma.

E credo di dover passare da una classe all'altra per vedere la definizione se tutti i campi di dati primitivi sono stati sostituiti da una classe, che sembra soffrire del problema yo-yo (un anti-pattern).

Quindi vorrei spostare i metodi ZipCode in una nuova classe, ad esempio:

Vecchio:

public class ZipCode{
    public boolean validate(String zipCode){
    }
}

Nuovo:

public class ZipCodeHelper{
    public static boolean validate(String zipCode){
    }
}

in modo che solo chi deve convalidare il codice postale dipenda dalla classe ZipCodeHelper. E ho trovato un altro "vantaggio" di mantenere l'ossessione primitiva: mantiene la classe simile alla sua forma serializzata, se presente, ad esempio: una tabella di indirizzi con colonna stringa zipCode.

La mia domanda è: "evitare il problema yo-yo" (spostarsi tra le definizioni di classe) è un motivo valido per consentire l '"ossessione primitiva"?


9
@ jpmc26 Allora rimarrai scioccato nel vedere quanto sia complesso il nostro oggetto codice postale - senza dire che è giusto, ma esiste
Jared Goguen

9
@ jpmc26, non riesco a vedere come passi da "complesso" a "mal progettato". Il codice complesso è spesso il risultato di un semplice codice che entra in contatto con la complessità del mondo reale piuttosto che con il mondo ideale che potremmo desiderare esistesse. "Tornando a quella funzione di due pagine. Sì, lo so, è solo una semplice funzione per visualizzare una finestra, ma è cresciuta con piccoli peli e cose su di essa e nessuno sa perché. Beh, ti dirò perché: quelli sono bug correzioni ".
Kyralessa

19
@ jpmc26 - il punto di avvolgere oggetti come ZipCode è la sicurezza dei tipi. Il codice postale non è una stringa, è un codice postale. Se una funzione prevede un codice postale, dovresti essere in grado di passare solo un codice postale, non una stringa.
Davor Ždralo

4
Questo sembra altamente specifico della lingua, lingue diverse fanno cose diverse qui. @ DavorŽdralo Nello stesso tratto dovremmo anche aggiungere molti tipi numerici. "solo numeri interi positivi", "solo numeri pari" potrebbero essere tutti tipi.
Paul23

6
@ paul23 Sì davvero, e il motivo principale per cui non li abbiamo è che molte lingue non supportano modi eleganti per definirli. È perfettamente ragionevole definire "età" come un tipo diverso da "temperatura in gradi centigradi", se solo così che "userAge == currentTemperature" viene rilevata come una sciocchezza.
IMSoP

Risposte:


116

Il presupposto è che non è necessario accedere alla classe ZipCode per comprendere la classe Address. Se ZipCode è ben progettato, dovrebbe essere ovvio ciò che fa semplicemente leggendo la classe Address.

I programmi non vengono letti end-to-end - in genere i programmi sono troppo complessi per renderlo possibile. Non puoi tenere in mente tutto il codice di un programma contemporaneamente. Quindi usiamo astrazioni e incapsulamenti per "dividere" il programma in unità significative, in modo da poter guardare una parte del programma (diciamo la classe Address) senza dover leggere tutto il codice da cui dipende.

Ad esempio, sono sicuro che non ti piace leggere il codice sorgente per String ogni volta che incontri String nel codice.

Rinominare la classe da ZipCode a ZipCodeHelper suggerisce che ora ci sono due concetti separati: un codice postale e un helper di codice postale. Quindi due volte più complesso. E ora il sistema dei tipi non può aiutarti a distinguere tra una stringa arbitraria e un codice postale valido poiché hanno lo stesso tipo. Qui è dove "ossessione" è appropriata: stai suggerendo un'alternativa più complessa e meno sicura solo perché vuoi evitare un semplice tipo di wrapper attorno a una primitiva.

L'uso di una primitiva è IMHO giustificato nei casi in cui non esiste alcuna convalida o altra logica a seconda di questo particolare tipo. Ma non appena aggiungi una logica, è molto più semplice se questa logica è incapsulata con il tipo.

Per quanto riguarda la serializzazione, penso che sembri una limitazione nel framework in uso. Sicuramente dovresti essere in grado di serializzare un ZipCode su una stringa o mapparlo su una colonna in un database.


2
Sono d'accordo con la parte "unità significative" (main-), ma non tanto che un codice postale e la convalida del codice postale sono lo stesso concetto. ZipCodeHelper(che preferirei chiamare ZipCodeValidator) potrebbe benissimo stabilire una connessione a un servizio Web per fare il suo lavoro. Ciò non farebbe parte della singola responsabilità "conservare i dati del codice postale". Fare in modo che il sistema di tipo non consenta codici postali non validi può essere comunque ottenuto rendendo il ZipCodecostruttore l'equivalente del pacchetto Java-privato e chiamando quello con un ZipCodeFactoryche chiama sempre il validatore.
R. Schmitz,

16
@ R.Schmitz: Non è ciò che significa "responsabilità" nel senso del principio della responsabilità singola. Ma in ogni caso, dovresti ovviamente usare tutte le classi di cui hai bisogno fintanto che incapsuli il codice postale e la sua convalida. L'OP suggerisce un aiuto invece di incapsulare il codice postale, il che è una cattiva idea.
JacquesB,

1
Voglio essere rispettosamente in disaccordo. SRP significa che una classe dovrebbe avere "uno, e solo uno, motivo per essere cambiato" (cambia in "in cosa consiste un codice postale" rispetto a "come viene convalidato"). Questo caso specifico è ulteriormente approfondito nel libro Clean Code : " Gli oggetti nascondono i loro dati dietro le astrazioni ed espongono le funzioni che operano su quei dati. La struttura dei dati espone i loro dati e non ha funzioni significative " - ZipCodesarebbe una "struttura di dati" e ZipCodeHelperun "oggetto". In ogni caso, penso che siamo d'accordo sul fatto che non dovremmo passare le connessioni web al costruttore ZipCode.
R. Schmitz,

9
L'uso di una primitiva è IMHO giustificato nei casi in cui non esiste alcuna convalida o altra logica a seconda di questo particolare tipo. => Non sono d'accordo. Anche se tutti i valori sono validi, preferirei comunque trasmettere la semantica alla lingua piuttosto che usare i primitivi. Se una funzione può essere chiamata su un tipo primitivo che non ha senso per il suo attuale utilizzo semantico, allora non dovrebbe essere un tipo primitivo, dovrebbe essere un tipo corretto con solo le funzioni sensibili definite. (Ad esempio, l'utilizzo intcome ID consente di moltiplicare un ID per un ID ...)
Matthieu M.

@ R.Schmitz Penso che i CAP siano un cattivo esempio per la distinzione che stai facendo. Qualcosa che cambia spesso potrebbe essere un candidato per separare Fooe FooValidatorclassi. Abbiamo potuto avere una ZipCodeclasse che convalida il formato e una ZipCodeValidatorche colpisce qualche servizio Web per verificare che un formattato correttamente ZipCodeè in realtà corrente. Sappiamo che i codici postali cambiano. Ma praticamente, avremo un elenco di codici ZIP validi incapsulati in ZipCode, o in alcuni database locali.
No U

55

Se puoi fare:

new ZipCode("totally invalid zip code");

E il costruttore per ZipCode fa:

ZipCodeHelper.validate("totally invalid zip code");

Quindi hai rotto l'incapsulamento e aggiunto una dipendenza piuttosto stupida alla classe ZipCode. Se il costruttore non chiama, ZipCodeHelper.validate(...)allora hai una logica isolata nella sua isola senza applicarla effettivamente. È possibile creare codici postali non validi.

Il validatemetodo dovrebbe essere un metodo statico sulla classe ZipCode. Ora la conoscenza di un codice postale "valido" è raggruppata insieme alla classe ZipCode. Dato che i tuoi esempi di codice sembrano Java, il costruttore di ZipCode dovrebbe generare un'eccezione se viene fornito un formato errato:

public class ZipCode {
    private String zipCode;

    public ZipCode(string zipCode) {
        if (!validate(zipCode))
            throw new IllegalFormatException("Invalid zip code");

        this.zipCode = zipCode;
    }

    public static bool validate(String zipCode) {
        // logic to check format
    }

    @Override
    public String toString() {
        return zipCode;
    }
}

Il costruttore controlla il formato e genera un'eccezione, impedendo così la creazione di codici postali non validi e il validatemetodo statico è disponibile per altri codici, quindi la logica di controllo del formato è incapsulata nella classe ZipCode.

Non esiste "yo-yo" in questa variante della classe ZipCode. Si chiama semplicemente corretta programmazione orientata agli oggetti.


Ignoreremo anche qui l'internazionalizzazione, che potrebbe richiedere un'altra classe chiamata ZipCodeFormat o PostalService (ad esempio PostalService.isValidPostalCode (...), PostalService.parsePostalCode (...), ecc.).


28
Nota: il vantaggio principale con l'approccio di @Greg Burkhardt qui è che se qualcuno ti dà un oggetto ZipCode, puoi fidarti che contiene una stringa valida senza doverla controllare di nuovo, poiché il suo tipo e il fatto che sia stata costruita con successo ti dà quella garanzia. Se invece hai passato stringhe in giro, potresti sentire la necessità di "asserire validate (zipCode)" in vari punti del tuo codice solo per essere sicuro di avere un codice postale valido, ma con un oggetto ZipCode costruito con successo, puoi fidarti che i suoi contenuti sono validi senza doverli controllare di nuovo.
Qualcuno il

3
@ R.Schmitz: il ZipCode.validatemetodo è il controllo preliminare che può essere eseguito prima di invocare un costruttore che genera un'eccezione.
Greg Burghardt,

10
@ R.Schmitz: se sei preoccupato per un'eccezione irritante, un approccio alternativo alla costruzione è quello di rendere privato il costruttore ZipCode e fornire una funzione pubblica statica di fabbrica (Zipcode.create?) Che esegue la convalida dei parametri passati, restituisce null se non ha esito positivo e costruisce altrimenti un oggetto ZipCode e lo restituisce. Il chiamante dovrà sempre verificare un valore di ritorno nullo, ovviamente. D'altra parte, se hai l'abitudine, ad esempio, di convalidare sempre (regex? Validate? Ecc.) Prima di costruire un ZipCode, l'eccezione potrebbe non essere così fastidiosa nella pratica.
Qualcuno il

11
È anche possibile una funzione di fabbrica che restituisce un <ZipCode> opzionale. Quindi il chiamante non ha altra scelta che gestire esplicitamente il possibile fallimento della funzione di fabbrica. Indipendentemente da ciò, in entrambi i casi, l'errore verrà scoperto da qualche parte vicino a dove è stato creato piuttosto che probabilmente molto più tardi, dal codice client lontano dal problema originale.
Qualcuno il

6
Non è possibile convalidare ZipCode in modo indipendente, quindi non farlo. È necessario l'oggetto Country per cercare le regole di convalida ZipCode / PostCode.
Giosuè il

11

Se combatti molto con questa domanda, forse la lingua che usi non è lo strumento giusto per il lavoro? Questo tipo di "primitive tipizzate dal dominio" sono banalmente facili da esprimere, ad esempio in F #.

Lì potresti, ad esempio, scrivere:

type ZipCode = ZipCode of string
type Town = Town of string

type Adress = {
  zipCode: ZipCode
  town: Town
  //etc
}

let adress1 = {
  zipCode = ZipCode "90210"
  town = Town "Beverly Hills"
}

let faultyAdress = {
  zipCode = "12345"  // <-Compiler error
  town = adress1.zipCode // <- Compiler error
}

Questo è davvero utile per evitare errori comuni, come il confronto di ID di entità diverse. E poiché queste primitive tipizzate sono molto più leggere di una classe C # o Java, finirai per usarle.


Interessante: come sarebbe se si volesse imporre la convalida di ZipCode?
Hulk, il

4
@Hulk Puoi scrivere OO-style in F # e trasformare i tipi in classi. Tuttavia, preferisco lo stile funzionale, dichiarando il tipo con tipo ZipCode = Private ZipCode della stringa e aggiungendo un modulo ZipCode con una funzione di creazione. Ci sono alcuni esempi qui: gist.github.com/swlaschin/54cfff886669ccab895a
Guran

@ Bent-Tranberg Grazie per la modifica. Hai ragione, un'abbreviazione di tipo semplice non fornisce la sicurezza del tipo di tempo di compilazione.
Guran,

Se ti è stato inviato il mio primo commento, che ho eliminato, la ragione è stata che ho frainteso la tua fonte. Non l'ho letto abbastanza attentamente. Quando ho provato a compilarlo, ho finalmente capito che stavi davvero provando a dimostrarlo esattamente, quindi ho deciso di modificarlo per farlo bene.
Bent Tranberg,

Si. La mia fonte originale era valida, purtroppo includendo l'esempio SUPPOSTO non valido. Doh! Dovrebbe essere appena collegato a Wlaschin invece di digitare il codice me stesso :) fsharpforfunandprofit.com/posts/…
Guran

6

La risposta dipende interamente da ciò che vuoi effettivamente fare con i codici postali. Ecco due possibilità estreme:

(1) Tutti gli indirizzi sono garantiti in un singolo paese. Nessuna eccezione. (Ad esempio nessun cliente straniero o nessun dipendente il cui indirizzo privato è all'estero mentre lavorano per un cliente straniero.) Questo paese ha codici postali e non ci si può aspettare che siano mai seriamente problematici (cioè non richiedono input in formato libero come "attualmente D4B 6N2, ma questo cambia ogni 2 settimane"). I codici postali vengono utilizzati non solo per l'indirizzamento, ma per la convalida delle informazioni di pagamento o per scopi simili. - In queste circostanze, una classe di codice postale ha molto senso.

(2) Gli indirizzi possono essere presenti in quasi tutti i paesi, pertanto sono rilevanti dozzine o centinaia di schemi di indirizzamento con o senza codici di avviamento postale (e con migliaia di strane eccezioni e casi speciali). Un codice "ZIP" è davvero richiesto solo per ricordare alle persone dei paesi in cui i codici postali sono usati per non dimenticare di fornire il loro. Gli indirizzi vengono utilizzati solo in modo tale che se qualcuno perde l'accesso al proprio account e può dimostrare il proprio nome e indirizzo, l'accesso verrà ripristinato. - In queste circostanze, le classi di codice postale per tutti i paesi interessati sarebbero uno sforzo enorme. Fortunatamente non sono affatto necessari.


3

Le altre risposte hanno parlato della modellazione del dominio OO e dell'utilizzo di un tipo più ricco per rappresentare il tuo valore.

Non sono in disaccordo, soprattutto dato il codice di esempio che hai pubblicato.

Ma mi chiedo anche se questo risponda effettivamente al titolo della tua domanda.

Considera il seguente scenario (estratto da un progetto reale a cui sto lavorando):

Hai un'applicazione remota su un dispositivo di campo che comunica con il tuo server centrale. Uno dei campi DB per la voce dispositivo è un codice postale per l'indirizzo a cui si trova il dispositivo campo. Non ti importa del codice postale (o di qualsiasi altra parte dell'indirizzo). Tutte le persone che se ne occupano sono dall'altra parte di un confine HTTP: ti capita di essere l'unica fonte di verità per i dati. Non ha posto nella modellazione del tuo dominio. Basta registrarlo, convalidarlo, archiviarlo e, su richiesta, rimuoverlo in un BLOB JSON per punti altrove.

In questo scenario, fare molto di più che convalidare l'inserimento con un vincolo regex SQL (o il suo equivalente ORM) è probabilmente eccessivo della varietà YAGNI.


6
Il tuo vincolo regex SQL potrebbe essere visualizzato come un tipo qualificato: all'interno del tuo database, il codice postale non è memorizzato come "VarChar" ma "VarChar vincolato da questa regola". In alcuni DBMS, potresti facilmente assegnare a quel tipo + vincolo un nome come "tipo di dominio" riutilizzabile, e siamo di nuovo nel posto consigliato di dare ai dati un tipo significativo. Sono d'accordo con la tua risposta in linea di principio, ma non credo che l'esempio corrisponda; un esempio migliore sarebbe se i tuoi dati sono "dati del sensore non elaborati" e il tipo più significativo è "array di byte" perché non hai idea del significato dei dati.
IMSoP,

@IMSoP punto interessante. Non sono sicuro di essere d'accordo però: potresti convalidare un codice postale di stringa in Java (o in qualsiasi altra lingua) con una regex, ma hai comunque a che fare con esso come una stringa anziché un tipo più ricco. A seconda della logica del dominio, potrebbe essere necessaria un'ulteriore manipolazione (ad esempio garantendo che il codice postale corrisponda allo stato, qualcosa che sarebbe difficile / impossibile da convalidare con regex).
Jared Smith,

Si potrebbe , ma non appena lo fate, state attribuendo che alcuni comportamenti specifici del dominio, e questo è esattamente ciò che gli articoli citati hanno da dire dovrebbe portare alla creazione di un tipo personalizzato. La domanda non è se puoi farlo in uno o l'altro stile, ma se dovresti , supponendo che il tuo linguaggio di programmazione ti dia la scelta.
IMSoP,

È possibile modellare una cosa come a RegexValidatedString, contenente la stringa stessa e la regex utilizzata per convalidarla. Ma a meno che ogni istanza non abbia una regex unica (che è possibile ma improbabile) questo sembra un po 'sciocco e dispendioso di memoria (e possibilmente tempo di compilazione regex). Quindi o metti il ​​regex in una tabella separata e lasci dietro una chiave di ricerca in ogni istanza per trovarlo (che è probabilmente peggio a causa dell'irregolarità) o trovi un modo per memorizzarlo una volta per ogni tipo comune di valore che condivide quella regola - - per esempio. un campo statico su un tipo di dominio o metodo equivalente, come diceva IMSoP.
Miral

2

L' ZipCodeastrazione potrebbe avere senso solo se anche la tua Addressclasse non avesse una TownNameproprietà. Altrimenti, hai una mezza astrazione: il codice postale designa la città, ma questi due bit di informazioni correlate si trovano in classi diverse. Non ha molto senso.

Tuttavia, anche allora, non è ancora un'applicazione corretta (o piuttosto una soluzione a) ossessione primitiva; che, a quanto ho capito, si concentra principalmente su due cose:

  1. Usare le primitive come valori di input (o persino output) di un metodo, specialmente quando è necessaria una raccolta di primitive.
  2. Classi che sviluppano proprietà extra nel tempo senza mai riconsiderare se alcune di queste debbano essere raggruppate in una sottoclasse.

Il tuo caso non è nessuno dei due. Un indirizzo è un concetto ben definito con proprietà chiaramente necessarie (via, numero, CAP, città, stato, nazione, ...). Non vi è alcun motivo per dividere questi dati in quanto ha un'unica responsabilità: designare una posizione sulla Terra. Un indirizzo richiede tutti questi campi per essere significativo. La metà di un indirizzo è inutile.

Questo è il modo in cui sai che non è necessario suddividere ulteriormente: la scomposizione ulteriore ridurrebbe l'intenzione funzionale della Addressclasse. Allo stesso modo, non hai bisogno di una Namesottoclasse per essere usata nella Personclasse, a meno che Name(senza una persona collegata) sia un concetto significativo nel tuo dominio. Che non è (di solito). I nomi sono usati per identificare le persone, di solito non hanno valore da soli.


1
@RikD: Dalla risposta: "non hai bisogno di una Namesottoclasse per essere usata nella Personclasse, a meno che Nome (senza una persona collegata) sia un concetto significativo nel tuo dominio ". Quando disponi di una convalida personalizzata per i nomi, il nome è diventato un concetto significativo nel tuo dominio; che ho esplicitamente indicato come caso d'uso valido per l'utilizzo di un sottotipo. In secondo luogo, per la convalida del codice postale, stai introducendo ipotesi aggiuntive, come i codici postali che devono seguire il formato di un determinato paese. Stai affrontando un argomento che è molto più ampio dell'intento della domanda di OP.
Flater,

5
" Un indirizzo è un concetto ben definito con proprietà chiaramente necessarie (via, numero, CAP, città, stato, paese). " - Beh, questo è semplicemente sbagliato. Per un buon modo per affrontare questo, guarda il modulo di indirizzo di Amazon.
R. Schmitz,

4
@Flater Beh, non ti biasimerò per non aver letto l'elenco completo delle falsità, perché è piuttosto lungo, ma contiene letteralmente "Gli indirizzi avranno una strada", "Un indirizzo richiede sia una città che un paese", "Un indirizzo avrà un codice postale "ecc., il che è contrario a quanto dice la frase citata.
R. Schmitz,

8
@GregBurghardt "Il codice postale presuppone il servizio postale degli Stati Uniti e puoi derivare il nome della città dal codice postale. Le città possono avere più codici postali, ma ogni codice postale è legato solo a 1 città." Questo non è corretto in generale. Ho un codice postale che viene utilizzato principalmente per una città vicina ma la mia residenza non si trova lì. I codici postali non si allineano sempre ai confini governativi. Ad esempio 42223 contiene contee di TN e KY .
JimmyJames,

2
In Austria esiste una valle accessibile solo dalla Germania ( en.wikipedia.org/wiki/Kleinwalsertal ). Esiste un trattato speciale per questa regione che, tra le altre cose, prevede anche che gli indirizzi in quest'area abbiano codici postali sia austriaci che tedeschi. Quindi, in generale, non puoi nemmeno supporre che un indirizzo abbia un solo codice postale valido;)
Hulk

1

Dall'articolo:

Più in generale, il problema yo-yo può anche riferirsi a qualsiasi situazione in cui una persona deve continuare a alternare tra diverse fonti di informazioni per comprendere un concetto.

Il codice sorgente viene letto molto più spesso di quanto sia scritto. Pertanto, il problema yo-yo, di dover passare da un file all'altro è una preoccupazione.

Tuttavia, no , il problema yo-yo sembra molto più rilevante quando si ha a che fare con moduli o classi profondamente interdipendenti (che si richiamano tra loro). Questi sono un tipo speciale di incubo da leggere, ed è probabilmente ciò che il direttore del problema yo-yo aveva in mente.

Tuttavia - , evitare troppi strati di astrazione è importante!

Tutte le astrazioni non banali, in una certa misura, presentano delle perdite. - la Legge delle Astrazioni Perdenti.

Ad esempio, non sono d'accordo con l'ipotesi fatta nella risposta di mmmaaa secondo cui " non è necessario yo-yo per [(visitare)] la classe ZipCode per comprendere la classe Address". La mia esperienza è stata che lo fai - almeno le prime volte che leggi il codice. Tuttavia, come altri hanno notato, ci sono momenti in cui una ZipCodeclasse è appropriata.

YAGNI (Ya A't Not Gonna Need It) è un modello migliore da seguire per evitare il codice Lasagna (codice con troppi livelli) - astrazioni, come tipi e classi, sono lì per aiutare il programmatore e non dovrebbero essere usate a meno che non lo siano un aiuto.

Personalmente mi propongo di "salvare righe di codice" (e ovviamente i relativi "salva file / moduli / classi", ecc.). Sono fiducioso che ci siano alcuni che potrebbero applicare a me l'epiteto di "ossessionato primitivo" - trovo più importante avere un codice di cui sia facile ragionare piuttosto che preoccuparsi di etichette, schemi e anti-schemi. La scelta corretta di quando creare una funzione, un modulo / file / classe o inserire una funzione in una posizione comune è molto situazionale. Mi riferisco all'incirca a 3-100 funzioni di linea, 80-500 file di riga e "1, 2, n" per il codice libreria riutilizzabile ( SLOC - esclusi commenti o targhetta della caldaia ; in genere desidero almeno 1 SLOC minimo aggiuntivo per riga di obbligatorio boilerplate).

La maggior parte dei modelli positivi sono nati dagli sviluppatori facendo esattamente questo, quando ne avevano bisogno . È molto più importante imparare a scrivere codice leggibile che cercare di applicare schemi senza lo stesso problema da risolvere. Qualsiasi buon sviluppatore può implementare il modello di fabbrica senza averlo mai visto prima nel caso insolito in cui si adatta perfettamente al loro problema. Ho usato il modello di fabbrica, il modello di osservatore e probabilmente anche centinaia, senza conoscerne il nome (ovvero, esiste un "modello di assegnazione variabile"?). Per un esperimento divertente - vedi quanti schemi GoF sono integrati nel linguaggio JS - Ho smesso di contare dopo circa 12-15 nel 2009. Il modello Factory è semplice come restituire un oggetto da un costruttore JS, ad esempio - non è necessario una WidgetFactory.

Quindi - , a volte ZipCode è una buona classe. Tuttavia, no , il problema yo-yo non è strettamente pertinente.


0

Il problema yo-yo è rilevante solo se devi capovolgere avanti e indietro. Ciò è causato da una o due cose (a volte entrambe):

  1. Cattiva denominazione. ZipCode sembra a posto, ZoneImprovementPlanCode richiederà uno sguardo alla maggior parte delle persone (e i pochi che non ne saranno colpiti).
  2. Accoppiamento inappropriato. Supponiamo che la classe ZipCode abbia una ricerca per prefisso. Potresti pensare che abbia senso perché è utile, ma non è realmente correlato allo ZipCode e infilarlo in esso significa che ora le persone non sanno dove andare per le cose.

Se puoi guardare il nome e avere un'idea ragionevole di ciò che fa, e i metodi e le proprietà fanno cose ragionevolmente ovvie, non devi andare a guardare il codice, puoi semplicemente usarlo. Questo è il punto centrale delle classi in primo luogo: sono pezzi di codice modulari che possono essere utilizzati e sviluppati in modo isolato. Se devi vedere qualcosa di diverso dall'API per la classe per vedere cosa fa, è nella migliore delle ipotesi un errore parziale.


-1

Ricorda, non esiste un proiettile d'argento. Se stai scrivendo un'app estremamente semplice che deve essere sottoposta a scansione veloce, una semplice stringa potrebbe fare il lavoro. Tuttavia, nel 98% delle volte, un oggetto valore come descritto da Eric Evans in DDD sarebbe la soluzione perfetta. Puoi facilmente vedere tutti i vantaggi offerti dagli oggetti Value leggendo in giro.

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.