gpt4 book ai didi

Java - 我应该在哪里放置我的域对象逻辑?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:31:48 25 4
gpt4 key购买 nike

我正在开发一个 java-spring 项目,我有一个包gr.serafeim.domain,其中包含我所有的域类(例如,学生、学校等 - 它们是具体类)。所有这些都通过JPA注解在它们之间建立联系。到现在为止一切都很好,但现在我需要为这些需要查询数据库以获取结果的类实现方法。

我应该如何实现这些方法?我的第一选择是将它放在域类中内部,但是为了做到这一点,我需要在所有域类中包含对数据存储库的引用。我不太喜欢这个——这是一个好的设计选择吗?我应该实现我的域类将实现的接口(interface)吗?您能否提出一个更好的解决方案——这种情况下的常见做法是什么?

TIA

最佳答案

我的回答:不,不要将对存储库的引用放入您的域模型中。而是将它们放入业务服务中。并且根本不对域进行任何安全管理。安全性指的是用例,而不是域逻辑,因此安全性置于域之上。

我不同意 Sandhu。我会使用以下架构:

  1. 模型类。他们不会为所有事情获得 getter/setter。这取决于模型逻辑。否则,您将获得可以轻松破坏一致性的模型。或者哪里有很多不明显的东西。假设您有 User.registrationDate 字段。当您构造一个新的 User 对象时,您不应该忘记手动填写 registrationDate 字段。所以,只需将 registrationDate 初始化放在构造函数中并删除 setter!
  2. 模型内部的存储库接口(interface)。假设您有一些业务逻辑依赖于现有的存储对象。您不能从您的域逻辑中明确引用基础架构依赖项,例如 JPA、Hibernate、JDBC 等。因此您可以从接口(interface)查询这些存储的对象。
  3. 商业服务(可选)。它们实现了一些复杂的逻辑,涉及许多不同的实体,不包括安全和事务管理。你的问题是关于它的。是的,如果您需要查询域逻辑中的实体,请将查询放入存储库并从您的业务服务中调用它。
  4. 基础架构包内的存储库实现。使用 JPA 或 mockito 或其他任何东西实现存储库接口(interface)。它们也不包括安全性和交易。
  5. 应用程序服务(可选)。如果与基础设施或安全检查有一些复杂的交互。
  6. 远程外观接口(interface)。客户端和服务器仅通过远程外观接口(interface)进行通信。
  7. 远程外观实现( Controller )。将厚实体对象转换为精简 DTO(数据传输对象)。所有事务划分和安全都在这里(通常使用注释)。

这种方法符合 DDD 风格,由 Martin Fowler 描述。我认为大多数现代项目都使用了 JPA。它不用作持久性提供者,而是用作 Activity 记录。 Active Record 不是领域模型实现模式,而是数据库抽象模式。因此,如果您真的想要事务脚本方法,请使用一些 Activity 记录库或类似 MyBatis 的东西,而不是重量级的 JPA 提供程序。

我也不明白 DAO 的必要性。 JPA 提供者自己进行数据抽象,不是吗?此外,数据抽象不是关于模型,而是关于基础设施。那么为什么将 DAO 置于模型之上呢?如果你真的需要 DAO,你应该把它放在模型下(我想是在存储库实现中)。

正确用法示例:

package my.example.model;

@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String login;
private String password;
@Temporal(TemporalType.TIMESTAMP)
private Date registrationDate;

User() {
// for persistence provider only
}

public User(String login, String password) {
this.login = login;
this.password = hashPassword(password);
this.registrationDate = new Date();
}

public String getLogin() {
return login;
}

public String setPassword(String password) {
this.password = hashPassword(password);
}

public boolean matchPassword(String password) {
return this.password.equals(hashPassword(password));
}

public Date getRegistrationDate() {
return registrationDate;
}

private static String hashPassword(String password) {
try {
MessageDigest digest = MessageDigest.getInstance("sha-1");
StringBuilder sb = new StringBuilder();
byte[] bytes = digest.digest(password.getBytes(charset));
for (byte b : bytes) {
sb.append(Character.forDigit((b >>> 4) & 0xF, 16)).append(Character.forDigit(b & 0xF, 16));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
}

package my.example.model;

public interface UserRepository {
User findByLogin(String login);

User findBySurrogateId(int id);

Integer getSurrogateId(User user);

boolean contains(User user);

void add(User user);

void delete(User user);
}

package my.example.infrastructure;

@Component
public class PersistentUserRepository implements UserRepository {
@PersistenceContext
private EntityManager em;

public void setEntityManager(EntityManager em) {
this.em = em;
}

@Override public User findByLogin(String login) {
// I'd use QueryDSL here
QUser qusr = new QUser("usr");
return new JPAQuery(em)
.from(qusr)
.where(qusr.login.eq(login))
.singleResult(qusr);
}

@Override public User findBySurrogateId(int id) {
return em.find(User.class, id);
}

@Override public Integer getSurrogateId(User user) {
return (Integer)em.getEntityManagerFactory().getPersistenceUnitUtil().getIdentity(user);
}

@Override public boolean contains(User user) {
return em.contains(user);
}

@Override public void add(User user) {
em.persist(user);
}

@Override public void delete(User user) {
em.remove(user);
}
}

package my.example.facade;

public interface UserRemoteFacade {
UserDTO getUser(String login);

UserDTO getUser(int id);

void changePassword(int userId, String newPassword);

void registerUser(String login, String password) throws LoginOccupiedException;

boolean authenticate(String login, String password);
}

package my.example.facade;

public class UserDTO implements Serializable {
private int id;
private String login;
private Date registrationDate;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getLogin() {
return login;
}

public void setLogin(String login) {
this.login = login;
}

public Date getRegistrationDate() {
return registrationDate;
}

public void setRegistrationDate(Date registrationDate) {
this.registrationDate = registrationDate;
}
}

package my.example.server;

@Transactional @Component
public class UserRemoteFacadeImpl imlements UserRemoteFacade {
private UserRepository repository;
private Security security;

@Autowired
public UserRemoteFacadeImpl(UserRepository repository, Security security) {
this.repository = repository;
this.security = security;
}

@Override public UserDTO getUser(String login) {
return mapUser(repository.findByLogin(login));
}

@Override public UserDTO getUser(int id) {
return mapUser(repository.findBySurrogateId(id));
}

private UserDTO mapUser(User user) {
if (user != security.getCurrentUser()) {
security.checkPermission("viewUser");
}
UserDTO dto = new UserDTO();
dto.setId(repository.getSurrogateId(user));
dto.setLogin(user.getLogin());
dto.setRegistrationDate(user.getRegistrationDate());
return dto;
}

@Override public void changePassword(int userId, String newPassword) {
User user = repository.findByLogin(login);
if (user != security.getCurrentUser()) {
security.checkPermission("changePassword");
}
user.setPassword(newPassword);
}

@Override public void registerUser(String login, String password) throws LoginOccupiedException {
if (repository.findByLogin(login) != null) {
throw new LoginOccupiedException(login);
}
User user = new User(login, password);
repository.add(user);
}

@Override public boolean authenticate(String login, String password) throws LoginOccupiedException {
User user = repository.findByLogin(login);
return user != null && user.matchPassword(password);
}
}

另请参阅此项目:http://dddsample.sourceforge.net/

关于Java - 我应该在哪里放置我的域对象逻辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20185808/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com