我正在努力为问卷调查问题找到一个整洁的解决方案。我们假设我有一个Questionnaire
类,其中包含Answer
s的集合,例如
public class Questionnaire
{
public virtual ISet<Answer> Answers {get;set;}
}
根据问题,答案需要具有不同类型,例如出生日期,十分标记,为什么你认为等。
我的第一个想法是这样的:
public class Question
{
public virtual QuestionType TypeOfQuestion {get;set;}
public virtual string PromptText {get;set;}
}
public class Answer
{
public virtual Question Question {get;set;}
}
public class DateTimeAnswer : Answer
{
public virtual DateTime Response {get;set;}
}
public class IntegerAnswer : Answer
{
public virtual int Response {get;set;}
}
// etc.
显而易见的问题是,从调查问卷中,无法访问Response
属性:
questionnaire.Answers[0].Response; // compile error
同样适用于界面。使用通用接口会更好,例如:
public interface IAnswer<T>
{
public virtual Question Question {get;set;}
public virtual T Response {get;set;}
}
public class DateTimeAnswer : IAnswer<DateTime> {}
问题出现在Questionnaire
类中,因为必须提供IAnswer的类型:
public class Questionnaire
{
public virtual ISet<IAnswer<???>> Answers {get;set;}
}
显然,我不希望有许多IAnswer的集合,每个集合都有不同的类型。我可以用
ISet<IAnswer<dynamic>>
然后NHibernate不喜欢它。
我意识到某处需要妥协,但我不确定哪个是最漂亮的。你会做什么?
答案 0 :(得分:4)
我认为继承问题和答案是一个很好的计划 - 摆脱那个QuestionType枚举。
然后你可以在Question上有一个MakeAnswer(string)抽象方法,它为你封装了很多逻辑,并且可以在必要时进行类型转换等。
我对Rob's answer上的一般问题的解决方案是这样的:
public interface IAnswer
{
Question Question { get; }
void Respond(IAnswerFormatter formatter);
}
IAnswerFormatter
看起来像这样:
public interface IAnswerFormatter
{
void Format(string value);
void Format(DateTime value);
...
}
DateTimeAnswer看起来像这样:
public class DateTimeAnswer : IAnswer
{
public DateTimeAnswer(Question question, DateTime value)
{
Question = question;
}
public Question Question { get; protected set; }
protected DateTime Response {get; set;}
public virtual void Respond(IAnswerFormatter formatter)
{
formatter.Write(Response);
}
}
DateTimeQuestion可能如下所示:
public class DateTimeQuestion : Question
{
public IAnswer MakeAnswer(string value)
{
// Ignoring error handling here
return new DateTimeAnswer(this, DateTime.Parse(value));
}
}
这样你的答案可以用自己的方式保存值,你的NH映射可以指定它在数据库中的外观(我建议使用Discriminators进行映射)你的问题可以负责从一般的响应中创建答案。 / p>
答案 1 :(得分:1)
有趣的问题..
我的意见/想法:
QuestionType
枚举!ISet<T>
- 我认为它不会增加任何价值.. 我会按照以下方式思考:
public class Questionnaire
{
public AnswerCollection Answers { get; set; }
}
public class AnswerCollection : Collection<Answer>
{
// Subclassed Collection<T> for Add/Remove Semantics etc.
}
public abstract class Answer : IAnswer<object>
{
public override object Response { get { // Base Impl. Here }; }
public abstract string CommonOperation()
{
// This is the key, the "common operation" - likely ToString?
// (for rendering the answer to the screen)
// Hollywood Principle - let the answers figure out how they
// are to be displayed...
}
}
public class DateTimeAnswer : Answer, IAnswer<DateTime>
{
public override DateTime Response { get { // Do Stuff }; }
public override string CommonOperation() { return "I can haz DateTime"; }
}
这个想法就在这里,我们需要了解你对所有对象所做的事情的本质,这可能只是显示答案..我们通过泛型添加类型安全所以我们可以肯定,如果没有类型参数,我们就无法创建新的响应。
然后我们可以非常肯定进出的内容仅限于我们实施的答案类型。 NHIB应该没有解决这个问题的真正问题,因为它知道它需要什么。
虽然很糟糕,我们从集合中回来了object
版本的Answer
, 集合是什么,答案< / em>的
这有帮助吗? :)
答案 2 :(得分:-1)
将答案存储在完整的数据模型中真的有意义吗?你打算和他们一起做什么?
最有可能的候选人似乎是报告,在这种情况下,您可能需要查看CQRS(命令查询责任分离)样式。相反,你会有一个QuestionnaireCompletedCommand,其中包含一个答案列表,然后你会以某种方式持续存在,以便针对它们运行报告。
当您拥有业务逻辑(您可能)时,数据模型很棒,但如果您没有任何业务逻辑,则可能只会使解决方案不必要地复杂化。说到看看CQRS时的复杂性,我不一定是指事件采购部分。这是一个很少人需要的巨大复杂因素。