2009-03-04 7 views
20

J'ai lu certaines des questions concernant les modèles de domaine anémiques et la séparation des préoccupations. Quelles sont les meilleures techniques pour effectuer/attacher la logique de domaine sur des objets de domaine anémiques? Dans mon travail, nous avons un modèle assez anémique, et nous utilisons actuellement des classes «helper» pour exécuter la base de données/la logique métier sur les objets du domaine. Par exemple:Techniques pour traiter le modèle de domaine anémique

public class Customer 
{ 
    public string Name {get;set;} 
    public string Address {get;set;} 
} 

public class Product 
{ 
    public string Name {get;set;} 
    public decimal Price {get;set;} 
} 

public class StoreHelper 
{ 
    public void PurchaseProduct(Customer c, Product p) 
    { 
     // Lookup Customer and Product in db 
     // Create records for purchase 
     // etc. 
    } 
} 

Lorsque l'application doit faire un achat, il créerait le StoreHelper et appeler la méthode sur les objets de domaine. Pour moi, il serait logique que le client/produit sache comment se sauver dans un dépôt, mais vous ne voudriez probablement pas de méthodes Save() sur les objets du domaine. Cela aurait aussi du sens pour une méthode comme Customer.Purchase (Product), mais cela met la logique du domaine sur l'entité.

