Question

Je cherche des conseils sur la façon que je devrais être concerné autour d'éviter le modèle de domaine anémique. Nous commençons tout juste sur DDD et luttons avec la paralysie d'analyse en ce qui concerne les décisions de conception simple. Le dernier point que nous collons sur est là une certaine logique commerciale appartient, par exemple, nous avons un objet Order, qui a des propriétés comme Status etc. dire Maintenant, je dois exécuter une commande comme UndoLastStatus parce que quelqu'un a fait une erreur avec un ordre, cela est pas aussi simple que de changer le Status que d'autres informations doit être connecté et propriétés ont changé. Maintenant, dans le monde réel c'est une tâche pure administration. Donc, la façon dont je le vois j'ai deux options que je peux penser à:

  • Option 1: Ajouter la méthode à l'ordre si quelque chose comme Order.UndoLastStatus(), alors que ce faire un peu de sens, il ne reflète pas vraiment le domaine. Aussi Order est l'objet principal dans le système et si tout ce qui concerne l'ordre est placé dans les choses de la classe de commande pourrait sortir de la main.

  • Option 2: Créer un objet Shop, et qui ont des services différents qui représentent des rôles differant. Donc, je pourrais avoir Shop.AdminService, Shop.DispatchService et Shop.InventoryService. Donc, dans ce cas, j'aurais Shop.AdminService.UndoLastStatus(Order).

Maintenant, la deuxième option que nous avons quelque chose qui reflète le domaine beaucoup plus, et permettrait aux développeurs de parler à des experts d'affaires au sujet des rôles similaires qui existent en réalité. Mais son cap aussi vers un modèle anémique. Quelle serait la meilleure façon d'aller en général?

Était-ce utile?

La solution

Option 2 conduirait à un code de procédure pour sûr.
Peut-être plus facile à développer, mais beaucoup plus difficile à maintenir.

dans le monde réel c'est une tâche pure administration

tâches "administration" doit être privé et invoqué par des partenariats public, entièrement actions "domain`ish". De préférence, -. Encore écrit facile à comprendre le code qui est chassé de domaine

Comme je le vois - problème est que UndoLastStatus peu de sens à l'expert de domaine
. Plus ils parlent de faire, l'annulation et remplir les commandes.

Quelque chose le long de ces lignes pourra être mieux:

class Order{
  void CancelOrder(){
    Status=Status.Canceled;
  }
  void FillOrder(){
    if(Status==Status.Canceled)
      throw Exception();
    Status=Status.Filled;
  }
  static void Make(){
    return new Order();
  }
  void Order(){
    Status=Status.Pending;
  }
}

Je n'aime personnellement l'utilisation des « statuts », ils sont automatiquement partagés à tout ce qui les usages eux - je vois que comme couplage inutile .

Je voudrais avoir quelque chose comme ceci:

class Order{
  void CancelOrder(){
    IsCanceled=true;
  }
  void FillOrder(){
    if(IsCanceled) throw Exception();
    IsFilled=true;
  }
  static Order Make(){
    return new Order();
  }
  void Order(){
    IsPending=true;
  }
}

Pour changer les choses connexes lorsque l'état de l'ordre des changements, le mieux est d'utiliser ce qu'on appelle événements de domaine .
Mon code regarderait le long de ces lignes:

class Order{
  void CancelOrder(){
    IsCanceled=true;
    Raise(new Canceled(this));
  }
  //usage of nested classes for events is my homemade convention
  class Canceled:Event<Order>{
    void Canceled(Order order):base(order){}
  }     
}

class Customer{
  private void BeHappy(){
    Console.WriteLine("hooraay!");
  }
  //nb: nested class can see privates of Customer
  class OnOrderCanceled:IEventHandler<Order.Canceled>{
   void Handle(Order.Canceled e){
    //caveat: this approach needs order->customer association
    var order=e.Source;
    order.Customer.BeHappy();
   }
  }
}

Si l'ordre devient trop grand, vous pouvez vérifier ce que noreferrer contextes bornés sont (comme Eric Evans dit - s'il avait une chance de nouveau écrit son livre, il se déplacerait des contextes borné au début).

En bref - c'est une forme de décomposition entraînée par domaine.

