Java 使用内部类反映真实事物的关系

Java 使用内部类反映真实事物的关系,java,inner-classes,Java,Inner Classes,这更像是一个概念性的问题。我知道如何做我想做的事。我想知道这样做是否正确 我试图在现实生活中表现一些涉及到筑巢的东西。它是一个指定使用一组项目执行的活动的文档。一个文档可能包含多个项目,每个项目可能有多个活动 因此,层次结构将是文档->项目->活动 我目前的想法是表示一个顶级类Document,它包含一个内部类ItemProgram,它本身包含一个内部类Activity。是的,这是两个层次的筑巢 public class Document { // Properties of the d

这更像是一个概念性的问题。我知道如何做我想做的事。我想知道这样做是否正确

我试图在现实生活中表现一些涉及到筑巢的东西。它是一个指定使用一组项目执行的活动的文档。一个文档可能包含多个项目,每个项目可能有多个活动

因此,层次结构将是文档->项目->活动

我目前的想法是表示一个顶级类Document,它包含一个内部类ItemProgram,它本身包含一个内部类Activity。是的,这是两个层次的筑巢

public class Document {

   // Properties of the document itself

   private Map<Item, ItemProgram> itemPrograms; // Map of item programs

   public class ItemProgram {

      // Properties of the item program itself

      private List<Activity> activities; // List of activities

      public class Activity {
         // Properties of the activity
      }
   }
}
公共类文档{
//文档本身的属性
私有映射itemPrograms;//项程序的映射
公共类项目计划{
//项目程序本身的属性
私有列表活动;//活动列表
公共课堂活动{
//活动的属性
}
}
}
内部类必须是公共的,但我将构造函数设置为私有的,这样它们只能由外部类中的add方法创建。如您所见,我使用集合类型存储实例

这样做对吗?双重嵌套


使用外部类中的集合来存储对内部类的所有实例的引用是否合适?

虽然每个实例都有一种类型,但这种特殊的方法很好,请记住(以及注释中的文档),如果您开始需要多个类型或派生的
文档
Activity
ItemProgram
您很可能需要将此类拆分,以形成更具可伸缩性的模式

如果
文档
包含自己的逻辑,加上创建
活动
实例的逻辑和创建
项目程序
实例的逻辑,则违反SRP(单一责任原则)的指导。这一原则有助于防止横向扩展中出现问题,并防止类爆炸,在这种情况下,您将获得表示组合的类,而不是使用组合模式

我还想说,如果嵌套类的客户机只是父(封闭)类,那么嵌套类是可以的,如果您在其他地方使用它们,我会将其分离出来

编辑综上所述,嵌套类比将它们作为单独的类没有任何好处,至少不会对您正在开发的系统产生积极影响:

  • 隐藏的复杂性,其他开发人员会知道文件包含三个类,而不是他们期望的,一个
  • 访问private时,父母可以访问嵌套的类变量,也可以通过其他方式访问嵌套的类变量,这两种方式都不是预期的,而且很难维护

我可以理解为什么您会尝试使用此结构,但我不会选择它(当然,没有绝对正确/错误的答案)。以下是一些需要考虑的事项:

内部类实例将可以访问其封闭对象的内部状态,这对于您的示例可能不是必需的,并且将使类紧密耦合

以这种方式进行双重嵌套是“不寻常的”,可能会使其他阅读您的代码的人感到困惑

在将来,如果系统的设计发生了变化,并且可以独立于项目(例如)创建活动,那么您必须在代码中执行一些主要的操作

内部类的实例将通过对其父对象的隐式引用创建,您是否真的需要这个额外的引用(父对象已经通过私有集合知道其子对象,它是否必须是一个双向关系,从而增加了一定的复杂性)


您是否考虑过这种设计会如何影响代码的可测试性?如果您想对Activity类进行单元测试,您是否可以这样做,即测试失败肯定表明Activity中存在问题,而不是某个父类中存在问题?

需要双向通信,因为Activity始终需要知道拥有它的ItemProgram,一个ItemProgram需要知道哪个SOR拥有它。所以,如果它们是顶级类,它们需要一个字段来包含这些信息。我会小心这些信息的传播。在程序本身中,
活动
是否确实需要知道拥有它的
项目程序
?或者这是一个数据库需求,如果是这样,那么在序列化对象时,应该在持久性层中完成映射。
ItemProgram
中的列表实际上表达了两者之间的关系。