.NET类设计问题 [英] .NET class design question

查看:298
本文介绍了.NET类设计问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为Question的类,它有一个名为Type的属性。基于这种类型,我想以特定的方式将问题呈现给html(多选=单选按钮,多个答案=复选框等)。我开始使用一个单独的RenderHtml方法,根据问题类型调用子方法,但我正在考虑将渲染逻辑分为单个实现接口的类可能会更好。然而,由于此类使用NHibernate持久化到数据库,而接口实现依赖于一个属性,我不知道如何最好地布局类。



类有问题:

  public class Question 
{
public Guid ID {get;组; }
public int Number {get;组; }
public QuestionType Type {get;组; }
public string Content {get;组; }
public Section Section {get;组; }
public IList< Answer>答案{get;组; }
}

根据QuestionType枚举属性,我想呈现以下内容(只是一个例子):

 < div> [Content]< / div> 
< div>
< input type =[取决于QuestionType属性]/> [答案值]
< input type =[取决于QuestionType属性]/> [答案值]
< input type =[取决于QuestionType属性]/> [答案值]
...
< / div>

目前,我在一个名为RenderHtml()的函数中有一个大的switch语句,但我想把它移到更清洁的地方。我只是不知道如何。



任何想法?



编辑:感谢大家答案!



我最终用策略模式使用以下界面:

  public interface IQuestionRenderer 
{
string RenderHtml(Question question);
}

以下实现:

  public class MultipleChoiceQuestionRenderer:IQuestionRenderer 
{
#region IQuestionRenderer成员

公共字符串RenderHtml(问题)
{
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
}

修改后的Question类使用内部字典,如下所示:

  public class Question 
{
private Dictionary< QuestionType ,IQuestionRenderer> _renderers =新词典< QuestionType,IQuestionRenderer>
{
{QuestionType.MultipleChoice,new MultipleChoiceQuestionRenderer()}
};

public Guid ID {get;组; }
public int Number {get;组; }
public QuestionType Type {get;组; }
public string Content {get;组; }
public Section Section {get;组; }
public IList< Answer>答案{get;组;

public string RenderHtml()
{
var renderer = _renderers [Type];
return renderer.RenderHtml(this);
}
}

看起来很干净。 :)

解决方案

你可以使用策略模式


  1. 让您的所有HTML渲染器实现一个公共接口,例如 IQuestionRenderer ,方法名称为 Render(Question)


  2. 在您的应用程序中具有 Dictionary< QuestionType,IQuestionRenderer> 的实例。在初始化时间内填写,可能是基于配置文件。


  3. 对于给定的问题实例,请执行以下操作: renderers [question .Type] .Render(question)


或者,你可以使用名为 RenderXXX 其中XXX是问题类型,并通过反射来调用它们。


I have a class called Question that has a property called Type. Based on this type, I want to render the question to html in a specific way (multiple choice = radio buttons, multiple answer = checkboxes, etc...). I started out with a single RenderHtml method that called sub-methods depending on the question type, but I'm thinking separating out the rendering logic into individual classes that implement an interface might be better. However, as this class is persisted to the database using NHibernate and the interface implementation is dependent on a property, I'm not sure how best to layout the class.

The class in question:

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; }
}

Based on the QuestionType enum property, I'd like to render the following (just an example):

<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>

Currently, I have one big switch statement in a function called RenderHtml() that does the dirty work, but I'd like to move it to something cleaner. I'm just not sure how.

Any thoughts?

EDIT: Thanks to everyone for the answers!

I ended up going with the strategy pattern using the following interface:

public interface IQuestionRenderer
{
    string RenderHtml(Question question);
}

And the following implementation:

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
}

The modified Question class uses an internal dictionary like so:

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);
    }
}

Looks pretty clean to me. :)

解决方案

You can for example use the strategy pattern:

  1. Have all your HTML renderers implement a common interface, for example IQuestionRenderer, with a method name Render(Question).

  2. Have an instance of Dictionary<QuestionType, IQuestionRenderer> in your application. Populate it at initialization time, perhaps based on a configuration file.

  3. For a given instance of a question, do: renderers[question.Type].Render(question)

Or, you could have methods named RenderXXX where XXX is the question type, and invoke them by using reflection.

这篇关于.NET类设计问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