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.
source to share
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....
}
source to share
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
.
source to share
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)
}
source to share
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
}
source to share