Reputation: 817
I have the following abstract class
public abstract class Document {
private File file;
public Document(File f) {
this.file = f;
}
...
public abstract String parse();
}
Currently, I have two classes that extend Document
, JsonDocument
and XmlDocument
.
In another class, DocumentContent, I have function that iterates through some collection of json and xml files and calls the parse() function to extract certain content.
How can I dynamically instantiate a Document object based on the file extension detected without using a conditional statement? There will be other file extensions added in the future, I want to avoid the need to update DocumentContent every time a new Document class type is created.
Upvotes: 0
Views: 393
Reputation: 10667
I had some similar requirement few years ago and solved it by using combination of Strategy pattern and Simple Factory pattern (NOT factory method pattern)
public class DocumentContent{
Document document;
//other code
}
So now your DocumentContent is composed of Document. This gives you flexibility to dynamically call methods of Document class. I will suggest you better have Document as interface which gets implemented in sub classes. You can instantiate like below :
document = new JsonDocument();
//OR
document = new XmlDocument();
And based on file extension you can instantiate either of classes. You can easily add / remove new Documents without much changes.
Upvotes: 0
Reputation: 30310
A very simple thing to do is to have a DocumentFactory
like so:
public class DocumentFactory {
public static Document createFrom(File f) {
//Produce the right kind of Document based on the File instance
}
}
Use this to create all your Document
s.
Then since each document knows how to parse itself, you can use polymorphism going forward so long as you always reference each with the Document
abstraction:
for (Document document : documents) {
document.parse();
}
Upvotes: 1
Reputation: 133567
You can choose to use reflection or not, without reflection you need to design a builder, something like:
abstract class DocumentBuilder {
public abstract Document build(File file);
}
HashMap<String, Builder> builders = new HashMap<String, Builder>();
builders.put("xml", new Builder(){
public build(File file) { return new XMLDocument(file); }
});
Builder correctBuilder = builders.get("xml");
if (correctBuilder != null)
return correctBuilder.build()
With reflection it would be similar but you will use the newInstance facility given by reflection itself:
HashMap<String, Class<? extends Document>> builders = new HashMap<String, Class<? extends Document>>();
builders.put("xml", XMLDocument.class);
try {
Document document = builders.get("xml").newInstance();
}
catch (...)
Upvotes: 2