也许最简单的方法是完全删除依赖项,而是引入依赖于其他两个模块的第三个模块。
在您的情况下,您可以将两个解析器合并为一个StudentLessonResolver
位于它自己的模块中,比如说ResolverModule
:
async assign({ lessonId, studentIds }: AssignStudentsToLessonInput) {
await this.studentService.assignLessonToStudents(lessonId, studentIds);
return this.lessonService.assignStudentsToLesson(lessonId, studentIds);
}
So StudentModule
and LessonModule
现在完全独立了,同时ResolverModule
取决于他们两个。不再循环了:)
如果由于某种原因您需要有两个解析器并让它们相互更新,您可以使用事件或回调来发布更改。
然后,您将再次引入第三个模块,该模块侦听这些事件并更新其他模块。
type AssignCallback = (assignStudentsToLesson: AssignStudentsToLessonInput) => Promise<void>;
class LessonResolver { // and similar for StudentResolver
private assignCallbacks: AssignCallback[] = [];
// ... dependencies, constructor etc.
onAssign(callback: AssignCallback) {
assignCallbacks.push(callback);
}
async assignStudentsToLesson(
@Args('assignStudentsToLessonInput')
assignStudentsToLesson: AssignStudentsToLessonInput,
) {
const { lessonId, studentIds } = assignStudentsToLesson;
await this.lessonService.assignStudentsToLesson(lessonId, studentIds); **** A.2 ****
for (const cb of assignCallbacks) {
await cb(assignStudentsToLesson);
}
}
}
// In another module
this.lessonResolver.onAssign(({ lessonId, studentIds }) => {
this.studentService.assignLessonToStudents(lessonId, studentIds);
});
this.studentResolver.onAssign(({ lessonId, studentIds }) => {
this.lessonService.assignStudentsToLesson(lessonId, studentIds);
});
再次,你打破了循环,因为StudentModule
and LessonModule
彼此不了解,而您注册的回调保证调用任一解析器都会导致两个服务都被更新。
如果您使用的是反应式库(例如 RxJS),您应该使用Subject<AssignStudentsToLessonInput>
解析器发布并订阅新引入的模块。
Update
正如OP所建议的,还有其他选择,例如将两个存储库注入到两个服务中。但是,如果每个模块都包含存储库和服务,即如果您导入LessonRepository
and LessonService
from LessonModule
,这不起作用,因为您仍然具有模块级别的循环依赖关系。
但如果学生和课程之间确实有紧密的联系,你也可以将两个模块合并为一个模块,那就没有问题了。
类似的选项是将第一个解决方案的单个解析器更改为直接使用存储库的服务。这是否是一个好的选择取决于管理商店的复杂性。从长远来看,您最好还是选择该服务。
我在单一解析器/服务解决方案中看到的一个优点是,它提供了用于将学生分配到课程的单一解决方案,而在事件解决方案中,studentService.assignLessonToStudents 和lessonService.assignStudentsToLesson 有效地执行完全相同的操作,因此尚不清楚应该使用哪一个。