我有一个名为Question的类,它有一个名为Type的属性.基于这种类型,我想以特定的方式将问题呈现给html(多选=单选按钮,多个答案=复选框等...).我开始使用单个RenderHtml方法,根据问题类型调用子方法,但我正在考虑将渲染逻辑分离为实现接口的各个类可能更好.但是,由于这个类使用NHibernate持久化到数据库并且接口实现依赖于属性,我不确定如何最好地布局类.
有问题的课程:
public class Question
{
public Guid ID { get; set; }
public int Number { get; set; }
public QuestionType Type { get; set; }
public string Content { get; set; }
public Section Section { get; set; }
public IList<Answer> Answers { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
基于QuestionType枚举属性,我想呈现以下内容(仅作为示例):
<div>[Content]</div>
<div>
<input type="[Depends on QuestionType property]" /> [Answer Value]
<input type="[Depends on QuestionType property]" /> [Answer Value]
<input type="[Depends on QuestionType property]" /> [Answer Value]
...
</div>
Run Code Online (Sandbox Code Playgroud)
目前,我在一个名为RenderHtml()的函数中有一个大的switch语句,可以完成脏工作,但是我想将它移动到更干净的东西.我只是不确定如何.
有什么想法吗?
编辑:感谢大家的答案!
我最终使用以下界面使用策略模式:
public interface IQuestionRenderer
{
string RenderHtml(Question question);
}
Run Code Online (Sandbox Code Playgroud)
以下实施:
public class MultipleChoiceQuestionRenderer : IQuestionRenderer
{
#region IQuestionRenderer Members
public string RenderHtml(Question question)
{
var wrapper = new HtmlGenericControl("div");
wrapper.ID = question.ID.ToString();
wrapper.Attributes.Add("class", "question-wrapper");
var content = new HtmlGenericControl("div");
content.Attributes.Add("class", "question-content");
content.InnerHtml = question.Content;
wrapper.Controls.Add(content);
var answers = new HtmlGenericControl("div");
answers.Attributes.Add("class", "question-answers");
wrapper.Controls.Add(answers);
foreach (var answer in question.Answers)
{
var answerLabel = new HtmlGenericControl("label");
answerLabel.Attributes.Add("for", answer.ID.ToString());
answers.Controls.Add(answerLabel);
var answerTag = new HtmlInputRadioButton();
answerTag.ID = answer.ID.ToString();
answerTag.Name = question.ID.ToString();
answer.Value = answer.ID.ToString();
answerLabel.Controls.Add(answerTag);
var answerValue = new HtmlGenericControl();
answerValue.InnerHtml = answer.Value + "<br/>";
answerLabel.Controls.Add(answerValue);
}
var stringWriter = new StringWriter();
var htmlWriter = new HtmlTextWriter(stringWriter);
wrapper.RenderControl(htmlWriter);
return stringWriter.ToString();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
修改后的Question类使用内部字典,如下所示:
public class Question
{
private Dictionary<QuestionType, IQuestionRenderer> _renderers = new Dictionary<QuestionType, IQuestionRenderer>
{
{ QuestionType.MultipleChoice, new MultipleChoiceQuestionRenderer() }
};
public Guid ID { get; set; }
public int Number { get; set; }
public QuestionType Type { get; set; }
public string Content { get; set; }
public Section Section { get; set; }
public IList<Answer> Answers { get; set; }
public string RenderHtml()
{
var renderer = _renderers[Type];
return renderer.RenderHtml(this);
}
}
Run Code Online (Sandbox Code Playgroud)
看起来很干净我.:)
这是使用对象继承来实现所需内容的经典案例.每当你看到一个大的switch语句切换对象的类型时,你应该考虑某种形式的子类.
我看到两种方法,取决于这些问题类型的"常见"方式,以及渲染是否是它们之间的唯一区别:
选项1 - 对问题类进行子类化
public class Question
{
public Guid ID { get; set; }
public int Number { get; set; }
public string Content { get; set; }
public Section Section { get; set; }
public IList<Answer> Answers { get; set; }
public virtual string RenderHtml();
}
public class MultipleChoiceQuestion
{
public string RenderHtml() {
// render a radio button
}
}
public class MultipleAnswerQuestion
{
public string RenderHtml() {
// render a radio button
}
}
Run Code Online (Sandbox Code Playgroud)
选项2 - 创建渲染界面,并将其作为问题类的属性
public class Question
{
public Guid ID { get; set; }
public int Number { get; set; }
public string Content { get; set; }
public Section Section { get; set; }
public IList<Answer> Answers { get; set; }
public IRenderer Renderer { get; private set; }
}
public interface IRenderer {
void RenderHtml(Question q);
}
public class MultipleChoiceRenderer : IRenderer
{
public string RenderHtml(Question q) {
// render a radio button
}
}
public class MultipleAnswerRenderer: IRenderer
{
public string RenderHtml(Question q) {
// render checkboxes
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将基于问题类型在构造函数中实例化渲染器.
如果问题类型在多种方式上与呈现不同,则选项1可能更可取.如果渲染是唯一的区别,请考虑选项2.
| 归档时间: |
|
| 查看次数: |
953 次 |
| 最近记录: |