I have the following problem:
Consider we have 3 classes :
Vehicle
Motorcycle
which extends Vehicle
Car
which extends Vehicle
That means that Vehicle
objects can hold both Motorcycle
and Car
objects.
I have one more class named VehicleDatabase
which basically "simulates" a database ( I wish I could use databases but this is an university project) and holds an ArrayList<Vehicle>
field named db
together with some methods that provide some basic operations so I can interact with the database (CRUD operations and some others).
One method I want to implement is the showVehicles()
. To simplify and get to the point of my question let's say that this method must simply print to the console the .toString()
's of all object specified by the function's parameter.
Example:
A menu shows up in the user:
Select which type of vehicles you want to be shown:
1.Motorcycles
2.Cars
Make your choice:
After that our function showVehicles
must take a parameter e.g showVehicles(CarSomething)
and print all the cars stored on the db
ArrayList. I just really can't find an more elegant way to implement that function. Below is my current implementation:
public void showVehicles(Class<?> cls)
{
for(Vehicle v : db)
{
if(v.getClass().equals(cls))
System.out.println(v.toString());
}
}
and invoke it like this : showVehicles(Car.class)
or showVehicles(Motorcycle.class)
.
Is there a better method to do this? Please give your suggestions. I just feel I don't use polymorphism as it should.
Here is one possibility.
I create a Map<Class<?>, List<Vehicle>>
to hold the inventory.
The map was created from a list of vehicles but it could be created by simply adding to the map outright.
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
abstract class Vehicle {
}
class MotorCycle extends Vehicle {
String name;
MotorCycle(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
class Car extends Vehicle {
String name;
Car(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
public class CarMapper {
public static void main(String[] args) {
List<Vehicle> list = new ArrayList<>();
list.add(new MotorCycle("Honda"));
list.add(new MotorCycle("Harley-Davidson"));
list.add(new Car("Ford"));
list.add(new Car("Chrysler"));
Map<Class<?>, List<Vehicle>> inventory = list.stream().collect(
Collectors.groupingBy(Object::getClass));
}
}
Whether this is a reasonable approach or not is up to you (and others who comment). You may still need a map to get the correct class from the user menu.
Map<String, Class<?>> menuMap = new HashMap<>();
menuMap.put("Car", Car.class);
menuMap.put("MotorCycle", MotorCycle.class);
Class<?> lookup = menuMap.get("Car");
for (Vehicle v : inventory.get(lookup)) {
System.out.println(v.toString());
}