1

There is a hierarchy of questions and answers:

class Answer
{
  int doubtLevel;
}
class YesNoAnswer extends Answer
{
  boolean isYes;
}
class ColorAnswer extends Answer
{
  int red;
  int green;
  int blue;
}

class Question
{
  Context ctx;
  abstract List<? extends Answer> answers;
}
class DoesItWorkQuestion extends Question
{
  Thing it;
  List<YesNoAnswer> answers;
}
class IsItTastyQuestion extends Question
{
  Dish dish;
  List<YesNoAnswer> answers;
}
class FavoriteColorQuestion extends Question
{
  List<ColorAnswer> answers;
}

First of all, I don't like to include list of answers in each concrete class just to fix a answer's type. Is there way to define a structure to keep list of answers outside questions? But answer's type must be fixed for a question.

Then I need to create structures which will hold a value for each answer in a question, e.g. suppose I want have a calculator which calculates probabilities for each answer:

class AnswerProbability<Q extends Question>
{
  Q question;
//??
   double getProbability(???Answer answer){...}
}
class ProbabilityCalculator
{
  //  different params may produce different answer lists 
  //(e.g. if probability of an answer is less than 1%, don't include 
  //the answer in the list).
  AnswerProbability<IsItTastyQuestion> tastyQuestionProbability(String param1, String param2);
  AnswerProbability<FavoriteColorQuestion> favoriteColorQuestion(String param);
...
}
...

and how it could be used:

AnswerProbability<IsItTastyQuestion> prob = calculator.tastyQuestionProbability(...);
// I want the "get" method take only YesNoAnswer type.
println(prob.get(new YesNoAnswer(true, 10) + prob.get(new YesNoAnswer(false, 5));
// or:
for(YesNoAnswer ans : prob.question.answers)
{
  if(ans.isYes)
    println(prob.get(ans));
}
// Also I need work with superclasses
List<AnswerProbability> aps;
aps.add(calculator.calculateTastyQuestionProbability("soup", "mushroom"));
aps.add(calculator.calculateFavoriteColorQuestion("socks"));
..
// use `doubtLevel` from the `Answer` superclass.
for(AnswerProbability ap : aps)
{
  for(Answer a : ap.question.answers)
  {
    if(a.doubtLevel < 5)
      println(ap.get(a));
  }
}

So, I want to avoid type-casts and run-time checks.

kan
  • 28,279
  • 7
  • 71
  • 101

1 Answers1

1

You can't have an abstract field. You can use generics here instead

class Question<A extends Answers> {
  Context ctx;
  final List<A> answers = new ArrayList<A>();
}

class DoesItWorkQuestion extends Question<YesNoAnswer> {
  Thing it;
}

class FavoriteColorQuestion extends Question<ColorAnswer> {
}

However I suspect what would be more useful is to record the count of each answer.

class Question<A extends Answers> {
  Context ctx;
  final Map<A, Integer> answerCounts = new HashMap<>();
}

class DoesItWorkQuestion extends Question<YesNoAnswer> {
  Thing it;
}

class FavoriteColorQuestion extends Question<ColorAnswer> {
}

// later
for(Entry<YesNoAnswer, Integer> ansCount : prob.question.answers.entrySet()) {
    switch(ansCount.getKey()) {
       case YES:
          int count = ansCount.getValue();
          // something
          break;
    }
}

This is more efficient as the size is proportional to the number of possible answers, not the number of answers and calculating probabilities is pretty easy.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130