Separare la maggior parte delle classi nel campo dati solo le classi class e method only (se possibile) è un buono o un anti-pattern?


10

Ad esempio, una classe di solito ha membri e metodi di classe, ad esempio:

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public void printInfo(){
        System.out.println("Name:"+this.name+",weight:"+this.weight);
    }

    public void draw(){
        //some draw code which uses this.image
    }
}

Ma dopo aver letto del principio della responsabilità singola e del principio Open closed, preferisco separare una classe in DTO e una classe di supporto solo con metodi statici, ad esempio:

public class CatData{
    public String name;
    public int weight;
    public Image image;
}

public class CatMethods{
    public static void printInfo(Cat cat){
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat){
        //some draw code which uses cat.image
    }
}

Penso che si adatti al principio della responsabilità singola perché ora la responsabilità di CatData è di conservare solo i dati, non si preoccupa dei metodi (anche per CatMethods). E si adatta anche al principio aperto chiuso perché l'aggiunta di nuovi metodi non ha bisogno di cambiare la classe CatData.

La mia domanda è: è un buono o un anti-schema?


15
Fare qualsiasi cosa alla cieca dappertutto perché hai imparato un nuovo concetto è sempre un anti-schema.
Kayaman,

4
Quale sarebbe il punto delle classi se è sempre meglio avere dati separati dai metodi che li modificano? Sembra una programmazione non orientata agli oggetti (che sicuramente ha il suo posto). Dato che questo è etichettato "orientato agli oggetti", suppongo che desideri utilizzare gli strumenti forniti da OOP?
user1118321

4
Un'altra domanda che dimostra che SRP è così male frainteso che dovrebbe essere vietato. Conservare i dati in diversi settori pubblici non è una responsabilità .
user949300

1
@ user949300, se la classe è responsabile di quei campi, spostarli altrove sull'app avrà ovviamente zero effetti. O per dirla in altro modo, ti sbagli: sono al 100% una responsabilità.
David Arno,

2
@DavidArno e R Schmitz: il contenuto dei campi non è considerato una responsabilità ai fini di SRP. Se così fosse, non ci potrebbe essere OOP, dato che tutto sarebbe un DTO, e quindi classi separate conterrebbero procedure per lavorare sui dati. Una singola responsabilità riguarda un singolo stakeholder . (Anche se questo sembra cambiare leggermente su ogni iterazione del principale)
user949300

Risposte:


10

Hai mostrato due estremi ("tutti i metodi privati ​​e tutti (forse non correlati) in un oggetto" contro "tutto pubblico e nessun metodo all'interno dell'oggetto"). IMHO buona modellazione OO non è nessuno di questi , il punto debole è da qualche parte nel mezzo.

Una cartina di tornasole di quali metodi o logiche appartengono a una classe e di ciò che appartiene all'esterno è di esaminare le dipendenze introdotte dai metodi. I metodi che non introducono dipendenze aggiuntive vanno bene, purché si adattino bene all'astrazione dell'oggetto dato . I metodi che richiedono dipendenze esterne aggiuntive (come una libreria di disegni o una libreria di I / O) raramente sono adatti. Anche se faresti svanire le dipendenze usando l'iniezione delle dipendenze, ci penserei ancora due volte se inserire tali metodi all'interno della classe di dominio è davvero necessario.

Quindi, non dovresti rendere pubblico ogni membro, né devi implementare metodi per ogni operazione su un oggetto all'interno della classe. Ecco un suggerimento alternativo:

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public String getInfo(){
        return "Name:"+this.name+",weight:"+this.weight;
    }
    public Image getImage(){
        return image;
    }
}

Ora l' Catoggetto fornisce una logica sufficiente per consentire al codice circostante di implementare facilmente printInfoe draw, senza esporre tutti gli attributi in pubblico. Il posto giusto per questi due metodi non è probabilmente una classe divina CatMethods(dal momento printInfoche drawsono probabilmente preoccupazioni diverse, quindi penso sia molto improbabile che appartengano alla stessa classe).

