需要检查类型时如何不违反开闭原则

问题描述 投票:0回答:1

我正在为一个用 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

我提出的第一个解决方案是向基本问题添加一个类型字段,并注入一个将问题类型映射到正确问题存储库的映射,但这种方法有一个缺陷:我如何选择,以及如果我使用这个解决方案,稍后我在客户端或控制器上也会遇到同样的问题。

第二种解决方案是只制作一个包含所有问题的问题类 这样做的问题是问题具有不同的属性,所以我会有很多空值,如果我想添加新类型,我需要每次都更改问题类,所以同样的问题。

我想到的第三个解决方案是不继承问题,而是在每个子类型中使用问题实例,但是如何将问题对象存储在调查类中?

javascript typescript oop solid-principles open-closed-principle
1个回答
0
投票

我认为解决您问题的方法是使用更面向对象的方式:保留在对象内部保存调查和问题的逻辑,并且不使用存储库。

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();
© www.soinside.com 2019 - 2024. All rights reserved.