I'm wanting to create a class that stores words in a set so that I can see if a word belongs to that set or not. I'm not wanting to build ever set every time I instantiate the class, so I'm using what I think is dependency injection. The following is a basic structure of the class. I'm a student learning about programming so using third party libraries isn't an option.  Is this an appropriate way to hard code my sets? Am I on the right track or should I be designing my class completely different from this?This code is presented to demonstrate if my understanding of class design is correct or not.public final class WordCollection {    private final Set<String> chapter_types = new HashSet<>();    private final Set<String> prepositions = new HashSet<>();    public WordCollection(){        buildChapterTypes();        buildPrepositions();    }    public WordCollection(String collectionType) {        if(collectionType.equals(chapters)) {            buildChapterTypes();        } else if(collectionType.equals(prepositions)) {            buildPrepositions();        }    }    private void buildChapterTypes() {        chapter_types.add(Prologue);        chapter_types.add(Section);        chapter_types.add(Epilogue);        chapter_types.add(Chapter);    }    public boolean isChapterType(String word) {        return chapter_types.contains(word);    }    public void buildPrepositions(){        prepositions.add(of);        prepositions.add(for);    }    public boolean isPreposition(String word) {        return prepositions.contains(word);    }}
How to build a class for comparing words in a lexical dictionary?
java;class design;natural language processing;dictionary
I agree with what Christophe says in his answer.  One thing I can't ignore is your claim to be using dependency injection.  What you're doing is NOT dependency injection at all.  You have your construction code (the build methods) mixed with your behavior code (the is methods).  There is no way to override this construction code.  This makes your code hard to change and hard to test.  Dependency injection says you should ask for what you need, not look for, or build, what you need.But if you want to do, what I think you want to do, your fundamental problem is that you need a different data structure.I have one that will let you do this:public static void main(String[] args) {    WordCollection wc = new WordCollection(new MapOfSetsBuilder()        .add(prologue, chapters)        .add(section, chapters)        .add(epilogue, chapters)        .add(chapter, chapters)        .add(of, prepositions)        .add(for, prepositions)        .add(smurf, chapters, prepositions, articles, verbs, adverbs, nouns)        .build()    );    if (wc.word(prologue).isOfType(chapters)) {        System.out.println(Whoo Hoo!);    }    if (wc.word(smurf).isOfType(nouns)) {        System.out.println(Smurftastic!);    }    if (wc.word(smurf).isOfType(gargamel)) {        System.out.println(Noo! Why? This is so wrong.);    }}Outputs:Whoo Hoo!Smurftastic!The structure? Map<String, Set<String>>I'm mapping each word to it's type.  A word might have more than one type so it maps to a set of types.All you need is this://Construction classclass MapOfSetsBuilder {    Map<String, Set<String>> result = new HashMap<>();    public MapOfSetsBuilder add(String key, String... values) {        Set setForKey = new HashSet<String>();        setForKey.addAll(Arrays.asList(values));        result.put(key, setForKey );        return this;    }    public Map<String, Set<String>> build() {        return result;    }}//Behavior classclass WordCollection {    Map<String, Set<String>> categories;    WordCollection (Map<String, Set<String>> categories){        this.categories = categories;    }    public TypeTest word(String word) {        return new TypeTest(word);    }    class TypeTest {        String word;        TypeTest(String word) {            this.word = word;        }        Boolean isOfType(String category) {            return WordCollection.this.categories.get(word).contains(category);        }    }}I'm not wanting to build ever set every time I instantiate the class ...OK ya lazy bum here's how to do that without shooting proper dependency injection in the face://Behavior classclass WordCollection {    Map<String, Set<String>> categories;    WordCollection(Map<String, Set<String>> categories) {        this.categories = categories;    }    public TypeTest word(String word) {        return new TypeTest(word);    }    class TypeTest {        String word;        TypeTest(String word) {            this.word = word;        }        Boolean isOfType(String category) {            return WordCollection.this.categories.get(word).contains(category);        }    }    public static class Builder {        public WordCollection buildDefault() {            return new WordCollection(new MapOfSetsBuilder()            .add(prologue, chapters)            .add(section, chapters)            .add(epilogue, chapters)            .add(chapter, chapters)            .add(of, prepositions)            .add(for, prepositions)            .add(smurf,chapters,prepositions,articles,verbs,adverbs,nouns)            .build()            );        }    }}Rather than a static factory method that can't be passed around as a reference in true dependency injection fasion I've opted for a static inner builder class.  This is reminiscent of the Josh Bloch builder pattern but is less of a pain because of the MapOfSetsBuilder class helping out. This is invoked with:WordCollection wc = new WordCollection.Builder().buildDefault();Why not a simple static factory method?  Because I'm on a static method hating kick.  I just don't like being forced out of the instance mode when there is no good reason aside for the need for a little more typing.  Anyway, this last bit is not needed for dependency injection. It's just a convenience.  It does nothing you couldn't have done in main and shared around.  The constructor that takes the map is what is supporting dependency injection here.  Done this way at least the WordCollection constructor can still take any stringy map of sets.  Not just this default map.