tags:

views:

205

answers:

5

Hi all,

I am trying to create a class. Let's call it Questionnaire. In Questionnaire, I want to instantiate a number of classes called Question. The constructor for Questionnaire accepts a string array of words, and for each word, there should be a Question class to accept it as an argument for its constructor. In other words, for every string that is passed as an argument, I want to create a Question.

I need to be able to put Questionnaire within a bigger class and still call the methods of the Question classes. The size of the array passed to Questionnaire varies as well. I don't know how I can put multiple classes within another class when I don't know how many classes there will be, and how to reference them from an outer class. If the array was a fixed length I'd just create Questions as question1, question2, question3... but since this is not the case I am not sure anymore. I do know there is a maximum number of Question classes I want to create though.

edit: I'm using J2ME CDLC 1.1 MIDP 2.0 for this (it's part of a mobile phone app) so my solutions are constrained by what it offers.

+2  A: 

You don't want to have a separate variable per question - use a List<Question> to have one variable which refers to a collection of questions:

public class Questionnaire
{
    private final List<Question> questions;

    public Questionnaire(String[] words)
    {
        questions = new ArrayList<Question>();
        for (String word : words)
        {
            questions.add(new Question(word));
        }
    }

    // Use questions here
}

EDIT: If you're in an environment without generics, you could use the non-generic form, like this:

    private final List questions;

    public Questionnaire(String[] words)
    {
        questions = new ArrayList();
        for (String word : words)
        {
            questions.add(new Question(word));
        }
    }

or like this if you don't have List/ArrayList:

    private final Vector questions;

    public Questionnaire(String[] words)
    {
        questions = new Vector();
        for (String word : words)
        {
            questions.add(new Question(word));
        }
    }

In either case you'll need to cast on every access. Alternatively, you could use an array:

    private final Question[] questions;

    public Questionnaire(String[] words)
    {
        questions = new Question[words.length];
        for (int i = 0; i < words.length; i++)
        {
            questions[i] = new Question(word);
        }
    }
