ala*_*n-p 8 oop inheritance hibernate seam jpa
这是一个相当冗长(并不过于复杂)的设计问题,所以请耐心等待.我正在尝试使用POJO和JPA实现人员/角色管理系统.我是ORM的新手,这主要是一个映射问题.
我已经将它作为POJO工作,并且对调用者级API感到满意,但现在想在Seam环境中使用JPA或Hibernate将其映射到数据库.
我的实现基于Decorator(GoF)和Person Role Object模式(Baumer/Riehle等人).所有角色都是硬编码的,并且不支持运行时添加新角色,因为它需要更改代码以扩展行为.我将使用用户组来实现安全性和权限.
有一个Person接口,其中包含角色管理方法,如addRole(),removeRole(),hasRole(),getRole(),getRoles()等.具体实现由PersonImpl类提供.
有一个抽象类Role,它还实现了Person接口(用于装饰器替换等价),以及一个扩展它的RoleImpl类.Role类包含对person实例的引用,使用它来为person接口上的任何方法/属性调用提供服务,这意味着Role的所有子类都可以处理Person接口.角色构造函数将person对象作为参数.
这些是接口/类:
public interface Person {
public String getFirstName();
public void setFirstName(String firstName);
.
.
.
public boolean isEnabled();
public void setEnabled(boolean enabled);
public Set<Role> getRoles();
public Role addRole(Class<? extends Role> roleType);
public void removeRole(Class<? extends Role> roleType);
public boolean hasRole(Class<? extends Role> roleType);
public Role getRole(Class<? extends Role> roleType);
public enum Gender {MALE, FEMALE, UNKNOWN};
}
public class PersonImpl implements Person {
.
.
.
}
public abstract class Role implements Person {
protected PersonImpl person;
@Transient
protected abstract String getRoleName();
protected Role() {}
public Role(PersonImpl person) {
this.person = person;
}
public String getFirstName() {
return person.getFirstName();
}
public void setFirstName(String firstName) {
person.setFirstName(firstName);
}
public Set<Role> getRoles() {
return person.getRoles();
}
public Role addRole(Class<? extends Role> roleType) {
return person.addRole(roleType);
}
.
.
.
}
public abstract class RoleImpl extends Role {
private String roleName;
protected RoleImpl() {}
public RoleImpl(PersonImpl person) {
super(person);
}
.
.
.
}
public class Employee extends RoleImpl {
private Date joiningDate;
private Date leavingDate;
private double salary;
public Employee(PersonImpl person) {
super(person);
}
.
.
.
}
Run Code Online (Sandbox Code Playgroud)
此图显示了类关系:
(如果你看不到内联图,可以通过yUML在这里查看)
我会像这样使用这些类:
Person p = new Person("Doe", "John", Person.MALE, ...);
// assuming Employee extends Role
Employee e = (Employee)p.addRole(Employee.class);
Run Code Online (Sandbox Code Playgroud)
由于Role类也实现了Person接口,我也可以这样做:
// assuming Parent extends Role
Parent parent = new Parent((PersonImpl)p);
e.addRole(Parent.class);
e.getDateOfBirth(); // handled by the decorated person class
// assuming Manager extends Employee extends Role
Manager m = (Manager)p.getRole(Manager);
if (m.hasRole(Employee.class) {
// true since Manager derives from Employee
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
(a)这种实施是否不必要地复杂,如果是这样,那么什么是更简单的方法?请注意,这是一个非平凡的业务应用程序而不是kiddy项目,我认为角色子类化对于在Employee,Manager等情况下利用行为很重要.
(b)如何在JPA/Hibernate中映射它?
(c)它是否可以映射,以便我也可以利用Seam身份管理?(我对角色的定义显然与Seam不相似)
(d)如果我使用table-per-subclass(InheritanceType.JOINED)映射策略,我将PersonImpl映射为PERSONS,将RoleImpl映射为ROLES表,并将RoleImpl的每个子类(例如Employee和Parent)映射到它们自己的表中.员工和家长.
然后,我将在PERSONS和ROLES(在PersonImpl中的角色集合上)之间建立@ManyToMany关系,并使用连接表PERSON_ROLES.
现在的问题是EMPLOYEES和PARENTS表等只有ROLE_ID引用,因为继承映射策略显然认为它们是Roles(ROLES)的扩展,而我需要它们作为PERSON_ROLES的附录,并且需要USER_ID + ROLE_ID要正确解析的密钥,或至少是USER_ID.
我更喜欢一个规范化的数据库,伴随着对额外连接的依赖,而不是非规范化的数据库,这将难以维护,并且可能会堆积大量未使用和不相关的字段,这就是为什么我认为每个子类的表是要走的路.
或者是一个每个类的表层次结构(InheritanceType.SINGLE_TABLE),在此场景中带有一个鉴别器列OK(从数据库维护角度来看)?请注意,某些角色可能包含许多属性/字段.
(e)这种设计有更好的替代方案吗?
非常感谢任何想法/建议.
如上所述
所以请耐心等待
所以我的回答将基于你所说的
所有角色都是硬编码的...有一个抽象类角色......
如果有一个AbstractRole类,那么我想在AbstractRole类中定义的一些属性是由所有子类继承的
@Entity
/**
* Which strategy should we use ??? keep reading
*/
@Inheritance
public abstract class AbstractRole implements Serializable {
private Integer id;
private String commonProperty;
private String otherCommonProperty;
private String anotherCommonProperty;
@Id
@GeneratedValue
public Integer getId() {
return this.id;
}
// getter's and setter's
}
Run Code Online (Sandbox Code Playgroud)
现在员工(父母和学生使用相同的方法)
@Entity
public class Employee extends AbstractRole {
private String specificEmployeeProperty;
// getter's and setter's
}
Run Code Online (Sandbox Code Playgroud)
但是使用哪种继承策略?
InheritanceType.JOINED
InheritanceType.SINGLE_TABLE
现在让我们看看
有一个角色管理方法的人,比如addRole(),removeRole(),hasRole(),getRole(),getRoles()等等
好吧,如果我看到类似addRole方法的东西,我认为Person与AbstractOole类有@OneToMany或@ManyToMany关系.我知道,我知道......你有@ManyToMany关系,但我真的建议你将@ManyToMany分成@OneToMany - @ManyToOne关系.看这里如何
@Entity
public class Person implements Serializable {
private Integer id;
private List<AbstractRole> roleList;
@Id
@GeneratedValue
public Integer getId() {
return this.id;
}
@OneToMany
public List<AbstractRole> getRoleList() {
return this.roleList;
}
// getter's and setter's
}
Run Code Online (Sandbox Code Playgroud)
最后
它是否可以映射,因此我也可以利用Seam身份管理
Seam Identity Management 允许您实现自己的行为,无论是否使用JPA.
@Name("authenticationManager")
public class AuthenticationManager {
/**
* Starting with Seam 2.1+, you should use Credentials instead of Identity
* To collect your username and password
*
* Your JSF Form should looks like
*
* <h:inputText value="#{credentials.username}"/>
* <h:inputSecret value="#{credentials.password}"/>
*/
private @In org.jboss.seam.security.Credentials credentials;
/**
* Login method
* must take no arguments
* must return a boolean indicating whether the credentials could be verified
*
* method name does not mind
*/
public boolean authenticate() {
/**
* Logic To verify whether credentials is valid goes here
*/
}
}
Run Code Online (Sandbox Code Playgroud)
并在/WEB-INF/components.xml中定义您的authenticate-method
<security:identity authenticate-method="#{authenticationManager.authenticate}"/>
Run Code Online (Sandbox Code Playgroud)
关于您的映射它取决于业务需求,客户需求等...但我认为它可以更简单,如上所示
祝你好运!
| 归档时间: |
|
| 查看次数: |
6057 次 |
| 最近记录: |