Question

Here are two options:

Option 1:

enum QuizCategory {

    CATEGORY_1(new MyCollection<Question>()
                    .add(Question.QUESTION_A)
                    .add(Question.QUESTION_B)
                    .add...),

    CATEGORY_2(new MyCollection<Question>()
                    .add(Question.QUESTION_B)
                    .add(Question.QUESTION_C)
                    .add...), 

    ...

    ;

    public MyCollection<Question> collection;

    private QuizCategory(MyCollection<Question> collection) {
        this.collection = collection;
    }

    public Question getRandom() {
        return collection.getRandomQuestion();
    }

}

Option 2:

enum QuizCategory2 {

    CATEGORY_1 {

        @Override
        protected MyCollection<Question> populateWithQuestions() {
            return new MyCollection<Question>()
                                .add(Question.QUESTION_A)
                                .add(Question.QUESTION_B)
                                .add...;
        }
    },

    CATEGORY_2 {

        @Override
        protected MyCollection<Question> populateWithQuestions() {
            return new MyCollection<Question>()
                                .add(Question.QUESTION_B)
                                .add(Question.QUESTION_C)
                                .add...;
        }
    };

    public Question getRandom() {
        MyCollection<Question> collection = populateWithQuestions();
        return collection.getRandomQuestion();
    }

    protected abstract MyCollection<Question> populateWithQuestions();

}

There will be around 1000 categories, each containing 10 - 300 questions (100 on average). At runtime typically only 10 categories and 30 questions will be used. Each question is itself an enum constant (with its fields and methods).

I'm trying to decide between those two options in the mobile application context. I haven't done any measurements since I have yet to write the questions and would like to gather more information before committing to one or another option. As far as I understand:

(a) Option 1 will perform better since there will be no need to populate the collection and then garbage-collect the questions; (b) Option 1 will require extra memory: 1000 categories x 100 questions x 4 bytes for each reference = 400 Kb, which is not significant.

So I'm leaning to Option 1, but just wondered if I'm correct in my assumptions and not missing something important? Perhaps someone has faced a similar dilemma? Or perhaps it doesn't actually matter that much?

Was it helpful?

Solution

If the differences of two approaches are neither significant in runtime nor in performance (and significant means: from a users point of view, not from an academic point of view), then choose the approach which is easier to implement and to maintain.

Actually, seeing only that small part of your application I cannot tell you which of those two approaches is easier to handle at the long term, but the first impression is that "Option 1" is not just faster, but also seems to need less code (at a first glance). The questions you should ask yourself before making the final decision here are:

  • does your memory extrapolation stick valid for the next months (or years) when the program runs in production?

  • does the list of categories / questions never change during the time your programs runs? (if it can change, there will be obviously a need to reload that objects from somewhere at some point in time)

  • what other operations (besides from getRandom) working with collection will be needed in your program? Are those operations easier to be implemented when you preload everything?

Furthermore, providing an accessor getCollection may be good idea, then you can hide the loading / reloading / lazy loading in the implementation of that accessor and change it later, when needed. So make it

    public Question getRandom() {
        return getCollection().getRandomQuestion();
    }

then you can change your initial decision later more easily.

OTHER TIPS

Is there any particular reason you are loading data you know won't be used? Try to constrain those queries/list loaders to only data you intend to use.

Instead of loading the whole data set first and then filtering, apply the random selection function against an index/key for a dataset, and then load only those particular records with a matching index/key.

If you don't have an index or key to query against, and an index/key can't be added in a long-lived fashion, perform an in-memory dataset transform and add a synthetic or fake key to each, then cache that transformed and keyed data. From there on out, refer to the cached data using the added key, until the cache is invalid.

Licensed under: CC-BY-SA with attribution
scroll top