我有一个不可变的User
实体:
public class User {
final LocalDate lastPasswordChangeDate;
// final id, name, email, etc.
}
如果必须更改用户的密码,我需要添加一个返回信息的方法。它的更改时间不超过passwordValidIntervalInDays
系统设置。
目前的做法:
public class UserPasswordService {
private SettingsRepository settingsRepository;
@Inject
public UserPasswordService(SettingsRepository settingsRepository) {
this.settingsRepository = settingsRepository;
}
public boolean passwordMustBeChanged(User user) {
return user.lastPasswordChangeDate.plusDays(
settingsRepository.get().passwordValidIntervalInDays
).isBefore(LocalDate.now());
}
}
问题是如何使上面的代码更加面向对象并避免贫血域模型反模式?如果将passwordMustBeChanged
方法移至User
,如果如何访问SettingsRepository
,是否应该将其注入User
的构造函数,或Settings
实例是否应该passwordMustBeChanged
是提供给ctor,还是Settings
方法需要提供Settings
实例?
SettingsRepository
和public class Settings {
int passwordValidIntervalInDays;
public Settings(int passwordValidIntervalInDays) {
this.passwordValidIntervalInDays = passwordValidIntervalInDays;
}
}
public class SettingsRepository {
public Settings get() {
// load the settings from the persistent storage
return new Settings(10);
}
}
的代码并不重要,但对于完整性,这里是:
{{1}}
答案 0 :(得分:4)
对于系统范围的密码过期策略,只要您的UserPasswordService
是域服务而不是应用程序服务,您的方法就不会那么糟糕。在用户中嵌入密码到期策略将违反SRP恕我直言,这不是更好。
你也可以考虑类似的东西(工厂用正确的设置初始化):
PasswordExpirationPolicy policy = passwordExpirationPolicyFactory().createDefault();
boolean mustChangePassword = user.passwordMustBeChanged(policy);
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return policy.hasExpired(currentDate, this.lastPasswordChangeDate);
}
如果最终可以为单个用户指定策略,那么您只需将策略对象存储在User
上。
您还可以在当前设计中使用ISP,并在PasswordExpirationPolicy
服务上实施UserPasswordService
界面。这将使您可以灵活地在以后重构为真实的策略对象,而无需更改User
与策略交互的方式。
如果你有一个Password
值对象,你也可以通过类似的东西(密码创建日期将嵌入密码VO)来使事情更具凝聚力:
//class User
public boolean passwordMustBeChanged(PasswordExpirationPolicy policy) {
return this.password.hasExpired(policy);
}
答案 1 :(得分:1)
答案 2 :(得分:0)
我偶然发现了一个文件,提供了我的问题的答案:
应用DDD时的一个常见问题是,当实体需要访问存储库或其他网关中的数据以执行业务操作时。一种解决方案是将存储库依赖项直接注入实体,但这通常是不受欢迎的。这样做的一个原因是因为它要求实现实体的普通旧(C#,Java等)对象成为应用程序依赖图的一部分。另一个原因是,由于违反了单一责任原则,因此对实体行为的推理更加困难。更好的解决方案是让应用程序服务检索实体所需的信息,有效地设置执行环境,并将其提供给实体。
http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/