Java - 如何避免仅为特定类需要创建setter?

时间:2016-11-15 19:38:41

标签: java oop

我正在使用Hibernate并且当前正在使用setter在创建时设置子节点中父节点的关系(以避免双方手动执行此操作)。我如何避免使用setter或避免将其暴露给其他类并获得相同的行为。使用反射可以吗?这是代码:

@Entity
@Table(name = "TEST_GROUP")
@Getter
public class TestGroupEntity extends AuditedEntity{

    @ManyToOne
    @JoinColumn(name = "owner", nullable = false)
    protected UserEntity owner;

    @Column(name = "description")
    @Setter
    protected String description;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    protected Set<TestEntity> tests = Sets.newHashSet();

    public boolean addTest(TestEntity testEntity) {
        return tests.add(testEntity);
    }

    public boolean removeTest(TestEntity testEntity) {
        return tests.remove(testEntity);
    }

    public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
        this.owner = owner;
        owner.setTestGroupEntity(this); ! how to avoid creation of setter
        this.tests = tests;
        tests.stream().forEach(t -> t.setTestGroupEntity(this));  ! how to avoid creation of setter
    }
}

这是儿童班(我希望在api级别保持不变性):

@MappedSuperclass
@AllArgsConstructor
public class TestEntity extends AuditedEntity {

    @Column(name = "name", nullable = false)
    protected String name;

    @Column(name = "description")
    protected String description;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "test_group", nullable = false)
    protected TestGroupEntity testGroupEntity;

    public void setTestGroupEntity(TestGroupEntity testGroupEntity) {
        this.testGroupEntity = testGroupEntity;
    }
}

编辑:我认为评论的代码部分不可见。遗憾。

2 个答案:

答案 0 :(得分:1)

  

如何避免使用setter或避免将其暴露给其余部分   类和获得相同的行为。可以使用反射吗?

当然,您可以将public setter的可见性降低到低于public的可见性,以便实体的客户端类无法使用它们。
在您的情况下,这是真正的问题,因为无论如何都可以从对象内部访问任何数据

来自hibernate doc

  

无需声明属性(字段或getter / setter)   上市。 Hibernate可以处理用public声明的属性,   受保护,包裹或私人可见性。再次,如果想要使用   运行时代理生成,用于延迟加载的可见性   getter / setter至少应该是包的可见性。

因此,尝试将private setter用于所需的字段。它应该解决你的问题。

评论后更新

您有几种解决方法可以解决您的问题:

  • 使用反射(你的基本想法) 缺点:它带来了一点复杂性,而不是在编译时进行全面检查,最后,看到你代码的人可能想知道你为什么使用它... 任何依赖于反射的概念(如AOP)都是一样的。

  • 将这些setters声明为package-private级别,并将3个类放在同一个package中。
    缺点:使用过的包。

  • 创建public init methods,如果它对同一个对象使用了多次,则会引发异常。通过这种方式,如果使用不当,您可以保证对象的一致性。
    缺点:客户不应使用的方法仍然提供给客户。

不幸的是,由于Java可见性机制无法为您所寻找的内容提供现成的解决方案,因此您没有一个完美的解决方案。
就个人而言,我更喜欢反射或初始化方法解决方案。

就个人而言,我注意到在基础类语言中作为Java,一个优秀的开发人员通常会反复过度保护对象/方法的可访问性。事实上,在许多情况下,它不是必需的,因为它不会破坏应用程序或数据的完整性。

这是一个使用init方法的例子:

 public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
        this.owner = owner;
        owner.constructInit(this); 
        this.tests = tests;
        tests.stream().forEach(t -> t.constructInit(this));  
    }

public class UserEntity {

    private TestGroupEntity testGroupEntity;

    public void constructInit(TestGroupEntity testGroupEntity) {
      if (this.testGroupEntity != null) {
        throw new IllegalArgumentException("forbidden");
      }
      this.testGroupEntity=testGroupEntity;
    }

}

答案 1 :(得分:0)

在父类中创建一个构造函数并从子函数中调用它。

这是父构造函数看起来像

public AuditedEntity(UserEntity owner, Set<TestEntity> tests){
  this.owner = owner;
  this.tests = tests;
}

并改变您的子构造函数,如

public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
   super(owner,tests);

}