I have class structure where
public abstract class AbstractBuilding
implements some non-relevant
interfaces for this question.
public abstract class AbstractAnimalBuilding extends AbstractBuiling
public class AnimalBuildingA extends AbstractAnimalBuilding
public class AnimalBuildingB extends AbstractAnimalBuilding
public class AnimalBuildingC extends AbstractAnimalBuilding
public class AnimalBuildingD extends AbstractAnimalBuilding
In a totally separate class I have the following method:
@FXML
private Button btnAnimalBuildingA;
@FXML
private Button btnAnimalBuildingB;
@FXML
private Button btnAnimalBuildingC;
@FXML
private Button btnAnimalBuildingD;
for (AbstractAnimalBuilding animalBuilding: animalBuildings){
if (animalBuilding instanceof AnimalBuildingA) {
changeButtonDisplay(btnAnimalBuildingA)
} else if (animalBuilding instanceof AnimalBuildingB){
changeButtonDisplay(btnAnimalBuildingB)
} else if (animalBuilding instanceof AnimalBuildingC) {
changeButtonDisplay(btnAnimalBuildingC)
} else if (animalBuilding instanceof AnimalBuildingD){
changeButtonDisplay(btnAnimalBuildingD)
//Do something specific here
}
}
private void changeButtonDisplay(Button buttonToChange){
button.setVisible(true);
}
Where animalBuildings
is a Set<AbstractAnimalBuilding>
containing any combination of AnimalBuildingX
's.
Assuming the structure at the top needs to be kept (eg, AnimalBuildingX
HAS to extend AbstractAnimalBuilding
), what would be a better approach than the multiple if-then-else
statements in determining what kind of building animalBuilding
is?
Would it feasible to simply create a new Interface
as outlined in this question and have each AnimalBuildingX
implement
it while still extending AbstractAnimalBuilding
or is there a way I can do it using the structure I currently have.
This is difficult to answer in general without more context.
One possibility is to create an abstract method in AbstractBuilding
and implement it differently in the subclasses.
Another possibility is to use the visitor pattern.
It depends on the action you want to take on behalf of the derived class type. If an action has to be taken which can be perfomed without the need, that the calling class knows the concrete implementation of AnimalBuilding
the interface method is appropriate. This usually is the case if you can find a common method description which is implemented differently for each concrete class (e.g. getName()
).
If you need to do specific actions dependent on the concrete class (e.g. AnimalBuildingA
differs from AnimalBuldingB
), you can implement the visitor pattern:
public abstract class AbstractAnimalBuilding {
...
public abstract void accept(AnimalBuildingVisitor v);
}
public interface class AnimalBuildingVisitor<T> {
public T visit(AnimalBuildingA a);
public T visit(AnimalBuildingB b);
...
}
The implementation of the accept-method usually is the one liner
return v.visit(this);
Then you create an implementation of the Abstract visitor which does the work you want to perform in the loop. The loop then looks like this
ConcreteAnimalBuildingVisitor v;
for (AbstractAnimalBuilding animalBuilding: animalBuildings)
animalBuilding.accept(v);
This way, the concrete class "identifies" itself to the concrete visior which then can perform the appropriate action.
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