嗨,我目前正在玩DDD(PHP)项目,并且遇到了以下问题。
假设有一条业务规则规定:成员只能有两个存储段列表。成员对象已在系统中广泛使用。
我的问题是该业务规则放在何处?
选项以及我的想法和关注点:
将其放入应用程序服务中:
由于这是一条业务规则,我认为它应该在域层而不是应用程序层。除非该规则绝对是特定于应用程序的,否则即使如此,我仍然认为它应该在由应用程序服务调用的域服务中使用。
将其放置在Factory中:(域层作为简单工厂或抽象类)
我可以使用规范模式通过查询数据库的实现来检查我的规则,以查看该用户是否已有存储桶列表。工厂的工作是创建对象,因此感觉就像检查规则一样。尽管其他团队成员愿意的话可以绕开工厂,并且不会强制执行此规则。
将其放入域服务中
:该服务将检查规则,然后致电工厂以构建对象。但是再次可以绕过该服务。
将其放在存储库中:(域层作为抽象类)
我可以使用与此处工厂建议的方法相同的方法,但是存储库的工作是使其看起来像一个内存中的集合。在这里检查规则感觉很不对劲,尽管这样可以确保在向集合中添加某些内容时强制执行该规则。
将其放置在实体中:
检查应在对象构造函数或其中调用的setMemberId方法中进行。这样可以确保甚至都无法构造无效对象,这对我来说似乎是最好的情况,但是该实体将依赖于BucketListMustBeUniqueForMemberSpecification,这对我来说是错误的。
将其放在值对象中:
MemberId由系统的许多其他部分使用,因此我不会将其放置在此处,但是我可以制作一个OwnerId值对象并将规则放置在其中,并将memberId-> id()用作构造函数输入。该规则将被强制执行,但同样会与BucketListMustBeUniqueForMemberSpecification产生依赖关系,该依赖关系将注入到构造函数中:/
class SQLBucketListMustBeUniqueForMemberSpecification implements ...
{
public function isSatisfiedBy($memberId)
{
// sql to try to find a bucket list of the members id
return $bucketList ? false : true
}
}
答案 0 :(得分:0)
“一个成员只能有两个存储桶列表”
为什么不将规则放在Member
本身内?除非您期望大量的关联,否则这是保护不变量的简单解决方案。
class Member {
...
final Set<BucketListId> bucketListIds;
public Member(...) {
bucketListIds = new HashSet<BucketListId>();
}
associateBucketLists(Set<BucketListId> bucketListIds) {
if (bucketListIds.size() > 2) throw ...;
bucketListIds.clear();
bucketListIds.addAll(bucketListIds);
}
}
您也可以这样做,以便从BucketList
个文件中创建Member
。
class Member {
int bucketListCount = 0;
public BucketList newBucketList(final BucketListId id, final BucketListDetails details) {
if (bucketListCount == 2) throw ...;
bucketListCount++;
return new BucketList(id, this.id, details);
}
}
class BucketList {
final BucketListId id;
final MemberId ownerId;
}
class MemberApplicationService {
public void newBucketListFor(memberId, ...) {
Member member = memberRepository.memberOfId(memberId);
BucketList bucketList = member.newBucketList(...);
bucketListRepository.add(bucketList);
}
}