MattM
MattM

Reputation: 817

Java - dynamically instantiate abstract subclass

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

Answers (3)

rai.skumar
rai.skumar

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

Vidya
Vidya

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 Documents.

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

Jack
Jack

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

Related Questions