Reputation: 627
I have an abstract class A
, two sub-classes called B
, C
and two overloaded methods who are in a separate class:
public void process(B objB) {...}
public void process(C objC) {...}
From a repository, I retrieve an entity whose type is A
and I would like to make a call like this:
A objA = repo.findById(id);
process(objA);
I know a cast is required but I don't want to make a lot of checks using the instanceof
or plenty of if
statements.
Which are the best options to implement such a method call? And is it such a code design good?
Upvotes: 1
Views: 1570
Reputation: 1332
Using instanceof
is not good option especially if you have plenty of places where you need to have access to particular subclass.
Obvious approach is to add abstract process()
method without params into base class and implement it in subclasses by calling corresponding process(this)
method from another class and passing this
reference into it.
When it is preferred to divide processing logic from class hierarchy (presumably it is your case) there is a pair of patterns: Strategy or more general Visitor. Here is an example of Visitor pattern usage:
abstract class A {
<T> T accept(Visitor<T> visitor);
}
class B extends A {
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
class C extends A {
@Override
public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this);
}
}
interface Visitor<T> {
T visit(B bObject);
T visit(C cObject);
}
Then define particular operation by implementing corresponsing visitor:
Visitor<Integer> visitor = new Visitor<Integer>() {
@Override
public Integer visit(B bObject) {
// TODO do something with bObject
return null;
}
@Override
public Integer visit(C cObject) {
// TODO do something with cObject
return null;
}
};
and just call accept:
A objA = repo.findById(id);
Integer result = objA.accept(visitor);
Upvotes: 1
Reputation: 217
Using overloaded methods in this instance cannot be done without casting the object first since the program will not call the overloaded method if the explicit object type does not match. So it would not call process(B objB) unless the object you were passing is explicitly of class B.
In order to avoid too much hassle, there are a few ways to do it. Depending on what differentiates between B and C, you can instantiate A as that type when pulling the object from the database (this can be done in the RowMapper) and write an if else statement to determine which process to call:
if(a.getClass() == B.class)
{
return process((B) a);
}
else
{
return process((C) a);
}
Or, if you have more subclasses, you can use a switch statement. That is the simplest way I can think of.
Upvotes: 0