0

I have a class (let's say Vehicle) with a rather large number of subclasses (Car, Bike, ..). Every subclass stores specific information on the type of the subclass (# of tires, ..).

I want to ensure that all this information is already enforced (at compile-time). So I don't want to specify this data in the constructor of the subclass (because I might forget to set some of them). I could put this info in the constructor of Vehicle, but this would clutter code quite a lot, since I have many of those parameters.

public class Vehicle {
  int numberOfTires;

  public Vehicle(int numberOfTires, ...) {
    ...
  }

}

public class Bike {
  public Bike() {
    super(2,...);
    ...
  }

}

I end up with completely unreadable constructors. It would also store this info per instance, even though it is specific to the subclass.

An alternative way is to introduce abstract static getters/setters and store the info in the subclasses.

public class Vehicle {

  ...
  abstract public int getNumberOfTires();

}

public class Bike {

    static int numberofTires = 2;

    ...

    public int getNumberOfTires() {
      return numberOfTires;
  }

}

This seems way cleaner and also stores the info per subclass and not per instance but there will be a lot of code duplication in the subclasses. Right now, all the subclasses contain ~20 setters/getters but virtually no real functionality. Is there a clean way of avoiding this? Perhaps using the Factory method or alike?

  • You could make the `static` members `public`. –  Jun 19 '14 at 13:12
  • I want to get the info operating on a set of Vehicle not on Bike. – user3756466 Jun 19 '14 at 13:14
  • 2
    I don't understand your comment. What *real* problem are you trying to solve? –  Jun 19 '14 at 13:17
  • 1
    Probably easiest to encapsulate all the parameters into a small class `VehicleParameters` and have that as the constructor argument to `Vehicle`. Having only one constructor will enforce it's correct usage – vikingsteve Jun 19 '14 at 13:27
  • Thanks for the answer and sorry, perhaps my comment was confusing. In the first code snippet I could just make $numberOfTires$ public. But I follow the second snippet in my code now for the reasons explained above. If I have an instance of Bike at hand I could still make $numberOfTires$ public and access it. But if I operate on a set of Vehicle, I only can access the info via the abstract method (or after an ugly checked cast on Bike). – user3756466 Jun 19 '14 at 13:28
  • Good idea, using a seperate class for the parameters should work for me. Thanks! – user3756466 Jun 19 '14 at 13:36
  • Maybe you should read about the "builder" pattern (http://en.wikipedia.org/wiki/Builder_pattern) – Solomon Slow Jun 19 '14 at 14:16

3 Answers3

0

In your shoes, I'd do it this way

public abstract class Vehicle {
    public abstract int getNumberOfTires();
}

and

public class Bike extends Vehicle {

    @Override
    public int getNumberOfTires() {
        return 2;
    }

}

and

public class Car extends Vehicle {

    @Override
    public int getNumberOfTires() {
        return 4;
    }

}
Leo
  • 6,480
  • 4
  • 37
  • 52
0

Seems to me that what you are talking about here are constants, e.g. values that are not supposed to change at runtime. In Java, constants are variables with the following qualifiers: static final, along with private/public. Then, you won't need setters, since a Bike will never anything other than 2 wheels for instance.

I don't really see the problem with having lots of getters and setters, your Bike-class has a set of properties describing it, and they are all needed. So something like:

public abstract class Vehicle {
    public abstract int numberOfTires();
    public abstract boolean hasEngine();
}

public class Bike extends Vehicle {

    private static final int NUMBER_OF_TIRES = 2;
    private static final boolean HAS_ENGINE = false;

    public int numberOfTires() {
        return NUMBER_OF_TIRES;
    }

    public boolean hasEngine() {
        return HAS_ENGINE;
    }
}

These variables are properties of the entity that you are representing, and as per object-oriented principles, they belong as members of the class.

All domain classes will have a number of variables, and in most cases they will require at least a getter, there is no way around this. Still, it is good to keep your domain classes as small as possible, not necessarily with regards to lines of code, concepts it represents. If a domain class has grown large, decompose it and group variables that belong together is separate classes. Then each of the smaller classes will have a constructor with a limited amount of variables, and instance creation

If all that matters in limiting the amount of code in your subclasses you could do something like the code below. I'm not sure if I would recommend it though, and I don't think I'd do this in practice.

public abstract class VehicleInfo {
    public abstract int numberOfWheels();
}

public class BikeInfo extends VehicleInfo {
    @Override
    public int numberOfWheels() {
        return 2;
    }
}

public class CarInfo extends VehicleInfo {
    @Override
    public int numberOfWheels() {
        return 4;
    }
}

public class Vehicle {
    final VehicleInfo info;
    Vehicle(final VehicleInfo info) {
        this.info = info;
    }

    public int numberOfWheels() {
        return info.numberOfWheels();
    }
}

public class Bike extends Vehicle {

    public Bike() {
        super(new BikeInfo());
    }
}

public class Car extends Vehicle {

    public Car() {
        super(new CarInfo());
    }
}

This way all getters are located in the superclass (as well as in the info-classes), and the subclasses can stay clean.

Tobb
  • 11,850
  • 6
  • 52
  • 77
  • Having another class for the parameters is just moving the code, which makes it a little harder to maintain as you double the classes. – Jonathan Drapeau Jun 19 '14 at 13:48
  • Indeed, and I didn't really like that solution, but if the goal is to rid the domain class of as much code as possible it would do the trick. There is nothing wrong with decomposing domain classes into smaller parts though.. I'll update my answer. – Tobb Jun 19 '14 at 19:51
0

You should put in your Vehicule class everything that is common. If the number of tires is a common attribute of all your Vehicule, than it belongs there.

Using the factory pattern you could avoid having to write each time you want a instance of a Bike all that is needed in the Vehicule class as the factory would do that. Meaning the code that sets the parameters of a Bike is written in one place, the BikeFactory class.

That would make the line creating a Bike looks like

Bike yourBike = BikeFactory.getInstance().create();

instead of

Bike yourBike = new Bike(numberOfTires, ... );

The factory would have either a line that looks like the above one or a bunch of calls to setters. I would recommend you use setters and just a new Bike() constructor without parameter.

The naming of the factory, methods and the factory being a singleton are only as example and can be implemented as you see fit in your application.

As mentionned, you could also use another class for the parameters but that only move the hassle of settings your parameters somewhere else.

Community
  • 1
  • 1
Jonathan Drapeau
  • 2,610
  • 2
  • 26
  • 32