Posso immaginare un CatDrawingControllerche implementa draw(e forse usa l'iniezione di dipendenza per ottenere un oggetto Canvas). Posso anche immaginare un'altra classe che implementa alcuni output e usi della console getInfo(quindi printInfopotrebbe diventare obsoleta in questo contesto). Ma per prendere decisioni sensate al riguardo, è necessario conoscere il contesto e come Catverrà effettivamente utilizzata la classe.

Questo è in realtà il modo in cui ho interpretato i critici del modello di dominio anemico di Fowler - per la logica generalmente riutilizzabile (senza dipendenze esterne) le classi di dominio stesse sono un buon posto, quindi dovrebbero essere utilizzate per questo. Ma ciò non significa implementare alcuna logica lì, al contrario.

Nota anche l'esempio sopra lascia ancora spazio per prendere una decisione sulla (im) mutabilità. Se la Catclasse non esporrà alcun setter ed Imageè immutabile, questo progetto consentirà di renderlo Catimmutabile (cosa che l'approccio DTO non farà). Ma se ritieni che l'immutabilità non sia richiesta o non utile per il tuo caso, puoi anche andare in quella direzione.


Attiva felici downvoter, questo diventa noioso. Se hai dei critici, per favore fammi sapere. Sarò felice di chiarire ogni equivoco, se ne hai.
Doc Brown,

Mentre in genere sono d'accordo con la tua risposta ... Sento che getInfo()potrebbe essere fuorviante per qualcuno che fa questa domanda. Mescola sottilmente le responsabilità di presentazione come printInfo()fa, sconfiggendo lo scopo della DrawingControllerclasse
Adriano Repetti,

@AdrianoRepetti Non vedo che stia sconfiggendo lo scopo di DrawingController. Sono d'accordo getInfo()e printInfo()sono nomi orribili. Considera toString()eprintTo(Stream stream)
candied_orange il

@candid non riguarda (solo) il nome ma ciò che fa. Quel codice riguarda solo i dettagli di una presentazione e abbiamo effettivamente sottratto l'output, non il contenuto elaborato e la sua logica.
Adriano Repetti,

@AdrianoRepetti: onestamente, questo è solo un esempio inventato, per adattarsi alla domanda originale e dimostrare il mio punto. In un sistema reale, ci sarà un contesto circostante che consentirà di prendere decisioni su metodi e nomi migliori, ovviamente.
Doc Brown,

6

Risposta in ritardo ma non posso resistere.

X è la maggior parte delle classi in Y buona o un anti-pattern?

Nella maggior parte dei casi, la maggior parte delle regole, applicate senza pensare, andranno per lo più orribilmente sbagliate (compresa questa).

Lascia che ti racconti una storia sulla nascita di un oggetto in mezzo al caos di un codice procedurale in fondo, veloce e sporco, che è accaduto, non per progettazione, ma per disperazione.

Io e il mio stagista stiamo programmando le coppie per creare rapidamente del codice di eliminazione per raschiare una pagina web. Non abbiamo assolutamente motivo di aspettarci che questo codice duri a lungo, quindi stiamo solo sbagliando qualcosa che funziona. Prendiamo l'intera pagina come una stringa e tagliamo le cose di cui abbiamo bisogno nel modo più incredibilmente fragile che tu possa immaginare. Non giudicare. Funziona.

Ora mentre facevo questo ho creato alcuni metodi statici per fare il taglio. Il mio stagista ha creato una classe DTO che era molto simile alla tua CatData.

Quando ho guardato per la prima volta il DTO mi ha infastidito. Gli anni di danni che Java mi ha fatto nel cervello mi hanno fatto indietreggiare nei campi pubblici. Ma stavamo lavorando in C #. C # non ha bisogno di getter e setter prematuri per preservare il diritto di rendere i dati immutabili o incapsulati in un secondo momento. Senza cambiare l'interfaccia puoi aggiungerle quando vuoi. Forse solo per poter impostare un breakpoint. Tutto senza dire nulla ai tuoi clienti. Sì C #. Boo Java.

Quindi ho tenuto la lingua. Ho visto mentre usava i miei metodi statici per inizializzare questa cosa prima di usarla. Ne avevamo circa 14. Era brutto, ma non avevamo motivo di preoccuparci.

Quindi ne avevamo bisogno in altri posti. Ci siamo ritrovati a voler copiare e incollare il codice. 14 linee di inizializzazione lanciate intorno. Stava iniziando a diventare doloroso. Esitò e mi chiese delle idee.

A malincuore ho chiesto "considereresti un oggetto?"

Guardò di nuovo il suo DTO e si incasinò il viso confuso. "È un oggetto".

"Intendo un oggetto reale"

"Huh?"

