Hibernate “这是一个好主意吗?”;将业务逻辑代码迁移到我们的域模型中;?

Hibernate “这是一个好主意吗?”;将业务逻辑代码迁移到我们的域模型中;?,hibernate,spring,jpa,Hibernate,Spring,Jpa,我正在阅读Hibernate in Action,作者建议将业务逻辑转移到我们的领域模型中(第306页)。例如,在本书提供的示例中,我们有三个实体,分别命名为Item、Bid、和User,作者建议在Item类中添加placeBid(User bidder amount,BigDecimal amount)方法 考虑到我们通常有一个独特的业务逻辑层(例如,Spring中的Manager或Service类),其中包括控制事务等。这真的是一个好建议吗?不向实体添加业务逻辑方法不是更好吗 提前谢谢。如前

我正在阅读Hibernate in Action,作者建议将业务逻辑转移到我们的领域模型中(第306页)。例如,在本书提供的示例中,我们有三个实体,分别命名为
Item
Bid
、和
User
,作者建议在
Item
类中添加
placeBid(User bidder amount,BigDecimal amount)
方法

考虑到我们通常有一个独特的业务逻辑层(例如,Spring中的
Manager
Service
类),其中包括控制事务等。这真的是一个好建议吗?不向实体添加业务逻辑方法不是更好吗

提前谢谢。

如前所述

我们有一个独特的业务逻辑层(通常称为服务层)

域驱动设计(DDD)指出您应该将业务逻辑放入域模型中。相信我,这真的很好。正如POJO在关于服务层的行动手册中所说的

  • 它是用例驱动的
  • 它可以定义事务边界
之前

@Service
public class BidServiceImpl implements BidService {

    @Autowired
    private ItemRepository itemRepository;

    public void placeBid(Integer itemId, User bidder, BigDecimal amount) {

        Item item = itemRepository.getById(itemId);

        if(amount.compareTo(new BigDecimal("0.00")) <= 0)
            throw new IllegalStateException("Amount must be greater than zero");

        if(!bidder.isEnabled())
            throw new IllegalStateException("Disabled bidder");

        item.getBidList().add(new Bid(bidder, amount));
    }

}
您的域逻辑如下所示

@Entity
public class Item implements Serializable {

    private List<Bid> bidList = new ArrayList<Bid>();

    @OneToMany(cascade=CascadeType.ALL)
    public List<Bid> getBidList() {
        return this.bidList;
    }

    public void placeBid(User bidder, BigDecimal amount) {

        if(amount.compareTo(new BigDecimal("0.00")) <= 0)
            throw new IllegalStateException("Amount must be greater than zero");

        if(!bidder.isEnabled())
            throw new IllegalStateException("Disabled bidder");

        /** 
          * By using Automatic Dirty Checking
          * 
          * Hibernate will save our Bid
          */
        item.getBidList().add(new Bid(bidder, amount));
     }

}
@实体
公共类项实现可序列化{
private List bidList=new ArrayList();
@OneToMany(级联=级联类型.ALL)
公共列表getBidList(){
返回此.bidList;
}
公开作废投标(用户投标人,大小数金额){

如果(amount.compareTo)(新的BigDecimal(“0.00”)这方面引用最多的文章之一是:

Martin Fowler的“贫血区域模型”。 非常值得一读:

一般的要点是,如果您的领域模型纯粹是数据,没有任何行为,那么您就失去了OO设计的许多好处

或引用:


“一般来说,你在服务中发现的行为越多,你就越有可能剥夺自己域模型的好处。如果你所有的逻辑都在服务中,那么你就盲目地剥夺了自己。”

我个人喜欢贫血模型——数据就是数据,代码就是代码;但也有例外

它可以归结为“密度”:如果你有大量的服务与几个域对象交互;在你的域模型中加入一些常见的业务逻辑是有意义的,因此它就成为了服务的一部分。如果你有一些服务与许多域对象交互,那么你就喜欢贫乏的模型而不是丰富的域对象对象


我发现,如果我在多个上下文中使用域对象(例如,我在客户端和服务端使用相同的域对象)这一业务逻辑常常会产生阻碍,因为它必须适用于所有上下文。

为什么项目知道在其上进行投标的规则?我会将其放在处理规则的不同模块中,并从投标过程中抽象出来。我不想每次我们改进规则时都更改项目类。但我会我仍然在Item.placeBid(…)方法中调用这些规则。很有趣。当我看到这些代码时,我仍然觉得有点倒退。我必须阅读DDD,看看我的想法。我觉得最后一个链接提供了“有时”的原因不过,使用服务层会触及我喜欢使用它们的许多要点,所以也许我并不是完全疯了。只要看看上面的Before/After示例和我的经验,大多数非琐碎的项目都存在于“有时”类别,我仍然觉得最好让实体对象没有商业逻辑代码。但到目前为止还没有练习DDD。@Stephane:一个项目知道如何在其上生成位,因为这就是项目的用途!在面向对象的世界观下,这是项目本质的基本部分。@Tom Anderson我认为项目可以知道这一点这里有一个验证要做,但我会把验证的细节提取到其他地方。我只是不想在这里列出所有的规则。但也许这没关系。我对DDD了解不多,这只是我写代码的感觉。我愿意了解更多:)检查并查看这个相关线程:所以你不喜欢OOP,但喜欢过程代码。希望你不是在单例组件上编写业务逻辑……不要忘记函数编程和不可变数据……是的,这不是OOP,但不是每个人都必须喜欢OOP,也不是每个不喜欢OOP的人都必须喜欢过程编程。你认为呢在你的表上设置触发器?正如我要说的,我不是触发器的粉丝,而是首先负责交互的过程应该决定数据的变化方式和时间。他谈到反模式,这太棒了,我觉得这只是没有实际例子的讨论。我不是在谈论实体验证on!在Sql中,我们不在表上定义函数,这意味着这将是一个gd想法。需要示例。
@Entity
public class Item implements Serializable {

    private List<Bid> bidList = new ArrayList<Bid>();

    @OneToMany(cascade=CascadeType.ALL)
    public List<Bid> getBidList() {
        return this.bidList;
    }

    public void placeBid(User bidder, BigDecimal amount) {

        if(amount.compareTo(new BigDecimal("0.00")) <= 0)
            throw new IllegalStateException("Amount must be greater than zero");

        if(!bidder.isEnabled())
            throw new IllegalStateException("Disabled bidder");

        /** 
          * By using Automatic Dirty Checking
          * 
          * Hibernate will save our Bid
          */
        item.getBidList().add(new Bid(bidder, amount));
     }

}