在提出以下问题之前:rest api and polymorphism
我想知道也许我的整个数据库模式和类结构是错误的。 当前的结构是:
- 人员基础抽象类包含姓名和年龄
- CHILD EXTENDS PERSON 包含最喜欢的电视节目
- PARENT EXTENDS PERSON 包含 child 列表
- GRANDPARENT EXTENDS PERSON 包含 parent 列表
在数据库中,每个子类型的表都组织在表中
我想到也许要重构这些类,因为子类型不会添加任何有值(value)的字段,除了子项/父项列表之外,只有一个类包含所有 字段:
@Entity
class Person{
@ManyToOne
private Person parent; //parent==null is a grandparent
@OneToMany
private List<Person> children;
}
但是,这样做的问题是,在我的业务逻辑中,父子和祖 parent 确实有不同的行为,这样就很难区分 此外,子女 parent 不能是祖 parent 。
另一个问题是,假设我保留当前的类结构
分离类并没有真正帮助我,因为我正在使用服务层
我无法知道我需要哪个服务类别,例如:
class PeopleController extends Controller {
public Result savePerson() {
Person p = objectMapper.readValue.. // deseralizes to correct subtype
// saving logic is different for each subtype, hence I need to
// find correct repository for this subtype but I don't want to use
// instance of or switch case, but to use polymorphism, but can't think
一种没有实现我不想要的 Activity 记录的方法 } }
最佳答案
类型的确定可以完全根据状态确定,并且不需要使用多态性,因为您的问题首先没有提供任何使用它的真正基础。您定义为收集的属性对于所有 Person
来说似乎都是合理的。
父
是包含非空子集的任何人。- 所有
Person
实例均构成一个Child
,但对于本练习,它可能意味着包含空子集的任何人。 GrandParent
是任何作为Parent
的人,但也要求子集中至少有一个实例是Parent
>.
考虑到这一点,我们可以考虑按如下方式重构数据模型。
@Entity
public class Person {
@Id
@GeneratedValue
private Integer id;
private String name;
private Integer age;
// any person can have this, not just children imo :)
private String favoriteShow;
@OneToMany(mappedBy = "parent")
private Set<Person> children;
@ManyToOne
private Person parent;
@Transient
public boolean isChild() {
return children == null || children.isEmpty();
}
@Transient
public boolean isParent() {
return !isChild();
}
@Transient
public boolean isGrandParent() {
return isParent()
&& children.stream().filter( Person::isParent ).count() > 0;
}
}
即使使用这种方法,您的逻辑也可以基于 boolean transient 方法检查进行分支。当然,您可以通过多种方式来优化这些方法,但我不会太担心,因为这些检查已经在 JDK8 上得到了很好的优化。
这里的好处是,您可以简单地拥有一个与 Controller 交互的 Person
服务,并且很可能有一个 Person
存储库,因为数据是作为一种类型对齐的。
我意识到每种类型的保存逻辑都不同,但我的问题是它真的必须不同吗?也许更深入地推理为什么需要拆分这些可以帮助我们提供更多背景信息。
关于java - 多态性和树结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38802725/