Perché un modello di dominio anemico è considerato negativo in C # / OOP, ma è molto importante in F # / FP?

43

In un post di blog su F # per divertimento e profitto, si dice:

In a functional design, it is very important to separate behavior from data. The data types are simple and "dumb". And then separately, you have a number of functions that act on those data types.

This is the exact opposite of an object-oriented design, where behavior and data are meant to be combined. After all, that's exactly what a class is. In a truly object-oriented design in fact, you should have nothing but behavior -- the data is private and can only be accessed via methods.

In fact, in OOD, not having enough behavior around a data type is considered a Bad Thing, and even has a name: the "anemic domain model".

Dato che in C # sembriamo continuare a prendere in prestito da F # e provare a scrivere più codice in stile funzionale; come mai non stiamo prendendo in prestito l'idea di separare i dati / il comportamento e persino di considerarli negativi? È semplicemente che la definizione non ha con OOP, o c'è una ragione concreta che non funziona in C # che per qualche motivo non si applica in F # (e infatti, è invertito)?

(Nota: sono particolarmente interessato alle differenze in C # / F # che potrebbero cambiare l'opinione di ciò che è buono / cattivo, piuttosto che di individui che potrebbero non essere d'accordo con entrambe le opinioni nel post del blog).

    
posta Danny Tuppeny 28.06.2013 - 19:02
fonte

3 risposte

37

Il motivo principale per cui FP punta a questo e C # OOP non è che in FP l'attenzione è sulla trasparenza referenziale; cioè, i dati entrano in una funzione e i dati vengono fuori, ma i dati originali non vengono modificati.

In C # OOP esiste un concetto di delega di responsabilità in cui delegare la gestione di un oggetto ad esso, e quindi si desidera che modifichi i suoi interni.

In FP non vuoi mai cambiare i valori in un oggetto, quindi avere le tue funzioni incorporate nell'oggetto non ha senso.

Inoltre in FP hai un polimorfismo di tipo più elevato che consente alle tue funzioni di essere molto più generalizzate di quanto permetta C # OOP. In questo modo puoi scrivere una funzione che funziona per qualsiasi a , e quindi averlo incorporato in un blocco di dati non ha senso; questo accopperebbe strettamente il metodo in modo che funzioni solo con quel particolare tipo di a . Comportamento del genere è ben fatto e comune in C # OOP perché non hai la possibilità di astrarre le funzioni in genere comunque, ma in FP è un compromesso.

Il problema più grande che ho riscontrato nei modelli di dominio anemici in C # OOP è che si finisce con codice duplicato perché si ha DTO x e 4 diverse funzioni che commettono attività f in DTO x perché 4 persone diverse non hanno visto l'altra implementazione. Quando metti il metodo direttamente su DTO x, allora quelle 4 persone vedono tutte l'implementazione di f e la riutilizzano.

Modelli di dati anemici nel riutilizzo del codice hinder C # OOP, ma questo non è il caso in FP perché una singola funzione è generalizzata in così tanti tipi diversi che si ottiene un maggiore riutilizzo del codice poiché tale funzione è utilizzabile in così tanti più scenari di una funzione che dovresti scrivere per un singolo DTO in C #.

Come ha sottolineato nei commenti , l'inferenza di tipo è uno dei vantaggi che FP si basa per consentire un tale polimorfismo significativo, e in particolare è possibile risalire al Hindley Milner sistema di tipo con inferenza di tipo Algoritmo W; tale inferenza di tipo nel sistema di tipo C # OOP è stata evitata perché il tempo di compilazione quando viene aggiunta l'inferenza basata sui vincoli diventa estremamente lungo a causa della ricerca esauriente necessaria, dettagli qui: link

    
risposta data 28.06.2013 - 19:22
fonte
5

Why is an anemic domain model considered bad in C#/OOP, but very important in F#/FP?

La tua domanda ha un grosso problema che limiterà l'utilità delle risposte che ottieni: stai implicando / presumendo che F # e FP siano simili. FP è un'enorme famiglia di linguaggi tra cui il termine simbolico di riscrittura, dinamico e statico. Anche tra i linguaggi FP tipizzati staticamente ci sono molte diverse tecnologie per esprimere modelli di dominio come i moduli di ordine superiore in OCaml e SML (che non esistono in F #). F # è uno di questi linguaggi funzionali, ma è particolarmente importante per essere snello e, in particolare, non fornisce né moduli di ordine superiore né tipi di tipo superiore.

In effetti, non potevo iniziare a dirti come i modelli di dominio sono espressi in FP. L'altra risposta qui parla in modo molto specifico di come è fatto in Haskell e non è del tutto applicabile a Lisp (la madre di tutti i linguaggi FP), alla famiglia di linguaggi ML o ad altri linguaggi funzionali.

how come we're not borrowing the idea of separating data/behavior, and even consider it bad?

I farmaci generici potrebbero essere considerati un modo per separare dati e comportamenti. I generici provengono dalla famiglia di linguaggi di programmazione funzionale ML non fanno parte di OOP. C # ha generici, ovviamente. Quindi si potrebbe sostenere che C # sta lentamente prendendo in prestito l'idea di separare i dati e il comportamento.

Is it simply that the definition doesn't fit with OOP,

Credo che OOP si basi su premesse fondamentalmente diverse e, di conseguenza, non ti fornisce gli strumenti necessari per separare i dati e il comportamento. Per tutti gli scopi pratici è necessario disporre di tipi di dati del prodotto e della somma e inviarli su di essi. In ML questo significa unione e tipi di record e corrispondenza dei modelli.

Controlla l'esempio che ho fornito qui .

or is there a concrete reason that it's bad in C# that for some reason doesn't apply in F# (and in fact, is reversed)?

Fai attenzione a saltare da OOP a C #. C # non è neanche lontanamente altrettanto puritano riguardo a OOP come altre lingue. .NET Framework è ora pieno di generici, metodi statici e persino lambda.

(Note: I'm specifically interested in the differences in C#/F# that could change the opinion of what is good/bad, rather than individuals that may disagree with either opinion in the blog post).

La mancanza di tipi di unione e corrispondenza dei pattern in C # rende quasi impossibile farlo. Quando tutto ciò che hai è un martello, tutto sembra un chiodo ...

    
risposta data 16.03.2015 - 13:24
fonte
-4

Penso che in un'applicazione aziendale spesso non si vogliano nascondere i dati perché la corrispondenza dei modelli su valori immutabili è ottima per garantire che si tratti di tutti i possibili casi. Ma se stai implementando algoritmi o strutture dati complessi, è meglio nascondere i dettagli di implementazione trasformando gli ADT (tipi di dati algebrici) in ADT (tipi di dati astratti).

    
risposta data 04.11.2015 - 18:04
fonte

Leggi altre domande sui tag