首页 > 解决方案 > 实体惰性方法和 Dimetra 法则

问题描述

我有实体:

@Entity
@Table(name = "CARDS")
public class Card {

  @ManyToOne
  @JoinColumn(name = "PERSON_ID", referencedColumnName = "ID", nullable = false)
  private Person person;

  @OneToMany(mappedBy = "card")
  private List<CardStatus> cardStatuses;

我的服务可以调用下一个代码:

public Card getCardBlaBlaBla(Long id){

   Card card  = cardRepository.findaCard(id);

   Something something = card.getCardStatuses().get(0).getSomething();
}

card.getCardStatuses().get(0).getSomething() -getCardStatusesLAZY

我的问题 - 这个挑战是否违反了 Dimetra 法?

得墨忒耳法则 有一个著名的启发式法则叫做得墨忒耳法则 2,它说模块不应该知道它所操作的对象的内部结构。正如我们在上一节中看到的,对象隐藏了它们的数据并暴露了操作。这意味着对象不应通过访问器公开其内部结构,因为这样做是公开而不是隐藏其内部结构。更准确地说,得墨忒耳法则说 C 类的方法 f 应该只调用这些方法:

• C
• An object created by f
• An object passed as an argument to f
• An object held in an instance variable of C

该方法不应调用任何允许的函数返回的对象上的方法。换句话说,与朋友交谈,而不是与陌生人交谈。以下代码似乎违反了得墨忒耳定律(除其他外),因为它在 getOptions() 的返回值上调用 getScratchDir() 函数,然后在 getScratchDir() 的返回值上调用 getAbsolutePath()。final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

Card- 是数据结构,不违反 Dimetra 法则,但LAZY方法有 logik(选择 DB)。

这个挑战是否违反了 Dimetra 法律?如果是,我该如何正确使用它?

我真的有很多代码,例如:

entityOblect.getChield().getChield().getSomething();

编辑

来自清洁代码书:

在此处输入图像描述

编辑2

(c) Robert C. Martin - 干净的代码

活动记录活动记录是 DTO 的特殊形式。它们是具有公共(或 bean 访问)变量的数据结构;但它们通常具有保存和查找等导航方法。通常,这些 Active Record 是从数据库表或其他数据源直接转换而来的。不幸的是,我们经常发现开发人员试图通过将业务规则方法放入其中来将这些数据结构视为对象。这很尴尬,因为它在数据结构和对象之间创建了混合体。当然,解决方案是将 Active Record 视为一种数据结构,并创建包含业务规则并隐藏其内部数据(可能只是 Active Record 的实例)的单独对象。

标签: javadesign-patternsentitydesign-principles

解决方案


这违反了得墨忒耳定律:

Something something = card.getCardStatuses().get(0).getSomething();

在一个语句中,您浏览所有这些对象:
Card-> List<CardStatus>-> CardStatus-> Something

理想情况下,您应该从客户端进行此通信:
Card-> Something

Card类中,Something可以使用执行此导航的方法来实现返回:
List<CardStatus>-> CardStatus-> Something

在某种程度上,最后一个也违反了 Demeter 定律,但在我们认为可以接受的水平上,因为我们不应该将这种关系List<CardStatus>->CardStatus视为陌生人关系

它可以给:

Something something = card.getSomethingOfCardStatuses(0);

或避免使用get前缀:

Something something = card.findSomethingOfCardStatuses(0);

并且findSomethingOfCardStatuses()可以定义Card为:

public Something findSomethingOfCardStatuses(int statusNumber){
    // add some check for the index if required 
    // you could return Optional or an Exception according to your requirements
    return cardStatuses.get(0).getSomething();
}

我知道许多开发人员喜欢在实体字段中手动挖掘,但我个人避免这样做,我尝试为他们提供一些具有有意义名称和行为的逻辑方法。它使核心变得更加清晰。


推荐阅读