对一对多关系进行编程

2022-09-04 20:11:29

因此,我很惊讶在Google上进行搜索,stackoverflow不会返回更多结果。

在OO编程中(我使用的是java),你如何正确地实现一对多关系?

我有一个班级和班级。我的申请是为一家为客户完成工作的虚构公司提出的。我目前的实现是使类与类没有任何关系,根本没有对它的引用。该类使用集合和方法来保存、检索和修改有关已由客户分配和/或为客户完成的作业的信息。CustomerJobJobCustomerCustomer

问题是,如果我想找出为哪个客户做了某项任务,该怎么办?我只找到这篇文章是相关的:http://www.ibm.com/developerworks/webservices/library/ws-tip-objrel3/index.htmlJob

根据作者的实现,我会让构造函数获取一个参数,并存储它,以便我可以检索它。但是,我根本无法保证此模型可以保持一致。没有将相关客户设置为该工作所不针对的客户,以及向客户添加为其他人完成的作业的重新定义。任何这方面的帮助将不胜感激。JobCustomer


答案 1

没有100%可靠的方法来保持完整性。

通常采用的方法是使用一种方法来构造关系,并在相同的方法中构造另一个方向。但是,正如你所说,这并不能阻止任何人搞砸它。

下一步是使一些方法包可访问,这样至少与你无关的代码不能破坏它:

class Parent {

  private Collection<Child> children;

  //note the default accessibility modifiers
  void addChild(Child) {
    children.add(child);
  }

  void removeChild(Child) {
    children.remove(child);
  }
}

class Child {

   private Parent parent;
   public void setParent(Parent parent){
     if (this.parent != null)
       this.parent.removeChild(this);
     this.parent = parent;
     this.parent.addChild(this);
   }
}

实际上,您通常不会在课堂上对这种关系进行建模。相反,您将在某种存储库中查找父级的所有子级。


答案 2

也许你没有预料到一个复杂的(零代码)答案,但是没有解决方案可以按照你想要的方式构建你的防弹API。这并不是因为范式(OO)或平台(Java),而只是因为你做了错误的分析。在事务性世界中(每个模拟现实生活问题及其随时间演变的系统都是事务性的),这段代码会在某个时候崩溃

// create
Job j1 = ...
Job j2 = ...
...
// modify
j1.doThis();
...

// access
j2.setSomeProperty(j1.someProperty);

因为当时被访问,甚至不能存在:)j1.somePropertyj1j2

TL;DR

对此的长答案是不变性,它还引入了生命周期事务的概念。所有其他答案都告诉你如何做到这一点,相反,我想概述一下为什么。一对多关系有两面性

  1. 有许多
  2. 属于

只要客户有作业,您的系统就是一致的,该作业属于客户。您可以通过多种方式实现这一点,但这必须发生在事务中,即由简单操作组成的复杂操作,并且在事务完成执行之前,系统必须不可用。这是否看起来太抽象,与你的问题无关?不,它不是:)事务系统确保仅当所有这些对象都处于有效状态时,客户端才能访问系统的对象,因此仅当整个系统是一致的。从其他答案中,您可以看到解决某些问题所需的处理量,因此保证是有代价的:性能。这就是为什么Java(和其他通用OO语言)不能开箱即用地解决你的问题的简单解释。ABBA

当然,OO语言既可以用来对事务性世界进行建模,也可以用于访问它,但必须特别小心,必须施加一些约束,并且客户端开发人员需要特殊的编程风格。通常,事务系统提供两个命令:搜索(也称为查询)和锁定。查询的结果是不可变的:它是系统在拍摄时非常具体的时刻的照片(即副本),修改照片显然对现实世界没有影响。如何修改系统?通常

  1. 在需要时锁定系统(或其部分)
  2. 定位对象:返回可在本地读取和写入的真实对象的副本(照片)
  3. 修改本地副本
  4. 提交修改后的对象,即让系统根据提供的输入更新其状态
  5. 放弃对(现在无用的)本地对象的任何引用:系统已更改,因此本地副本不是最新的。

(顺便说一句,您能看到生命周期的概念如何应用于本地和远程对象吗?

你可以使用s,修饰符等,但是在引入事务和不可变性之前,你的设计将有缺陷。通常,Java应用程序由数据库支持,该数据库提供事务功能,并且通常数据库与ORM(例如Hibernate)耦合以编写面向对象的代码。Setfinal