我正在为一个用 TypeScript 管理调查的程序编写后端,但不知道如何在不违反开放/封闭原则 (OCP) 的情况下设计我的 Survey 和 SurveyRepository 类
我的调查课程是这样的
class Survey {
private readonly metadata: SurveyMetadata
private readonly options: SurveyOptions
private title: string
private description: string
private readonly questions: Question[]
//getter setter
}
class Question {
private readonly metadata: QuestionMetadata
private required: boolean
private question: string
}
现在我有针对每种问题类型的课程
class TextQuestion extends Question {
//just a super call
}
class ChoiceQuestion extends Question {
private answerOptions: AnswerOptions
private isMultiple: boolean
}
现在为了将数据存储在数据库中,我编写了一个存储库类
class SurveyRepository extends IRepositroy {
public insert(survey: Survey): number
}
现在,如果我想将调查插入数据库,我还需要存储问题,因为我需要知道问题的类型,而我知道这样做的唯一方法是这样的:
for(const question of questions){
switch(instanceof question){
case TextQuestion:
//code to store text question
break;
case ChoiceQuestion:
//code to store choice question
break;
}
}
但这违反了 OCP。
我想到的解决方案:
为每种问题类型创建一个存储库是一种选择,但这样调查存储库就没有任何意义
我读到了关于访客模式在这种情况下有效吗?
编辑:
经过更多研究,我在 stackoverflow 上发现了这个问题,但没有得到解答 Stack Overflow
我提出的第一个解决方案是向基本问题添加一个类型字段,并注入一个将问题类型映射到正确问题存储库的映射,但这种方法有一个缺陷:我如何选择,以及如果我使用这个解决方案,稍后我在客户端或控制器上也会遇到同样的问题。
第二种解决方案是只制作一个包含所有问题的问题类 这样做的问题是问题具有不同的属性,所以我会有很多空值,如果我想添加新类型,我需要每次都更改问题类,所以同样的问题。
我想到的第三个解决方案是不继承问题,而是在每个子类型中使用问题实例,但是如何将问题对象存储在调查类中?
我认为解决您问题的方法是使用更面向对象的方式:保留在对象内部保存调查和问题的逻辑,并且不使用存储库。
interface Question {
save(): void;
}
class TextQuestion implements Question {
// constructors and fields
save() {
// logic to save TextQuestion to DB
}
}
class ChoiceQuestion implements Question {
// constructors and fields
save() {
// logic to save ChoiceQuestion to DB
}
}
class Survey {
// constructors and fields
private readonly questions: Question[];
save(): void {
// logic to save data of the Survey to DB
for (let question of this.questions) {
question.save();
}
}
}
// Usage
let cq1 = new ChoiceQuestion(/* some parameters */);
let cq2 = new ChoiceQuestion(/* some parameters */);
let tq1 = new TextQuestion(/* some parameters */);
let survey = new Survey(/* some parameters and questions: cq1, cq2, tq1 */);
survey.save();