5

我有一个表单应该绑定到一个包含很多子对象的复杂对象,每次在加载这个表单之前,我必须在一个只有很多new语句并调用一个setter方法的方法中初始化所有子对象,我必须对许多表单和其他复杂对象重复此场景

有比initializeEmployee方法更好的策略吗?

例如:

@Entity
public class Employee {
    Integer Id;
    Contract contract;
    Name name;
    List<Certificate> list;
    // getter and setters
}

@Entity
public class Contract {
    String telephoneNum;
    String email;
    Address address;
    // getter and setters
}

@Entity
public class Address {
    String streetName;
    String streetNum;
    String city;
}

public class Name {
    String fName;
    String mName;
    String lName;
    // getter and setters
}

// And another class for certificates

public initializeEmployee() {
    Employee emplyee = new Employee();

    Name name = new Name();
    employee.setName(name);

    Contract contract = new Contract();
    Address  address = new Address();
    contract.setAddress(address);
    employee.setContract(contract);

    // set all other employee inner objects, 
}

编辑: 根据以下答案,似乎没有最佳答案。但是,我可以使用实体constructorFactory设计模式。

但是这两种解决方案都没有解决我在使用必填字段和可选字段初始化所有字段策略时的其他问题。

例如:如果我有Name要求(即,如果 Name 对象属性为空,则 Employee 实体将不会持久化,另一方面,Contract实体是可选的。我不能将空Contract对象持久化到数据库中,所以我必须使它null首先在持久化之前,然后在持久化之后重新初始化它,如下所示

// Set Contract to null if its attributes are empty
Contract contract = employee.getContract()
if(contract.getTelephoneNum().isEmpty && contract.getEmail().isEmpty() && contract.getAddress().isEmpty()){
    empolyee.setContract(null);
}

employeeDAO.persist(employee);
// reinitialize the object so it could binded if the the user edit the fields.
employee.setContract(new Contract());
4

4 回答 4

7

You can add constructors (it is their role after all) to your entities to instanciate these fields if having a null value has no meaning for your case.

Another way, if you don't like adding contructors, is to add a static factory method to instanciate your bean which will look like initializeEmployee() but with potential parameters and returning an Employee object. http://en.wikipedia.org/wiki/Factory_method_pattern

Similarly, you can instanciate your collections too, as there is probably no meaning for a null collection (but there is one for an empty collection).

You can add behaviour to your entities, don't be locked in Anemic Domain Model which is considered an anti-pattern by Martin Fowler http://www.martinfowler.com/bliki/AnemicDomainModel.html

EDIT

I see you are using dao.persist(entity): you are probably using JPA. If so, maybe it is best to not modify your object graph (on the front side) and add an EntityListener (in the persistence layer) for Employee: here is a link for Hibernate EntityListener (it is a JPA feature, so if you are using another framework don't worry) http://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html

With an EntityListener, you can add small "aop like" actions before persistence and after. This will allow you to not deal with null values on the domain and front layers and will ensure that every entity fits in any case (better validation).

In PrePersist: you'all add your code to check null values (possibly with custom methods "isEmpty()" on the domain classes) and nullify fields if needed. In PostPersist you add your new object.

于 2013-10-10T12:32:11.980 回答
4

我无法得到你真正需要的东西,但我认为你可以这样尝试:

@Entity
public class Employee {
    Integer Id;
    Contract contract = new Contract();
    Name name = new Name();
    List<Certificate> list;
    // getter and setters
}

@Entity
public class Contract {
    String telephoneNum;
    String email;
    Address address = new Address();
    // getter and setters
}
于 2013-10-15T19:50:12.143 回答
2

我不确定它是否会减少冗长,但由于这是一个 UI 问题,您可以在 flow.xml 中初始化可编辑对象,然后在保存到数据库之前将它们全部放在一个 Employee 实例中。

<on-start>
    <evaluate expression="new foo.bar.Name()" result="flowScope.employeeName" />
    <evaluate expression="new foo.bar.Contract()" result="flowScope.contract" />
    <evaluate expression="new foo.bar.Address()" result="flowScope.address" />
</on-start>
于 2013-10-17T10:21:22.757 回答
1

实际上,我建议不要直接在 GUI 中使用 Hibernate Entities。在许多情况下(我也假设在您的情况下,但我缺少有关您的用例的一些细节),改用数据传输对象模式很有用。您可以创建这样的 DTO,它是特定于 GUI 的,只有您需要的那些字段,并且结构只是根据需要而复杂。

在特定的用户操作(例如保存)之后,使用那些 DTO(在事件处理上)来创建将被持久化的实体。

除非您的情况是仅进入 GUI 屏幕会导致创建实体,否则我会推荐工厂模式。

另请注意,在许多情况下,构成主对象的组件对象(在您的示例中为 Employee)的初始化最好在主对象的构造函数中初始化,例如。如果您希望 Contract 不能为 null - 在构造函数中对其进行初始化。证书列表和其他列表相同。

于 2013-10-16T16:10:08.840 回答