Calling a Method Based on the Object Type

I have two helper methods:

public String load(URL url) {...}
public String load(File file) {...}

      

I want to have a method that calls the appropriate helper method depending on what type of object it receives:

public void operate(Object object) {...}

      

I understand that there is a tricky way to do this:

public void operate(Object object) {
    String data = null;
    if (object.getClass().equals(File.class)) {
        data = load((File) object);
    }
    if (object.getClass().equals(URL.class)) {
        data = load((URL) object);
    }
    // operate on the data....
}

      

However, this doesn't seem elegant and was curious if there was a better way.

+3


source to share


5 answers


A slightly less confusing way instanceof

, for example

if (object instanceof File)) {
    data = load((File) object);
}

      



However, most of the time using instanceof

is a sign of a better structure for what you are trying to achieve, for example

public void operate(File file) {
    operate(load(file));
}

public void operate(URL url) {
    operate(load(url));
}

public void operate(String data) {
    // operate on the data....
}

      

+2


source


However, it doesn't seem graceful and curious if there is a better way.

It is right. This violates the Open-Closed principle. The class must be open for extension, but closed for modification. You are also correct when you say you want a shared object. Here's what you can do:

Create bootloader interface

public interface Loader<T> {
   public String load(T t);
}

      

Create bootloader to load from file

public class FileLoader implements Loader<File> {
     public String load(File f) { 
            //load from file 
     }    
}

      

Create bootloader to boot from Url



public class UrlLoader implements Loader<Url> {
     public String load(URL r) { 
            //load from url 
     }    
}

      

Create a class that works with data

 class DataOperator<T> {
    Loader<T> loader;
    public SomeClient(Loader<T> loader) {
       this.loader = loader;
    }

    public void operate(T inputSource) {
       String data = loader.load(inputSource);
       //operate on the data
    }

 }

      

The client code can then use the above API as shown below:

DataOperator<File> fileDataOperator = new DataOperator<>(new FileLoader());
fileDataOperator.operate(new File("somefile.txt"));

DataOperator<URL> urlDataOperator = new DataOperator<>(new UrlLoader());
urlDataOperator.operate(new URL("http://somesite.com")); 

      

You might be thinking that there are many classes to solve a simple problem. However, this is actually built into the well-known open-close principle. Notice how you control which method is used to load data by instantiating the appropriate class. Another advantage is that you can decide which method to use in runtime

by creating Factory

one that enters the user and creates the appropriate concrete subclass. This is a simplified version of the Strategy .

Disclaimer: The code samples provided above have not been tested for compilation errors as I do not have one on this machine Java

.

+5


source


You can use instanceof and check it and then discard the object and call the method:

if (obj instanceof File) {
   ((File) obj).method();
}
else if (obj instanceof URL) {
   ((URL) obj).method();
}

      

or vice versa:

if (obj instanceof File) {
 load((File) obj)
}
else if (obj instanceof URL) {
   load((URL) obj)
}

      

+3


source


You're right: casting is necessary, but inelegant.

Another way to do this if you like GoF design templates is the visitor template as well as double submission.

The third way is to use Java reflection.

+3


source


Overload the work method as well. Using the data you received to call a method that takes a string.

public static void operate(URL url) {
    String data = load(url);
    doOperations(data);
}

public static void operate(File file) {
    String data = load(file);
    doOperations(data);
}

private static void doOperations(String data) {
    //TODO Do something with data
}

      

+1


source







All Articles