Quando devo mescolare le funzioni con i dati in una classe?

3

Sulla base di alcune domande ho chiesto ( 1 , 2 , 3 ) Spesso mi viene suggerito di separare i dati dalle funzioni (a causa di cambiamenti di funzione, singola responsabilità, separazione delle preoccupazioni, adozione di interfacce, immutabilità, ...).

Quindi la mia domanda è: in quali situazioni le funzioni dovrebbero essere incapsulate con i dati? che tipo di funzioni sono? Rappresentare un'entità o un concetto un'unica responsabilità? se sì, allora posso concludere che nessuna funzione dovrebbe essere introdotta in una classe che rappresenta un'entità! Mi sono perso qualcosa?

Secondo i seguenti approcci, che succede se seguo sempre il secondo approccio! Si noti che nella seconda classe di approccio Entity non ha variabili di stato private in quanto non ha alcuna funzione, quindi i suoi campi sono accessibili in classe EntityOp1 e EntityOp23

class Entity
{ 
    public data;
    private s1, s2, s3;
    operation1;
    operation2;
    operation3;
}

vs.

class Entity
{
   public data;
}

class EntityOp1
{
     Entity e;
     private s1;
     operation1;
}
class EntityOp23
{
     Entity e;
     private s2, s3;
     operation2;
     operation3;
}
    
posta Ahmad 06.04.2015 - 07:31
fonte

4 risposte

8

L'obiettivo principale di OOP è limitare l'ambito in cui i campi (o le proprietà) possono essere mutati. Ciò rende molto più semplice il ragionamento e il debug di tale codice. Ecco perché la terza domanda a cui si fa riferimento parla di mutabilità. Se i tuoi campi sono immutabili, non è necessario limitare l'ambito dell'accesso al campo, quindi la separazione dei dati dalle operazioni ha molto più senso. Questo è ciò che fanno tutti i linguaggi puri / funzionali.

Probabilmente hai frainteso l'SRP e la separazione delle preoccupazioni. Dati e funzioni NON sono preoccupazioni separate. Sono parti di preoccupazione singola. Dovresti sempre modellare le tue funzioni e i tuoi dati come parti interconnesse, non come entità separate.

Ma i problemi iniziano quando includi le dipendenze nel mix. Ecco quali sono le prime due domande di riferimento. Avere dipendenza da qualche altro codice è una responsabilità, quindi dovresti provare a minimizzare il codice che dipende da qualcos'altro. Se hai una classe che dipende da una libreria complessa, ma solo il 10% di quella classe ha effettivamente bisogno di quella libreria, allora è una buona idea separare quei 10% in classi / entità separate. Ma questo lo rende un problema, perché ora la nuova classe non può accedere ai campi incapsulati cui potrebbe accedere in precedenza. Varie lingue offrono vari strumenti su come risolvere questo problema. Potresti renderli pubblici, interni o rendere la classe un "amico" o qualsiasi altra cosa.

Il fatto è che la modellazione e la progettazione di OOP sono aree estremamente complesse con un sacco di "cose da fare" e "cosa non fare" non contestati e ogni volta che si presenta una soluzione a un problema qualcuno ha problemi simili dove la soluzione non lo fa lavoro. Tutto si riduce all'esperienza. Sono stati scritti interi libri, blog e seminari su questo argomento. Non c'è modo di rispondere alla tua domanda con parole semplici, poche centinaia di post.

    
risposta data 06.04.2015 - 08:52
fonte
4

La semplice risposta è combinare i dati con le funzioni responsabili di tali dati. Ad esempio, se hai una classe Document , ha senso avere una funzione CalculateWordCount , poiché è la classe responsabile delle Parole all'interno del documento. In alternativa, puoi avere il Document responsabile per Paragraph oggetti, che sono a loro volta responsabili delle funzioni Paragraph -level e così via.

La parte difficile è la modellazione di funzioni che sembrano abbracciare diverse aree di responsabilità. Ad esempio, un metodo Save su quel Document . È responsabilità di Document salvare se stesso, anche se ora dovrà essere a conoscenza di un filesystem su cui salvare? Dovremmo invece avere una classe FileSystem che riceve la classe Document e la salva (che ci consente di cambiarla con WebStorage in seguito), o passare FileSystem in Document.Save ? Entrambi sono progetti validi, e sono dove l'esperienza può aiutarti a decidere.

    
risposta data 06.04.2015 - 08:43
fonte
1

Se la tua conclusione dalle risposte precedenti è che dovresti separare i dati dalla funzione,

  1. Hai frainteso le risposte
  2. Queste risposte sono sbagliate.

Ciò presuppone che si stia utilizzando un linguaggio orientato agli oggetti, in cui l'intera idea è combinare funzioni e dati.

    
risposta data 06.04.2015 - 07:39
fonte
1

Se hai bisogno di esempi quando legare dati e comportamenti e quando separarli, libri come quelli di GoF li hanno. Parte importante: ogni modello ha un'area di applicabilità ben definita, che indica quando usarlo.

Un altro principio di progettazione di base è "Accoppiamento basso (tra entità), alta coesione (all'interno di una singola entità)", le entità sono oggetti o funzioni o oggetti di dati puri.

Insieme ai pattern, hai bisogno di una visione su cosa applicarli, cioè su cosa modellare. Raccomando il libro " Modelli di analisi " di Martin Fowler e il "Domain-driven design" AKA "DDD" di Eric Evans.

    
risposta data 07.04.2015 - 22:41
fonte

Leggi altre domande sui tag