【问题标题】:How to implement correctly an association in Java OOP code by a given class diagram?如何通过给定的类图正确实现 Java OOP 代码中的关联?
【发布时间】:2016-01-05 14:00:15
【问题描述】:

我很困惑如何在 java 代码中正确实现,关联绘制在 UML 类图上。

假设我们只有两个类(即订单和产品),它们以不同的方式指定关联, 这些关联可以绘制为以下情况 A、B 或 C:

自从我找到了这个答案:https://stackoverflow.com/a/2293760/3248096 谈论(与箭头和导航方向的关联)

我的第一个问题是关于实现 B 与 A 的区别。 在 A 实现上我会写:

public class Order{
     private Set<Product> products; 
}


public class Product{
     private Set<Order> orders; 
}

关于 B 的实现:

public class Order{
     private Set<Product> products; 
}


public class Product{
     //no references properties back to order from here since no back navigability
     ...
}

第二个问题是关于 C 模型的: 通过实现表示从 0 到 4 的有限基数的最佳方法是什么(有吗?)? (产品可能有 0 到 4 个父订单没有多大意义。更多的是理解建模与代码)

public class Product{
     //Array(4) orders...?
}

【问题讨论】:

  • 注意:我不是在问 A 是否比 B 更好。我们选择了 Order Product 作为示例,将它们视为具有关系的两个实体。重点不在于订购尽可能多的产品是否正确,反之亦然。该关系可能表示为A图或B。我想了解的是B实现是否由于添加的箭头而满足B图。
  • 我认为 A 和 B 的意思是一样的,即箭头隐含在 A 中,该订单包含产品。因此,您的第一个实现是错误的(双向引用)。第二个是正确的。关于 C,如果没有更多信息,很难说发生了什么。
  • A 和 B 显然不是同一个意思。如果关联实现为双向关联(如问题中所建议)或单向关联(如 B 中所示),则 A 将其打开。请参阅下面的答案。

标签: java oop uml


【解决方案1】:

一个订单有多个产品,因此将产品集合放入订单似乎是正确的。

另一方面,Product 的一个实例应该只与一个 Order 相关联。可能在多个产品之间共享一种 ProductModel,但是对我来说,一个产品实例应该只链接到一个订单。因此,这里不再需要收集,也不再需要链接,因为我们已经在订单和这些产品之间建立了链接。

所以B的实现似乎没问题。

对于第二个问题,C 实现,您应该有一个具有 4 个插槽的数组或一个无限大小的集合。在这两种情况下,您都必须添加代码来控制添加或删除元素时的状态。例如,在接受添加新产品之前检查订单是否已经没有4个产品,并妥善处理。

【讨论】:

  • 请。请参阅我对我的问题添加的注释。关于 A/B。对不起,如果我不清楚,但这不是重点
  • 图表是正确实现的...但是在现实生活中,我们不会为了娱乐而画那么多图表,图表是通过反映真实的具体情况来绘制的,只有一个应该是真正符合逻辑的到情况。但是,是的,您的代码反映了您的图表;)
  • 我同意你的看法,这只是一个“学术”问题,而不是现实生活。
  • 请注意,这是一种可能的实现方式,但也有其他实现方式。你也可以添加一个类来管理两个对象之间的链接。根据情况(可能取决于开发人员),可以选择一种或其他实现来实现目的
  • “产品”一词对于单个产品和产品类型的使用都含糊不清。这也是问题中 Product 类的预期含义。
【解决方案2】:

关于您的问题C

可以通过这种方式获得固定大小的列表:

public class Order {
     private List<Product> products = Arrays.asList(new Product[4]); 
}

看这个link on ideone看一个例子(请不要介意公共属性,我只是懒得在这个简短的例子中写一个setter方法)。

代码:

import java.util.*;
import java.lang.*;
import java.io.*;

class Product {

}

class Order{
     public List<Product> products = Arrays.asList(new Product[4]); 
}

/* Name of the class has to be "Main" only if the class is public. */
class Main
{
    public static void main (String[] args) throws Exception
    {
        Order o = new Order();
        o.products.set(0, new Product());
        System.out.println(o.products);
        o.products.add(new Product()); // throws UnsuportedOperationException
    }
}

【讨论】:

  • 我明白了,授予它的唯一方法是通过初始化和编写正确的 setter 方法。
  • 关于这一行:private List products = Arrays.asList(new Product[4]);我一直在和我的一位同事讨论,他说最好使用像这样的数组: Product[] products= new Product[2];因为您的解决方案会浪费更多内存。你怎么看?
【解决方案3】:

好的,虽然问多个问题不是很好的风格,但这里是 A/B 的答案。引入可导航性只有很少的语义。它告诉您必须能够沿箭头方向导航。因此,原始类具有关联指向的类的属性。但在大多数情况下,从设计模型中可以明显看出(从实现的方法中)哪一方需要另一方的属性。因此,您可以毫无问题地离开它。

话虽如此,两种实现都从纯粹的“箭头上下文”实现了设计。对private Set&lt;Order&gt; orders; 的需求源于整个系统设计。如果您在 B 案例中离开 private Set&lt;Product&gt; products;,那只会是错误的。

【讨论】:

    【解决方案4】:

    您的模型 A 仅在 OrderProduct 之间指定了多对多关联。它尚未指定如何借助引用属性来实现此关联:作为单向关联还是作为双向关联?

    您的模型 B 可能旨在表达 OrderProduct 之间的单向多对多关联,以引用属性 Order::products 的形式实现。但是请注意,这需要不同的视觉符号,因为 UML 导航箭头没有太多语义(它们不暗示引用属性,但也可以通过关联产品的基于查询的检索方法来处理)。如this post 中所述,您必须将箭头替换为“关联端所有权”点。

    您的模型 C 只是添加了一个上限多重性约束,这意味着您必须阻止用户对同一产品进行五次订购。使用 Java Bean 注解,这个约束可以这样表达:

    @Size(max=4) Set<Product> products;
    

    您可能想在我的book chapter on Associations 中了解更多相关信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多