user10099
user10099

Reputation: 1427

Java - keeping track of object types

Let's say that I have abstract class Car and there are x concrete classes (RedCar, BlueCar ...) that extend class Car. Then I have class Garage that has property Car[] cars.

I want to write a boolean method to class Garage that will loop through the cars and returns true if searched car (one of concrete type (RedCar, BlueCar..) passed as parameter) was found, otherwise returns false.

What is the best way to do it?

For now, I have something like this :

public boolean hasCar(Class<? extends Car> c) {
    for (int i = 0; i < this.cars.length; i++) {
        if (c.isInstance(this.cars[i])) {
            return true;
        }
    }
    return false;
}

but wouldn't it be better if I create an enum with all possible Car types (subclasses of Car), add a property to class Car, which will hold the constant from enum and compare it based on it?

Something like this:

public enum CarType{
    RED_CAR, BLUE_CAR
}

public abstract class Car{
    public CarType type;
    Car(CarType type){
        this.type = type;
    }
}

public class RedCar extends Car{
    public RedCar(){
        super(CarType.RED_CAR);
    }
}

public class BlueCar extends Car{
    public BlueCar(){
        super(CarType.BLUE_CAR);
    }
}

public class Garage{
    private Car[] cars;
    public boolean hasCar(CarType type) {
        for (int i = 0; i < this.cars.length; i++) {
            if(this.cars[i].type == type){
                return true;
            }
        }
        return false;
    }
}

Which one is the better method?

Upvotes: 2

Views: 359

Answers (5)

Lefteris E
Lefteris E

Reputation: 2814

To answer this, I have to ask my self which offers the easiest extensibility? I would say the first implementation.

Upvotes: 0

omer schleifer
omer schleifer

Reputation: 3935

Another approach you could use is passing a filter object and asking the car itself if it matches the filter. the implemntation details of the filter may depend on your real life example (and may even compare by using instanceof()), but in the simplified example you give, it may be a string or an enum specifying the color you are looking for. something like

public class CarFilter()
{
String Color;
}

In the base class of car you have a method:

public boolean matchesFilter(CarFilter filter){} //maybe abstract?

In the derived class RedCar the method maybe implemnted like this:

public boolean matchesFilter(CarFilter filter)
{
 return filter.Color == "red"; //MAYBE case insensitive?
}

Upvotes: 0

BLuFeNiX
BLuFeNiX

Reputation: 2594

The enum solution you posted will only work if you want to confirm that a car of a certain type is found. Not the specific car object itself. Also, if your Car subclasses don't have any difference other than a type variable, you probably don't need subclasses.

The first method looks fine, and may be shortened (a little) like this:

public boolean hasCar(Class<? extends Car> c) {
    for (Car car : this.cars) {
        if (c.isInstance(car) {
            return true;
        }
    }
    return false;
}

Upvotes: 1

Animatinator
Animatinator

Reputation: 410

If you're definitely sticking with having the different colours of car as subtypes, I would say your first version is better - your second will involve updating the enumeration every time you add a new type of car and involves a lot of copy-and-paste style coding for the constructors.

However, I'd recommend that if you want to search the garage for certain colours of car it would make sense to have the colour as a property of the car rather than having to check the car's type. In your second example, the code looks 'cleaner' as you're not using reflection, but you've basically got duplicated information as a car's colour is represented both by its type and by its CarType property. Simply having a single Car type with a Colour value would make this code a lot shorter and neater. Though with this said, I don't know what you ultimately want to do with this so your approach of having subtypes may still be best - take what I say with a pinch of salt.

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 691755

If all the subclasses don't add any state to the base class and don't change or add behavior by adding or overriding methods to/of the base class, then you shouldn't have subclasses. Just having a Car class with a type attribute is sufficient.

If the subclasses have a good reason to exist, then you could indeed use an enum, but that would prevent adding any other type of car (without also changing the enum).

Having a method which searches for a specific type of car looks like a design smell to me. That probably means that the Car class is not sufficiently polymorphic: instanceof and casts are not very OO.

Upvotes: 2

Related Questions