【问题标题】:What is the best practice for retrieving an item in a collection from a domain model?从域模型中检索集合中的项目的最佳实践是什么?
【发布时间】:2009-09-01 20:30:11
【问题描述】:

从具有指定属性的域对象的集合中检索对象的最佳做法是什么?

例如,我们有一个汽车保险应用程序,它有两个类:一个带有汽车列表的人。如果我总是需要从具有指定 VIN 的人那里检索汽车,那么实现该方法的最佳方法是什么?我在下面提供了一些示例 - 欢迎其他示例

示例 1
在 Person 实体中添加一个新方法来检索 VIN

public class Person { private HashSet<Car> cars = new HashSet<Car&gt(); public Set<Car> getCars() { return this.cars; } public Car getCarByVin(VIN vin) { //loop over cars and retrieve the car with the VIN } }

因此,从应用程序来看,该过程将是......


    VIN vin = new VIN(...);
    Person person = personDao.getPerson();
    Car personCar = person.getCarByVin(vin); 

示例 2
在 Person 实体中创建一个新的列表集合,并将通过 VIN 方法检索到该集合中

public class Person { private CarSet cars = new CarSet(); public CarSet getCars() { return this.cars; } } public class CarSet implements Set<Car> { //implement required methods for Set public Car byVin(VIN vin) { //loop over set and retrieve the car with the VIN } }

因此,从应用程序来看,该过程将是......


    VIN vin = new VIN(...);
    Person person = personDao.getPerson();
    Car personCar = person.getCars().byVin(vin); 

【问题讨论】:

  • 你能告诉我们为什么你首先需要这辆真正的汽车吗?是为了展示还是您试图实现它们的特定行为?
  • @ShaneC - 给出的示例只是一个简单的示例,我可以发布它而无需解释完整的域。在我真正的问题中,我试图在另一个实体对象中使用集合中的一个对象作为业务规则。

标签: java dns domain-driven-design


【解决方案1】:

我认为得墨忒耳法则在这里适用,这有利于第一个例子。任何时候链接,例如 foo.getBar().doBlah(),这都违反了得墨忒耳法则。这显然不是法律,但当一个类必须了解另一个类中的位的太多细节时,它是一个很好的指导方针。

【讨论】:

  • 啊,是的,LoD……你是对的——第一个比第二个更好,因为隐藏了细节。谢谢克里斯!
【解决方案2】:

只要你说带有指定 VIN 的汽车,你就让我认为这是实体,而不是值对象......此外,如果你需要“检索”它,这意味着它是实体,而不是值。通常不需要检索值对象,如果需要,您可以即时创建一个...您确定您清楚 DDD 中实体和值元素之间的区别吗?

添加:那么如果 Car 是一个实体,从您所说的来看,它似乎应该是一个以 Person 作为聚合根的聚合中的成员实体。 (尽管它可能是它自己的聚合的根)在任何情况下,都应该构建 Person 存储库,以便在获取聚合时它也可以获取该人的 Cars。 Person 类应该有一个类型为 Cars 或 CarCollection 的属性,该属性名为 Cars 或 OwnedCars 或其他名称,并且该类型(Cars 或 CarCollection)应该有一个索引器,该索引器可以根据 VIN 检索特定的汽车。

public class Person    
{
   private int persId;
   // other fields
   private Cars cars;

   public Cars Cars { get; set; }
   // all other stuff
}

public class Cars: Collection<Car> // or 'public class Cars: List<Car>' or ...
{
    public bool Contains(string VinNumber]
    {
        foreach (Car c in this)
           if (c.VinNumber = VinNumber) return true;
        return false;
    }
    public Car this[string VinNumber]
    {
        get 
        {
            foreach (Car c in this)
                if (c.VinNumber = VinNumber) return c;
            return null;
        }
    }
}

【讨论】:

  • 我认为这作为评论比作为“答案”更好。
  • 你可能是对的;这似乎是一个实体对象。谢谢查尔斯。
  • 问题说这是Java代码。上面的代码是 C#。 :)
  • 正如 jsight 所说,C# 并没有帮助,但是这个概念就像示例 2 中给出的一样。对吗?如果不是,它有什么不同?
【解决方案3】:

在这种情况下,我发现将搜索方法放在对象本身上更容易,而不是尝试将集合类子类化(并带来所有可能由看似简单的决定导致的设计决策更改)。

以上所有内容都假设基本设计确实是您想要的。不过,我通常更喜欢某种外观,它允许我按人和 vin 搜索车辆,而不是搜索人对象本身。

【讨论】:

  • 对于其他一些应用程序,有一个“服务”层,它在数据访问逻辑上创建了一个外观。这就是你的建议吗?
     public class CarFinderService { public Car findCar(PersonId personId, VIN vin) { //根据指定人员的 VIN 查找汽车 } } 
  • @Jared - 是的,类似的东西。
【解决方案4】:

我真的不喜欢你的 CarSet 设计。如果没有专门的行为,我不希望看到专门的课程。诚然,这是一个简单的例子来证明一个观点。

但我也反对您的 Person 示例。您有一个对 HashSet 的私有引用,该引用应该具有 Set 的静态类型。然后你有一个 getter,它返回对该私有数据成员的引用。您应该意识到这是一个任何人都可以操作的可变引用。您的私人修饰符毫无意义。

在这种情况下,正确的做法是使用 java.util.Collections 类返回对不可变 Set 的引用,以防止客户端修改私有状态。

【讨论】:

  • 你是对的,Collections.unmodifiableXXX() 方法是我们的​​朋友。对于这个例子,我想让它易于阅读并省略它。谢谢达菲!
猜你喜欢
  • 2018-10-18
  • 1970-01-01
  • 2017-12-07
  • 2012-08-19
  • 2018-12-11
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多