"Lascia che ti mostri qualcosa. Decidi se è utile"

Ho scelto un nuovo nome e ho rapidamente creato qualcosa che sembrava un po 'così:

public class Cat{
    CatData(string catPage) {
        this.catPage = catPage
    }
    private readonly string catPage;

    public string name() { return chop("name prefix", "name suffix"); }
    public string weight() { return chop("weight prefix", "weight suffix"); }
    public string image() { return chop("image prefix", "image suffix"); }

    private string chop(string prefix, string suffix) {
        int start = catPage.indexOf(prefix) + prefix.Length;
        int end = catPage.indexOf(suffix);
        int length = end - start;
        return catPage.Substring(start, length);
    }
}

Questo non ha fatto nulla che i metodi statici non stessero già facendo. Ma ora avevo risucchiato i 14 metodi statici in una classe in cui potevano essere soli con i dati su cui lavoravano.

Non ho costretto il mio stagista a usarlo. Gliel'ho appena offerto e gli ho lasciato decidere se voleva attenersi ai metodi statici. Tornai a casa pensando che probabilmente si sarebbe attaccato a ciò che già aveva lavorato. Il giorno dopo ho scoperto che lo stava usando in molti posti. Declutrava il resto del codice che era ancora brutto e procedurale, ma questo po 'di complessità era ora nascosto da noi dietro un oggetto. Era un po 'meglio.

Ora certo ogni volta che accedi a questo sta facendo un bel po 'di lavoro. Un DTO è un bel valore memorizzato nella cache veloce. Mi sono preoccupato per questo, ma mi sono reso conto che avrei potuto aggiungere la memorizzazione nella cache se mai ne avessimo avuto bisogno senza toccare il codice di utilizzo. Quindi non mi preoccuperò fino a quando non ci importa.

Sto dicendo che dovresti sempre attenerti agli oggetti OO su quelli DTO? No. Lo splendore di DTO quando devi attraversare un confine che ti impedisce di spostare i metodi. I DTO hanno il loro posto.

Ma anche gli oggetti OO. Scopri come utilizzare entrambi gli strumenti. Scopri quanto costa ciascuno. Impara a decidere il problema, la situazione e il tirocinante. Dogma non è tuo amico qui.


Dal momento che la mia risposta è già ridicolmente lunga, lasciami disabituarti di alcune idee sbagliate con una revisione del tuo codice.

Ad esempio, una classe di solito ha membri e metodi di classe, ad esempio:

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public void printInfo(){
        System.out.println("Name:"+this.name+",weight:"+this.weight);
    }

    public void draw(){
        //some draw code which uses this.image
    }
}

Dov'è il tuo costruttore? Questo non mi sta dimostrando abbastanza per sapere se è utile.

Ma dopo aver letto del principio della responsabilità singola e del principio Open closed, preferisco separare una classe in DTO e una classe di supporto solo con metodi statici, ad esempio:

public class CatData{
    public String name;
    public int weight;
    public Image image;
}

public class CatMethods{
    public static void printInfo(Cat cat){
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat){
        //some draw code which uses cat.image
    }
}

Penso che si adatti al principio della responsabilità singola perché ora la responsabilità di CatData è di conservare solo i dati, non si preoccupa dei metodi (anche per CatMethods).

Puoi fare molte cose sciocche nel nome del principio di responsabilità singola. Potrei sostenere che Cat Strings e Cat ints dovrebbero essere separati. Che i metodi di disegno e le immagini devono avere tutti una propria classe. Che il tuo programma in esecuzione sia una singola responsabilità, quindi dovresti avere solo una classe. : P

Per me, il modo migliore per seguire il singolo principio di responsabilità è trovare una buona astrazione che ti consenta di mettere la complessità in una scatola in modo da poterla nascondere. Se riesci a dargli un buon nome che impedisce alle persone di essere sorprese da ciò che trovano quando guardano dentro, l'hai seguito abbastanza bene. Aspettarsi che imponga più decisioni di quelle che chiedono problemi. Onestamente, entrambi i tuoi elenchi di codici lo fanno, quindi non vedo perché l'SRP sia importante qui.

E si adatta anche al principio aperto chiuso perché l'aggiunta di nuovi metodi non ha bisogno di cambiare la classe CatData.