Voici quelques techniques que j'ai rencontré, pas sûr sont bons/mauvais:

  1. hériteront Client et produit d'une classe « entité », qui fournit les opérations CRUD de base d'une manière générique (en utilisant un ORM peut-être).
    • Plus: Chaque objet de données serait automatiquement obtenir les opérations CRUD, mais sont ensuite liés à la base de données/ORM
    • Inconvénients: Cela ne résout pas le problème des opérations commerciales sur les objets, et aussi des liens tous les objets de domaine à une entité de base qui pourrait ne pas être appropriée
  2. Utiliser des classes d'aide pour gérer les opérations CRUD et la logique métier
    • est-il logique d'avoir OTI pour les opérations de « base de données pures », et des aides d'affaires séparées pour eux opérations spécifiques à l'entreprise?
    • Est-il préférable d'utiliser des classes auxiliaires non statiques ou statiques pour cela?
    • Avantages: objets de domaine ne sont pas liés à une base de données/logique métier (complètement anémique)
    • Inconvénients: pas très OO, pas très naturel d'utiliser les aides dans le code d'application (qui ressemble à du code C)
  3. Utilisez la technique Double Dispatch où l'entité a des méthodes pour enregistrer dans un répertoire arbitraire
    • plus: une meilleure séparation des préoccupations
    • Inconvénients: les entités ont une certaine logique supplémentaire ci-joint (bien qu'il soit découplé)
  4. En C# 3.0, vous pouvez utiliser des méthodes d'extension pour fixer les méthodes CRUD/d'affaires à un objet de domaine sans le toucher
    • Est-ce une approche valable? Quels sont les avantages/inconvénients?
  5. D'autres techniques?

Quelles sont les meilleures techniques pour gérer cela? Je suis assez nouveau à DDD (je lis le livre d'Evans - ainsi peut-être que cela ouvrira mes yeux)

Répondre

7

Martin Fowler a beaucoup écrit sur les modèles de domaines, y compris anemic domain models. Il a également de brèves descriptions (et diagrammes de classes UML) de nombreux modèles de conception pour les modèles de domaine et les bases de données qui pourraient être utiles: Catalog of "Patterns of Enterprise Application Architecture". Je suggère de regarder les modèles Active Record et Data Mapper. De la description de votre problème, il semble que vos classes auxiliaires contiennent à la fois les règles de domaine/métier et les détails d'implémentation de base de données. L'enregistrement actif déplace la logique du domaine de l'assistant et le code de base de données dans les autres objets de domaine (comme votre classe de base Entity). Le Data Mapper déplacerait la logique du domaine de l'assistant dans les objets de domaine et le code de la base de données dans un objet de carte séparé. L'une ou l'autre approche serait plus orientée objet que les classes auxiliaires de style procédural.

Le livre "Domain Driven Design" d'Eric Evans est excellent. Il devient un peu sec, mais ça vaut vraiment le coup. InfoQ a un "Domain Driven Design Quickly" mini-book qui est une bonne introduction au livre d'Evans. Plus "Domain Driven Design Quickly" est disponible en format PDF gratuit.

2

J'ai toujours pensé au modèle de domaine anémique comme anti modèle.Il est clair qu'un client achètera des produits, cette capacité peut être generised par une implémentation de l'interface

Interface IPurchase 
     Purchase(Product); 

, donc un quelconque de vos objets de domaine peut alors mettre en œuvre que si nécessaire. De cette façon, vous pouvez introduire des fonctionnalités à vos objets de domaine - ce qui est exactement ce qu'il devrait être.

14

Afin d'éviter le modèle anémique, factoriser vos classes d'aide:

Logic comme:
"Customer.PurchaseProduct (produit de produit, le paiement de paiement)",
« Customer.KillCustomer (tueur de personne, arme d'arme) "
doit exister directement dans l'objet de domaine" Client ".

Logic comme:
"Customer.IsCustomerAlive()"
"Customer.IsCustomerHappy()"
devrait aller aux spécifications.

Logic comme:
"Customer.Create()",
"Customer.Update()"
doit évidemment aller à des dépôts.

Logic comme:
"Customer.SerializeInXml()"
"Customer.GetSerializedCustomerSizeInBytes()"
devrait aller aux services.

Les constructeurs complexes devraient aller aux usines.

Voilà comment je le vois. Je serais heureux si quelqu'un pouvait commenter ma compréhension de l'approche DDD.


Edit:

Parfois - modèle de domaine anémique shouldn't be avoided.

Édité ma réponse pour ajouter que DDD ne consiste pas à ramasser et laisser tomber des modèles.
DDD est à propos de la façon dont nous pensons.

+0

On dirait qu'il y a BEAUCOUP de classes différentes pour gérer un client. Pourquoi ne pas en lancer la majeure partie dans une seule classe, avec un service pour gérer quelque chose de complexe? –

+0

Ma réponse est vieille comme l'enfer. : D –

+0

@LuckyLindy Principalement parce que DDD est sur le point de créer un pont entre les experts du domaine et les programmeurs. Le modèle de domaine ne doit pas contenir d'éléments techniques, sinon le langage omniprésent ne pourra pas exister. Pour sortir des trucs techniques - nous devons l'abstraire. L'abstraction de quelque chose gonfle toujours la base du code. –

0

Une approche que vous n'avez pas mentionnée consiste à utiliser AOP pour gérer votre accès aux données. Un exemple de mon utilisation récente de cette approche (bien que simplifiée à des fins d'affichage) était que j'avais une entité de domaine Account qui avait une méthode debit, encapsulant la logique métier requise pour effectuer un débit réussi à partir du compte.

N.B. Tout le code est Java avec la notation AspectJ AOP ...

public boolean debit(int amount) { 
    if (balance - amount >= 0) { 
     balance = balance - amount; 
     return true; 
    } 
    return false; 
} 

Avec le dépôt approprié injecté dans mon aspect, je puis utilisé un pointcut pour intercepter les appels à cette méthode ...

pointcut debit(Account account,int amount) : 
    execution(boolean Account.debit(int)) && 
    args(amount) && 
    target(account); 

. ..et appliqué quelques conseils:

after(Account account, int amount) returning (boolean result) : debit(account,amount) { 
    if (result) getAccountRepository().debit(account, amount); 
} 

à mon avis ce qui donne une séparation bien des préoccupations, et permet à vos entités de domaine de se concentrer entièrement sur la logique métier de y notre application.

Questions connexes