Tengo una clase llamada Pregunta que tiene una propiedad llamada Tipo. Basado en este tipo, quiero presentar la pregunta a html de una manera específica (opción múltiple = botones de opción, respuesta múltiple = casillas de verificación, etc.). Empecé con un único método RenderHtml que llamaba submétodos según el tipo de pregunta, pero estoy pensando en separar la lógica de representación en clases individuales que implementan una interfaz. Sin embargo, como esta clase se conserva en la base de datos utilizando NHibernate y la implementación de la interfaz depende de una propiedad, no estoy seguro de cómo diseñar la clase.Pregunta de diseño de clase .NET
la clase en cuestión:
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; }
}
Sobre la base de la propiedad QuestionType enumeración, me gustaría hacer el siguiente (es un ejemplo):
<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>
Actualmente, tengo una gran cambiar instrucción en una función llamada RenderHtml() que hace el trabajo sucio, pero me gustaría moverlo a algo más limpio. No estoy seguro de cómo.
¿Alguna idea?
EDIT: Gracias a todos por las respuestas!
Terminé yendo con el patrón de estrategia utilizando la interfaz siguiente:
public interface IQuestionRenderer
{
string RenderHtml(Question question);
}
Y la siguiente implementación:
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
}
La clase de preguntas modificado utiliza un diccionario interno de este modo:
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);
}
}
Parece bastante limpio para mí. :)
Las instrucciones de cambio son muy sucias. El 95 por ciento de las veces hay una mejor manera de hacerlo. –
Esa sería la razón por la que estaba buscando una mejor manera. :) – Chris