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 object type it receives:
public void operate(Object object) {...}
I understand that there is a convoluted way of doing it which is:
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 does not seem elegant and was curious if there was a better way..
To call an object's method, simply append the method name to an object reference with an intervening '. ' (period), and provide any arguments to the method within enclosing parentheses. If the method does not require any arguments, just use empty parentheses.
The dot ( . ) is used to access the object's attributes and methods. To call a method in Java, write the method name followed by a set of parentheses (), followed by a semicolon ( ; ).
Methods of an object are called to make it do something. Calling a method in an object also makes use of dot notation. The object whose method is being called is on the left side of the dot, and the name of the method and its arguments are on the right side: customer. addToCart(itemNumber, price, quantity);
You have to call with an object. If the method is static the object can be the class.
However, this does not seem elegant and was curious if there was a better way.
That's right. This violates the Open-Closed principle. A class must be open to extension but closed to modification. You are also correct when you say that you need a generic Object. Here's what you can do :
Create a Loader interface
public interface Loader<T> {
public String load(T t);
}
Create a loader for loading from File
public class FileLoader implements Loader<File> {
public String load(File f) {
//load from file
}
}
Create a loader for loading from Url
public class UrlLoader implements Loader<Url> {
public String load(URL r) {
//load from url
}
}
Create a class that operates on the 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
}
}
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 this is a lot of classes for solving a simple problem. However, this is actually inline with the well known Open-Closed design principle. Notice how you control what technique is used for loading the data by creating an instance of an appropriate class. Another advantage you get is that you can decide which technique to use at runtime
by creating a Factory
that takes user input and creates the appropriate concrete subclass. This is a simplified version of the Strategy pattern.
Disclaimer : The code samples presented above have not been tested for compilation errors as I don't have Java
on this machine.
A slightly less convoluted way is instanceof
, e.g.
if (object instanceof File)) {
data = load((File) object);
}
However, most of the time, using instanceof
is a sign that there's a better structure for what you're trying to achieve, e.g.
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....
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With