我有一个商业规则,例如:
如果求职者想要申请职位空缺,请确保申请中使用的简历已经完成且求职者没有 已适用于该职位空缺。如果条件满足,那么 该应用程序将以JobApplicatiion编写。
这就是我提出的:
JobSeeker.php
class JobSeeker {
private $applications;
private $resume;
/** Other irrelevant props **/
public function apply(Vacancy $vacancy, Resume $resume) {
// Business rule #1
if(!$resume->isCompleted()) throw new \Exception('Resume '.$resume->getTitle().' is incomplete.');
// Business rule #2
$alreadyApplied = array_filter($this->applications->toArray(), function(JobApplication $application) use($vacancy) {
return $application->getVacancy() === $vacancy;
});
if($alreadyApplied) throw new \Exception('Vacancy '.$vacancy->getTitle().' is already applied');
// If both rules passed, then create a JobApplication
$application = new JobApplication($this, $vacancy, $resume);
$this->applications->add($application);
return $application;
}
}
JobApplication.php
class JobApplication {
private $applicant;
private $vacancy;
private $resume;
public function __construct(JobSeeker $applicant, Vacancy $vacancy, Resume $resume) {
$this->applicant = $applicant;
$this->vacancy = $vacancy;
$this->resume = $resume;
}
}
如果我希望每个人都只使用
$jobApplication = $jobSeeker->apply($vacancy, $jobSeeker->getResume());
然后没问题。
当有人这样做时会出现问题
$jobApplication = new JobApplication($jobSeeker, $vacancy, $resume);
第二个示例将绕过业务规则验证。
我确实将规则检查分为不同的方法:
JobSeeker.php
class JobSeeker {
public function canApply() {
// Here goes those 2 business rules mentioned
}
public function apply(Vacancy $vacancy, Resume $resume) {
if($this->canApply($vacancy, $resume)) {
return new JobApplication($this, $vacancy, $resume);
}
}
}
JobApplication.php
class JobApplication {
public function __construct(JobSeeker $jobSeeker, Vacancy $vacancy, Resume $resume) {
if($jobSeeker->canApply($vacancy, $resume)) {
// Same as before
}
}
}
虽然第二种方法保证了业务规则约束,但它非常冗余,仍然无法提供预期的结果。
$jobApplication = new JobApplication($jobSeeker, $vacancy, $resume);
我需要深入了解这一点。
谢谢!
答案 0 :(得分:2)
根据您的操作方式,我看到它有2个聚合根
JobSeeker
Vacancy
Resume
类似于用户的个人资料
DDD喜欢使用服务,几乎所有东西。
所以我们有JobSeekerApplicaitonService
这项服务将用于外部世界。
在JobSeekerApplicaitonService
我会添加方法apply
public function apply(JobSeeker $jobSeeker, Vacancy $vacancy);
首先,我们检查是否符合业务规则。 即
$jobSeeker->getResume()->isCompleted();
如果未完成,此检查会抛出错误。
接下来,我们在JobSeekerApplicaitonService
创建另一个函数来检查JobSeeker是否已经应用,也可以用于视图,让用户已经看到他已经申请过。
public function hasApplied(JobSeeker $jobSeeker, Vacancy $vacancy);
但是这个方法现在可以在我们的应用函数中使用
$ this-> hasApplied($ jobSeeker,$ vacancy);
在已经应用时再次抛出异常。
您现在可以节省new JobApplication
的费用。虽然我会说JobSeekerApplicaitonService
存储库并在那里创建它,但它保存在数据库中,因为这就是应用程序服务,委托者。
代码
class JobSeekerApplicaitonService {
public function apply(JobSeeker $jobSeeker, Vacancy $vacancy) {
if ($jobSeeker->getResume()->isCompleted()) {
// throw exception
} elseif ($this->hasApplied($jobSeeker, $vacancy)) {
// throw exception
}
// save logic or something else you want
}
public function hasApplied(JobSeeker $jobSeeker, Vacancy $vacancy) {
// your check, I would now use the JobApplicationRepository
return false;
}
}
答案 1 :(得分:0)
JobSeeker& JobApplication是正确的。 JobSeeker.apply方法充当JobApplications的工厂:
job_application = job_seeker.apply(vacancy, resume)
看起来不错。
然而,以下陈述并没有多大意义:
$jobApplication = new JobApplication($jobSeeker, $vacancy, $resume);
考虑到现实世界,你有没有看到JobApplication在你的桌面上随意地随意爆发?我没有:)在大多数情况下,一个实体是从另一个实体创建的:
employee = company.hire(person)
invoice = employee.create_invoice(customer, invoice_terms)
etc...
如果您发现某个实体正在进行新版修改。在命令处理程序中,它应该引起一阵眉毛。