我正在撰写一个程序,向用户展示一系列问题,收集他的回复并打印出来。
我有不同类型的问题,具体取决于他们需要的响应类型:整数,布尔值或文本。
我开始编写这段代码:
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() + "\r\n";
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 for Printer类,而是首先进行。
但是,SRP呢?
如果那时我需要用HTML写出问题和答案:
abstract class Question
{
string text;
abstract string Print();
abstract string PrintHTML();
}
class HTMLPrinter { ... }
¿不是问题子类违反SRP,因为他们知道如何以纯文本和HTML格式打印它们吗?
答案 0 :(得分:1)
Aren没有质疑违反SRP的子类,因为他们知道如何以纯文本和html打印它们
你是对的。
首先,根据您的命名惯例和设计,如果我理解您的演示,为什么答案会延伸Question
?继承是一个&#34;是一个&#34;对象之间的关系。
我们应该说答案是个问题吗?您的业务看起来有两个不同的概念:
我可能会做类似的事情:(对不起语法,它是某种伪代码)
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。
制作答案界面是好的,因为打印机不必知道答案是整数,布尔或字符串还是随便。如果你有其他&#34;类型&#34;问题,你应该定义一个界面IQuestion:
interface IQuestion{
IAnswer answer; // or List<IAnswer> answers
string toString();
}
然后IQuestionPrinter应该考虑它:
interface IQuestionPrinter{
string print(List<IQuestion> questions);
}