Beh no. Il principio open close non riguarda l'aggiunta di nuovi metodi. Si tratta di essere in grado di cambiare l'implementazione di vecchi metodi e di non dover modificare nulla. Niente che ti usi e non i tuoi vecchi metodi. Invece scrivi qualche nuovo codice da qualche altra parte. Qualche forma di polimorfismo lo farà bene. Non lo vedo qui.

La mia domanda è: è un buono o un anti-schema?

Bene diavolo come dovrei saperlo? Guarda, farlo in entrambi i modi ha benefici e costi. Quando si separa il codice dai dati, è possibile modificare entrambi senza dover ricompilare l'altro. Forse questo è di fondamentale importanza per te. Forse rende il tuo codice inutilmente complicato.

Se ti fa sentire meglio non sei così lontano da qualcosa che Martin Fowler chiama un oggetto parametro . Non devi solo prendere le primitive nel tuo oggetto.

Quello che vorrei che tu facessi è sviluppare un senso su come fare la tua separazione, o no, in entrambi gli stili di codifica. Perché ci crediate o no non siete costretti a scegliere uno stile. Devi solo vivere con la tua scelta.


2

Ti sei imbattuto in un argomento di dibattito che ha creato discussioni tra gli sviluppatori per oltre un decennio. Nel 2003, Martin Fowler ha coniato la frase "Anemic Domain Model" (ADM) per descrivere questa separazione di dati e funzionalità. Lui - e altri che sono d'accordo con lui - sostengono che "Rich Domain Models" (mescolando dati e funzionalità) è "OO corretto" e che l'approccio ADM è un anti-pattern non OO.

Ci sono sempre stati quelli che hanno respinto questo argomento e quella parte dell'argomento è diventata più forte e più audace negli ultimi anni con l'adozione da parte di più sviluppatori di tecniche di sviluppo funzionale. Tale approccio incoraggia attivamente la separazione dei dati e le preoccupazioni relative alla funzione. I dati dovrebbero essere immutabili il più possibile, quindi l'incapsulamento dello stato mutabile diventa una preoccupazione. Non vi è alcun vantaggio nel collegare direttamente le funzioni a tali dati in tali situazioni. Il fatto che non sia "non OO" o no non ha assolutamente alcun interesse per queste persone.

Indipendentemente dal lato della recinzione su cui ti siedi (mi siedo con fermezza sul lato "Martin Fowler sta parlando di un carico di vecchi tosh" lato BTW), il tuo uso di metodi statici per printInfoed drawè quasi universalmente disapprovato. I metodi statici sono difficili da deridere quando si scrivono test unitari. Quindi, se hanno effetti collaterali (come stampare o disegnare su uno schermo o un altro dispositivo), non dovrebbero essere statici o dovrebbero avere la posizione di uscita passata come parametro.

Quindi potresti avere un'interfaccia:

public interface CatMethods {
    void printInfo(Cat cat);
    void draw(Cat cat);
}

E un'implementazione che viene iniettata nel resto del sistema in fase di esecuzione (con altre implementazioni utilizzate per i test):