L'idée est relativement simple - il est normal d'avoir plusieurs commandes de différents points de vue aka contextes.

par exemple. -. Ordre du contexte commercial, Ordre du contexte comptable

namespace Shopping{
 class Order{
  //association with shopping cart
  //might be vital for shopping but completely irrelevant for accounting
  ShoppingCart Cart;
 }
}
namespace Accounting{
 class Order{
  //something specific only to accounting
 }
}

Mais domaine généralement assez lui-même évite la complexité et est facilement décomposables si vous écoutez assez près. Par exemple. Vous pourriez entendre des termes d'experts comme OrderLifeCycle, OrderHistory, OrderDescription que vous pouvez tirer parti comme points d'ancrage pour la décomposition.

NB: Gardez à l'esprit - je suis nulle compréhension au sujet de votre domaine
. Il est très probable que ces verbes que je utilise sont complètement étranges à elle.

Autres conseils

Je serais guidé par le GRASP principes. Appliquer le Expert information principe de conception, qui est que vous devez assigner la responsabilité de la classe qui a naturellement les informations les plus nécessaires pour réaliser le changement.

Dans ce cas, étant donné que la modification du statut de la commande implique d'autres entités, je ferais chacun de ces objets de domaine de bas niveau en charge une méthode pour appliquer la modification par rapport à lui-même. Ensuite, utilisez également une couche de service de domaine que vous décrivez dans l'option 2, que les résumés l'opération, couvrant plusieurs objets de domaine au besoin.

Voir aussi le motif Façade .

Je pense avoir une méthode comme UndoLastStatus sur la classe Order se sente un mauvais bit parce que les raisons de son existence sont en dehors de sens de la portée d'une ordonnance. D'autre part, ayant une méthode qui est responsable de la modification du statut d'une commande, Order.ChangeStatus, s'intègre bien comme un modèle de domaine. L'état d'une commande est un concept approprié de domaine et changer ce statut doit être fait par la classe Ordre, puisqu'elle possède les données associées à un état de la commande - il est de la responsabilité de la classe pour se maintenir cohérente et dans un état approprié .

Une autre façon de penser est que l'objet L'ordre est ce qui a persisté à la base de données et il est le « dernier arrêt » pour toutes les modifications appliquées à un ordre. Il est plus facile de raisonner sur ce qu'est un état valide pour un ordre peut-être dans la perspective d'un ordre plutôt que du point de vue d'un composant externe. C'est ce que DDD et POO sont tout, ce qui rend plus facile pour l'homme à la raison sur le code. En outre, l'accès aux membres privés ou protégés peut être nécessaire d'exécuter un changement d'état, auquel cas avoir la méthode soit la classe de commande est une meilleure option. Ceci est l'une des raisons pour lesquelles les modèles de domaine anémiques sont mal vus -. Ils changent la responsabilité de maintenir l'état cohérent loin de la classe propriétaire, rompant ainsi l'encapsulation entre autres

Une façon de mettre en œuvre une opération plus spécifique, comme UndoLastStatus serait de créer un OrderService qui expose le domaine et comment les composants externes fonctionnent sur le domaine. Ensuite, vous pouvez créer un simple objet de commande comme ceci:

class UndoLastStatusCommand {
  public Guid OrderId { get; set; }
}

Un OrderService l'aurait un procédé pour traiter cette commande:

public void Process(UndoLastStatusCommand command) {
  using (var unitOfWork = UowManager.Start()) {
    var order = this.orderRepository.Get(command.OrderId);
    if (order == null)
      throw some exception

    // operate on domain to undo last status

    unitOfWork.Commit();
  }
}

Alors maintenant, le modèle de domaine pour l'ordre expose toutes les données et les comportements qui correspondent à un ordre, mais le OrderService, et la couche de service en général, déclarer les différents types d'opérations qui sont effectuées sur un ordre et exposer le domaine pour une utilisation par des composants externes, comme la couche de présentation.

Il faut aussi considérer la recherche dans le concept de événements de domaine qui considère les modèles de domaine anémiques et les moyens de les améliorer.

On dirait que vous ne conduisez pas ce domaine des tests. Jetez un coup d'oeil au travail de Rob Vens , en particulier son travail sur la modélisation exploratoire , l'inversion du temps et actif-passif.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top