我正在编写一个程序来向用户显示一组问题,收集他的回答并打印它们。
根据他们需要的响应类型,我有不同类型的问题:整数、布尔值或文本。
我开始编写这段代码:
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);
}