DDD - 实体状态转换实体、状态、DDD

2023-09-03 12:39:42 作者:我是你禽兽大人

考虑下面简单的例子:

 公共类门票
{
   公众诠释标识;
   公共TicketState状态;

   公众门票()
   {
      //从那里做我在这里得到了新状态的实体?其编号和名称
      国家= State.New;
   }

   公共无效结束()
   {
      //从那里我在这里得到了已完成状态的实体?其编号和名称
      国家= State.Finished;
   }
}

公共类TicketState
{
   公众诠释标识;
   公共字符串名称;
}
 

类状态直接使用的域对象门票内。后来在售票小号生命周期的其他国家可能被设置。

该票券持续到票务表,以及TicketState。因此,数据库中的门票将有一个外键票证状态表。

在我的实体内设置此时,相应的状态,我怎么加载从DB状态实例?我一定要注入资源库到实体?我需要使用像城堡这种情况下一个框架?还是有更好的解决方案,或许传递状态从外面?

 公共类门票
{
   // ...
   公共ITicketStateRepository STATEREP; //<  - 注入

   公众门票()
   {
      状态= stateRep.GetById(NEW_STATE_ID);
   }
   // ...
}
 
软件设计笔记 领域驱动设计 DDD

有没有最好的做法?到目前为止,我没有使用任何的依赖注入框架或任何东西,不停的任何持久性的东西出来我的域名。

另外approch:

 公共类门票
{
   // ...

   公共票务(NewTicketState newTicketState)
   {
      国家= newTicketState;
   }
   公共无效结束(FinishedTicketState finishedTicketState)
   {
      国家= finishedTicketState;
   }
   // ...
}
 

解决方案

的票不会有引用到资源库。它必须与TicketState一对一的关系,而将TicketRepository根本的JOIN和映射中的值进入票务

当我创建模型对象我通常不使他们认识到他们是否是持久性的,所以它们与存储库注入。存储库处理所有CRUD操作。

有些人反对这一点,说这导致了贫血的域模型;也许你是其中之一。如果是这样的情况下,库注入到你的票的对象,但简单的要求它做JOIN,并返回其状态填充票。当您插入或更新必须修改两个表作为一个单独的工作单位,所以一定要有交易接通。

我喜欢的领域模型对象以外的CRUD老年退休金计划的原因是,它通常是不参与的情况下使用或交易唯一的域对象。例如,也许您的简单的买门票用例将有一票的对象,但也可能被这种处理保留和休息和总账及行李的库存和各种其他一些事情的其他对象。你真的要坚持几个模型对象作为一个单独的工作单位。只有服务层可以知道,当一个模型对象是作用于自己的,当它是一个大的,宏伟的计划的一部分。

更新:

还有一个原因就是我不喜欢注射模型对象与DAO,因此它可以处理持久职责的想法是层的捣毁和循环依赖它引入。如果你保持模型的清洁从任何引用持久化类,你可以使用它们,而无需调用其他层。这是一个单向的依赖;持久知道模型,但模型不知道的持久性。

注入持久化到模型中,他们是周期性地依赖于对方。你永远无法使用或测试的任何一个没有其他。无分层,关注没有分离。

consider the following simplified example:

public class Ticket
{
   public int Id;
   public TicketState State;

   public Ticket()
   {
      // from where do I get the "New" state entity here? with its id and name
      State = State.New;
   }

   public void Finished()
   {
      // from where do I get the "Finished" state entity here? with its id and name          
      State = State.Finished;
   }
}

public class TicketState
{
   public int Id;
   public string Name;
}

The class state is used directly within the domain object ticket. Later in the ticket s lifecycle other states might be set.

The ticket is persisted into a Ticket table, as well as the TicketState. So within the DB the ticket will have a foreign key to the ticket state table.

When setting the appropiate state within my entity, how do I load the state instance from the DB? Do I have to inject a repository into the entity? Do I need to use a framework like castle for such case? Or are there better solutions, maybe passing the state from outside?

public class Ticket
{
   //...
   public ITicketStateRepository stateRep; //<-- inject

   public Ticket()
   {
      State = stateRep.GetById(NEW_STATE_ID);
   }
   //...
}

Is there any best practice? So far I did not use any dependency injection framework or anything and kept any persistence things out of my domain..

Another approch:

public class Ticket
{
   //...

   public Ticket(NewTicketState newTicketState)
   {
      State = newTicketState;
   }
   public void Finished(FinishedTicketState finishedTicketState)
   {
      State = finishedTicketState;
   }
   //...
}

解决方案

The Ticket would not have a reference to a repository. It would have a one-to-one relationship with TicketState, and the TicketRepository would simply do the JOIN and map the values into the Ticket.

When I create model objects I usually don't make them aware of whether or not they're persistent, so they aren't injected with a repository. The repository handles all CRUD operations.

Some people object to this, saying that it leads to an anemic domain model; perhaps you're one of them. If that's the case, inject the repository into your Ticket object, but simple ask it to do the JOIN and return a Ticket with its state populated. When you insert or update you have to modify two tables as a single unit of work, so be sure to have transactions turned on.

The reason I like to have CRUD ops outside the domain model object is that it usually isn't the only domain object participating in a use case or transaction. For example, maybe your simple "buy ticket" use case will have a Ticket object, but there might also have to be some other objects that deal with reservations and seating and general ledger and inventory of baggage and all sorts of other things. You'll really want to persist several model objects as a single unit of work. Only the service tier can know when a model object is acting on its own and when it's part of a larger, grander plan.

Update:

Another reason why I don't like the idea of injecting a model object with a DAO so it can handle persistence duties is the trashing of layers and the cyclic dependency it introduces. If you keep model clean from any references to persistence classes you can use them without having to invoke the other layer. It's a one-way dependency; persistence knows about model, but model does not know about persistence.

Inject the persistence into model and they're cyclicly dependent on each other. You can never use or test either one without the other. No layering, no separation of concerns.