Jon Skeet
`questions = new ArrayList<Question>();` perhaps? `List` is an interface after all. Given the `newbie` tag, probably worth specifying the need for `import java.util.*;` (or more specific imports) as well
barrowc
Jon, that's using generics, isn't it? Ugh, I should probably have mentioned I am working with J2ME. I don't think it supports generics.
colig
as colig points oout, you can't instantiate a List
LES2
@barrowc: Doh, fixed. That'll teach me to answer Java questions in the middle of writing a chapter about .NET generic collections :) @colig: In that case, you could use the raw type. Will edit.
Jon Skeet
@colig: I would *strongly* advise that if you're new to Java, learning in J2ME isn't a great idea. I suggest you start off by learning the basics with the desktop framework, and then move onto J2ME. Aside from anything else, it's a lot easier to just experiment without having to worry about emulators etc.
Jon Skeet
Please don't use non-generic java - it's crap. Prefer Collection types (List, Set, etc.) to arrays (this is Josh Bloch's advice in Effective Java, 2nd Edition). You probably want to loosely couple the creation of each Question object to the QUestionnaire class. Otherwise it becauses difficult to add new types of questions. In my example below I've coded some examples using a YesNoQuestion type. You can see how it would be (maybe) easy to add a new question type - say, MultipleChoiceQuestion(String,Choices).
LES2
@LES2: Did you read where the OP said that he's using J2ME, and the bit where I said "if you're in an environment without generics"? I wouldn't be mentioning nongeneric types without good reason...
Jon Skeet
A: 

Why don't you use a List on the questionaire and for each question you add you add one to the List, for example.

public class Questionnaire
{
    public List<Question> myQuestions {get; private set;}

    public Questionnaire(string[] questions)
    {

       myQuestions = new List<Questions>();

       foreach(string q in questions)
       {
          myQuestions.Add(new Question {questionText = g});
       }
    }
}
public class Question
{
    public string questionText {get; set;}
}

Then you will be able to check the questions from outside... this is what you want?

Hope this helps

EDIT: ohh is Java, but you got the idea right?

MRFerocius
As with the other answer above, `List` is an interface so `new List<Questions>();` is incorrect. `List` should be `ArrayList` (or other class which implements the `List` interface and `<Questions>` should be `<Question>`
barrowc
Also the `get; private set;` and `get; set;` parts don't seem to be Java. C# maybe?
barrowc
the poor guy barely knows java and here you are berating him with C#?
LES2
Guys, ideas, concepts, Im showing that, if you need all done go somewhere else...
MRFerocius
A: 
import java.util.*;

public class Questionnaire implements Iterable<Question> {
    private final List<Question> questions;

    public Questionnaire(String ...words) {
       questions = new ArrayList<Question>(words.length);
       for(String word : words) {
           questions.add(new Question(word));
       }
    }

    // allows you to use a Questionnaire object in a for-each loop
    public Iterator<Question> iterator() { return questions.iterator(); }

    @Override
    public String toString() { return questions.toString(); }
}

You could add many more goodies to your class to make it more useful. An example of using the class above follows:

public class QuestionnaireTest {
    public static void main(String[] words) {
        Questionnaire questionnaire = new Questionnaire(words);
        for(Question q : questionnaire) {
            System.out.println("You asked: " + q);
        }
    }
}

You could also use it as follows:

public class QuestionnaireTest3 {
    public static void main(String[] words) {

        // because I declared the constructor to accept "String ...words", I can specify as many questions as I want using simple syntax
        Questionnaire questionnaire = new Questionnaire("How deep the ocean?", "How high the moon?");
        for(Question q : questionnaire) {
            System.out.println("I asked: " + q);
        }
    }
}

Even though I did so in my first example above, you should really accept an array of String objects as questions. Here's a better design:

public class Questionnaire implements Iterable<Question> {
    private List<Question> questions = new ArrayList<Question>();

    public void add(Question q) {
        if(q == null) throw new IllegalArgumentException("can't add null question!");

        questions.add(q);
    }

    public Question get(int index) {
       if(index < 0 || index >= questions.size()) throw new IndexOutOfBoundsException("invalid question index: " + index);

       return questions.get(index);
    }

    // allows you to use a Questionnaire object in a for-each loop
    public Iterator<Question> iterator() { 
        return Collections.unmodifiableList(questions).iterator();
    }

    @Override
    public String toString() { return questions.toString(); }
}

public abstract class Question {
    public String getText();
    public String getAnswer();
    public String getOptions();
    // ...
}

public class YesNoQuestion extends Question {
    private final String text;
    private final String answer;

    public YesNoQuestion(String text, boolean answer) {
       if(!(text.startsWith("Is"))) throw new IllegalArgumentException("Must start with is: " + text);

        this.text = text;

        this.answer = answer ? "Yes" : "No"; // if answer == true, the "Yes",...
    }

     @Override
     public String getText() { return text; }

     public String getAnswer() { return answer; }

     public String getOptions() { return "Yes or No ?"; }
}

And now you can use it as follows:

public class QuestionnaireTest4 {
    public static void main(String[] words) {

        Questionnaire test = new Questionnaire();

        test.add(new YesNoQuestion("Is dogs animals?", false));
        test.add(new YesNoQuestion("Is me has cheezburgers?", true));

        for(Question q : questionnaire) {

            System.out.println(q);
            System.out.println(q.getOptions());

            String input = null; // you need to code this part
            if(q.getAnswer().equals(input))
                System.out.println("CORRECT!");
            else
                System.out.println("YOU IS STUPID!!!!");
        }
    }
}
LES2
Are you talking about {get; set;} on my post and you are showing him an ITERATOR??? COME ON!!!
MRFerocius
LMAO!!!!! Hey - that Iterator trick can make your life more pleasant. It's nice to be able to think about something that is a collection of things as a collection. This way you don't need to actually expose your List to clients. Just give them an add, get method and the Iteratate method. Maybe a numberOfQuestions() too. I'm assuming that the person is going to actually want to build a program with his class. I think I was complaining about non-java code as an answer to a Java question!!!!
LES2
+1  A: 

As J2ME API lacks the Collections API, your best bet is to grab a Vector.

Vector questions = new Vector();
for (int i = 0; i < words.length; i++) {
    questions.addElement(new Question(words[i]));
}
BalusC
A: 

You probably want to go with a Set of questions rather than List. Try :

private final Set<Question> questions;

This will prevent duplicate questions. Everything else will be the same as JonSkeet's answer.

fastcodejava
J2ME doesn't have it either.
BalusC
Ooops, never mind then, didn't the j2me tag.
fastcodejava