internal class CatMethodsForScreen implements CatMethods {
    public void printInfo(Cat cat) {
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public void draw(Cat cat) {
        //some draw code which uses cat.image
    }
}

Oppure aggiungi parametri extra per rimuovere gli effetti collaterali da questi metodi:

public static class CatMethods {
    public static void printInfo(Cat cat, OutputHandler output) {
        output.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat, Canvas canvas) {
        //some draw code which uses cat.image and draws it on canvas
    }
}

Ma perché dovresti provare a inserire un linguaggio OO come Java in un linguaggio funzionale, invece di utilizzare un linguaggio funzionale dall'inizio? È una specie di "Odio Java, ma tutti lo usano così devo, ma almeno lo scriverò a modo mio". A meno che tu non sostenga che il paradigma OO sia obsoleto e in qualche modo obsoleto. Mi iscrivo alla scuola di pensiero "Se vuoi X, sai dove trovarlo".
Kayaman,

@Kayaman, " Mi iscrivo alla" Se vuoi X, sai dove trovarla "scuola di pensiero ". Io non. Trovo questo atteggiamento sia miope che leggermente offensivo. Non uso Java, ma utilizzo C # e ignoro alcune delle funzionalità "real OO". Non mi interessa l'ereditarietà, gli oggetti con stato e simili e scrivo molti metodi statici e classi (finali) sigillate. La dimensione degli strumenti e della comunità intorno a C # non è seconda a nessuno. Per F #, è decisamente più povero. Quindi mi iscrivo alla scuola di pensiero "Se vuoi X, chiedi che venga aggiunta alla tua attuale attrezzatura".
David Arno,

1
Direi che ignorare gli aspetti di una lingua è molto diverso dal cercare di mescolare e abbinare funzionalità di altre lingue. Non provo nemmeno a scrivere "OO reale", poiché cercare di seguire semplicemente regole (o principi) in una scienza inesatta come la programmazione non funziona. Ovviamente devi conoscere le regole in modo da poterle infrangere. Affrontare le funzionalità alla cieca può essere dannoso per lo sviluppo del linguaggio. Senza offesa, ma IMHO una parte della scena FP sembra sentire "FP è la cosa più grande dopo il pane a fette, perché la gente non lo capisce". Non direi (o penso) che OO o Java siano "i migliori".
Kayaman,

1
@Kayaman, ma cosa significa "cercare di combinare funzioni di altre lingue"? Stai sostenendo che le funzioni funzionali non dovrebbero essere aggiunte a Java, perché "Java è un linguaggio OO"? Se è così, questo è un argomento miope a mio avviso. Lascia che il linguaggio si evolva con le esigenze degli sviluppatori. Credo che costringerli a passare a un'altra lingua sia invece l'approccio sbagliato. Sicuramente alcuni "sostenitori del PQ" vanno oltre il fatto che FP è la cosa migliore di sempre. E alcuni "sostenitori di OO" vanno oltre il fatto che OO abbia "vinto la battaglia perché è chiaramente superiore". Ignorali entrambi.
David Arno,

1
Non sono anti-FP. Lo uso in Java dove è utile. Ma se un programmatore dice "Lo voglio" è come un cliente che dice "Lo voglio". I programmatori non sono designer di linguaggi e i client non sono programmatori. Ho votato a favore della tua risposta dal momento che dici che la "soluzione" di OP è disapprovata. Il commento nella domanda è però più conciso, cioè ha reinventato la programmazione procedurale in un linguaggio OO. L'idea generale ha comunque senso, come hai dimostrato. Un modello di dominio non anemico non significa che dati e comportamenti siano esclusivi e che i renderer o i presentatori esterni sarebbero vietati.
Kayaman,

0

DTO - Oggetti di trasporto dati

sono utili proprio per questo. Se si desidera spostare i dati tra programmi o sistemi rispetto ai DTO sono desiderabili in quanto forniscono un sottoinsieme gestibile di un oggetto che riguarda solo la struttura e la formattazione dei dati. Il vantaggio è che non è necessario sincronizzare gli aggiornamenti con metodi complessi su più sistemi (purché i dati sottostanti non cambino).

Il punto centrale di OO è di associare i dati e il codice che agisce su tali dati strettamente insieme. Separare un oggetto logico in classi separate è di solito una cattiva idea.


-1

Molti modelli e principi di progettazione sono in conflitto, e alla fine solo il tuo giudizio come un buon programmatore ti aiuterà a decidere quali schemi dovrebbero applicare per un problema specifico.

A mio avviso, il principio Fai la cosa più semplice che potrebbe eventualmente funzionare dovrebbe vincere per impostazione predefinita a meno che tu non abbia una forte ragione per rendere il design più complicato. Quindi, nel tuo esempio specifico, opterei per il primo progetto, che è un approccio più tradizionale orientato agli oggetti con dati e funzioni insieme nella stessa classe.

Ecco un paio di domande che potresti farti sull'applicazione:

