我有这样的业务规则:
如果求职者想申请职位空缺,请确保申请中使用的简历已完成,并且求职者没有已申请该职位空缺。如果满足条件,则该应用程序将在JobApplication中编写。
这就是我想到的:
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);
我需要对此有所了解。
谢谢!
在我看来,根据你的操作方式,你有两个聚合根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,$vacation);
在已应用时再次抛出异常。
现在,您可以节省地重新使用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;
}
}
JobSeeker&JobApplication是正确的。JobSeeker.apply方法充当JobApplications:的工厂
job_application = job_seeker.apply(vacancy, resume)
看起来不错。
然而,下面的陈述没有多大意义:
$jobApplication = new JobApplication($jobSeeker, $vacancy, $resume);
考虑到现实世界,你有没有见过一份求职申请凭空出现并落在你的桌子上?我没有:)在大多数情况下,一个实体是从另一个创建的:
employee = company.hire(person)
invoice = employee.create_invoice(customer, invoice_terms)
etc...
如果您在命令处理程序中看到一个实体是"new ed",它应该会引起注意。