代码之家  ›  专栏  ›  技术社区  ›  harriyott Erik Funkenbusch

NHibernate中不同类型答案的问题

  •  2
  • harriyott Erik Funkenbusch  · 技术社区  · 14 年前

    我在试着为一个问卷问题找到一个简洁的解决办法。让我们说我有一个 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> {}
    

    然后问题就来了 类,因为必须提供IAnswer的类型:

    public class Questionnaire
    {
        public virtual ISet<IAnswer<???>> Answers {get;set;}
    }
    

    很明显,我不想有很多不同类型的IAnswer集合。我可以用

    ISet<IAnswer<dynamic>> 
    

    但是尼伯内特不会喜欢的。

    我意识到有些地方需要妥协,但我不确定哪一个最漂亮。你会怎么做?

    3 回复  |  直到 14 年前
        1
  •  4
  •   Community CDub    7 年前

    我认为将问题和答案子类化是一个很好的计划——去掉问题类型enum。

    然后您就可以有一个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));
        }
    }
    

    这样,您的答案可以以自己的方式保存值,并且您可以指定它在数据库中的外观(我建议使用鉴别器进行映射)。您的问题可以负责从一般响应创建答案。

        2
  •  1
  •   Community CDub    7 年前

    有趣的问题。。

    我的意见/想法:

    • 作为 Steve said -把那讨厌的东西扔掉 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 从收藏回来,那 收藏品是什么, 答案 .

        3
  •  -1
  •   Shane Courtrille    14 年前

    将答案存储在完整的数据模型中真的有意义吗?你要拿他们干什么?

    最可能的候选者似乎是报告,在这种情况下,您可能需要研究CQRS(命令查询责任分离)样式。相反,您将有一个QuestionnaireCompletedCommand,它将包含一个答案列表,然后您将以某种方式保留这些答案,以便可以对它们运行报告。

    当您有业务逻辑(您可能有)时,数据模型是很好的,但是如果您没有任何业务逻辑,您可能只是不必要地使解决方案复杂化。说到复杂化,当我说看cqr时,我并不一定是指事件来源部分。这是一个非常复杂的问题,很少有人需要。