  • Avrò mai bisogno di fornire un modo alternativo per il rendering di un'immagine Cat? In tal caso, l'eredità non sarà un modo conveniente per farlo?
  • La mia classe Cat deve ereditare da un'altra classe o soddisfare un'interfaccia?

La risposta affermativa a uno di questi potrebbe portare a un design più complesso con DTO e classi funzionali separate.


-1

È un buon modello?

Probabilmente otterrai risposte diverse qui perché le persone seguono diverse scuole di pensiero. Quindi, prima ancora di iniziare: questa risposta è secondo la programmazione orientata agli oggetti, come è descritto da Robert C. Martin nel libro "Clean Code".


"True" OOP

Per quanto ne so, ci sono 2 interpretazioni di OOP. Per la maggior parte delle persone, si riduce a "un oggetto è una classe".

Tuttavia, ho trovato più utile l'altra scuola di pensiero: "Un oggetto è qualcosa che fa qualcosa". Se lavori con le classi, ogni classe sarebbe una delle due cose: un " detentore di dati " o un oggetto . I detentori dei dati conservano i dati (duh), gli oggetti fanno cose. Ciò non significa che un detentore di dati non possa avere metodi! Pensate a una list: Una listrealtà non fa nulla, ma ha metodi, per far rispettare il modo in cui essa detiene i dati .

Titolari dei dati

Sei Catun ottimo esempio di titolare di dati. Certo, al di fuori del tuo programma un gatto è qualcosa che fa qualcosa , ma all'interno del tuo programma, a Catè una stringa name, un int weighte un'immagine image.

Il fatto che i titolari dei dati non facciano nulla non significa che non contengano logiche aziendali! Se la Catclasse ha un costruttore che richiede name, weighte image, hai incapsulato con successo la regola di business che ogni gatto ha quelli. Se puoi modificare il weightdopo che una Catclasse è stata creata, questa è un'altra regola aziendale incapsulata. Queste sono cose basilari, ma ciò significa solo che è molto importante non sbagliarle - e in questo modo, ti assicuri che è impossibile sbagliarle.

Oggetti

Gli oggetti fanno qualcosa. Se vuoi oggetti Clean *, possiamo cambiarlo in "Gli oggetti fanno una cosa".

La stampa delle informazioni sul gatto è il lavoro di un oggetto. Ad esempio, è possibile chiamare questo oggetto " CatInfoLogger", con un metodo pubblico Log(Cat). Questo è tutto ciò che dobbiamo sapere dall'esterno: questo oggetto registra le informazioni di un gatto e per farlo ha bisogno di un Cat.

All'interno, questo oggetto avrebbe riferimenti a tutto ciò di cui ha bisogno per adempiere alla sua unica responsabilità di abbattere i gatti. In questo caso, questo è solo un riferimento a Systemper System.out.println, ma nella maggior parte dei casi, saranno riferimenti privati ​​ad altri oggetti. Se la logica per la formattazione dell'output prima della stampa diventa troppo complessa, è CatInfoLoggerpossibile ottenere un riferimento a un nuovo oggetto CatInfoFormatter. Se in seguito, ogni registro deve anche essere scritto in un file, è possibile aggiungere un CatToFileLoggeroggetto che lo fa.

Titolari dei dati vs oggetti - riepilogo

Ora, perché dovresti fare tutto questo? Perché ora cambiare una classe cambia solo una cosa ( il modo in cui un gatto è registrato nell'esempio). Se stai cambiando un oggetto, stai solo cambiando il modo in cui viene eseguita una determinata azione; se si cambia un titolare di dati, si cambia solo quali dati sono conservati e / o in che modo sono conservati.

Cambiare i dati potrebbe significare che anche il modo in cui qualcosa deve essere fatto deve cambiare, ma quel cambiamento non avverrà finché non lo fai accadere tu stesso cambiando l'oggetto responsabile.

Eccessivo?

Questa soluzione potrebbe sembrare un po 'eccessiva. Lasciatemi essere sincero: lo è . Se l'intero programma è grande solo come nell'esempio, non eseguire nessuna delle operazioni sopra descritte: basta scegliere una delle modalità proposte con un lancio di monete. Non c'è pericolo di confondere altro codice se non esiste un altro codice.

Tuttavia, qualsiasi software "serio" (= più di uno script o 2) è probabilmente abbastanza grande da trarre vantaggio da una struttura come questa.


Risposta

Separare la maggior parte delle classi in classi DTO e helper [...] è un buono o un anti-schema?

Trasformare "la maggior parte delle classi" (senza ulteriori qualifiche) in DTO / titolari di dati, non è un modello anti, perché in realtà non è un modello: è più o meno casuale.

Mantenere separati dati e oggetti è comunque considerato un buon modo per mantenere pulito il codice *. A volte avrai solo bisogno di un DTO piatto, "anemico" e basta. Altre volte, sono necessari metodi per imporre il modo in cui i dati vengono conservati. Basta non mettere la funzionalità del tuo programma con i dati.


* Questo è "pulito" con una C maiuscola come il titolo del libro, perché - ricorda il primo paragrafo - si tratta di una scuola di pensiero, mentre ce ne sono anche altre.

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.