单一责任原则与开盘原则



我正在编写一个程序来向用户显示一组问题,收集他的回答并打印它们。

根据他们需要的响应类型,我有不同类型的问题:整数、布尔值或文本。

我开始编写这段代码:

abstract class Question
{
string text;
}
class IntegerQuestion : Question
{
int response;
}
class TextQuestion : Question
{
string response;
}
class BooleanQuestion : Question
{
bool response;
}

好吧,现在我们必须打印问题和答案。

我的第一个方法是在 Question 类中定义一个新的抽象 Print 函数,以强制子类定义 Print 方法,然后定义一个 Printer 类:

abstract class Question
{
string text;
abstract string Print();
}
class Printer
{
string PrintQuestions(List<Question> questions)
{
string result = "";
foreach(var question in Questions)
result += question.Print() + "rn";
return result;
}
}

我想到的另一种方法是原谅抽象方法并像这样创建 Printer 类:

class Printer
{
string PrintQuestions(List<Question> questions)
{
string result = "";
foreach(var question in Questions)
{
if(question is IntegerQuestion)
{
var integerQuestion = (IntegerQuestion)question;
result += integerQuestion.text + integerQuestion.response;
}
if(question is TextQuestion)
{
...
}
...
}
return result;
}
}

显然,第二种方法不遵循 OCP 打印机类,而是首先执行。

但是,SRP呢?

如果那时我需要用 HTML 编写问题和回复:

abstract class Question
{
string text;
abstract string Print();
abstract string PrintHTML();
}
class HTMLPrinter { ... }

¿问题子类不是违反SRP吗,因为他们知道如何以纯文本和html打印它们?

问题子类是否违反SRP,因为它们知道如何以纯文本和html打印它们

你说得很对。

首先,关于您的命名约定和设计,如果我理解您的演示,为什么答案扩展Question?继承是对象之间的"是"关系。

我们应该说答案就是问题吗?看起来您的业务中有两个不同的概念:

问题
  • 与问题保持
  • 回答,
  • 保留用户对问题的回答

我可能会做类似的事情:(对不起语法,它是某种伪代码(

interface IAnswer{
string toString();
}
class IntegerAnswer implements IAnswer{
int answer;
string toString(){
return (string)this.answer;
}
}
....
class Question{
string text;
IAnswer answer; //or List<IAnswer> answers if you can old more than one answer by Question
string toString(){
return this.text;
}
}

然后,您可以定义一个打印机:

interface IQuestionPrinter{
string print(List<Question> questions);
}
class Printer implements IQuestionPrinter{
string print(List<Question> questions){
string res = '';
foreach(question in questions){
res+=question.toString() + " : " + question.answer.toString();
}
return res;
}
}
class HTMLPrinter implements IQuestionPrinter{
string print(List<Question> questions){
string res = "<ul>";
foreach(question in questions){
res+="<li>";
res+= "<span>" + question.toString() + "</span>";
res+="<span>" + question.answer.toString()+"</span>;
res+="</li>";
}
return res+"</ul>";
}
}

或类似的东西。

然后,您所有的问题和答案都知道他们必须扩展 toString(( 方法,我们将打印工作委托给专用的 IQuestionPrinter。

制作答案界面很好,因为打印机不必知道答案是整数,布尔值还是字符串或其他什么。如果你有其他"类型"的问题,你应该定义一个接口IQuestion:

interface IQuestion{
IAnswer answer; // or List<IAnswer> answers
string toString();
}

然后IQuestionPrinter应该考虑它:

interface IQuestionPrinter{
string print(List<IQuestion> questions);
}

相关内容

  • 没有找到相关文章

最新更新