Question

Is it better to use a single factory method and a general constructor for all instances, then populate the instances? OR should multiple factory methods and constructors be used instead? What are the advantages to each approach?

For example (Option #1):

VehicleFactory {
  Vehicle createVehicle(int serialNo);
}

// assuming that Car and Plane are of type Vehicle:

Car car = (Car)VehicleFactory.createVehicle(serialNo1);
car.setCarSpecificField1(...);
car.setCarSpecificField2(...);

Plane plane = (Plane)VehicleFactory.createVehicle(serialNo2);
plane.setPlaneSpecificField1(...);
plane.setPlaneSpecificField2(...);

Here Plane and Car will have a simple general constructor, but would require multiple setters and getters. The caller would have to populate the instances.

Or (Option #2):

VehicleFactory {
  Car createCar(int serialNo, CarSpecificField1 field1, CarSpecificField2 field2, ...)
  Plane createPlane(int serialNo, PlaneSpecificField1 field1, PlaneSpecificField2, ...)
}

Car car = VehicleFactory.createCar(serialNo1, carSpecificField1, ...);
Plane plane = VehicleFactory.createPlane(serialNo2, planeSpecificField1, ...);

Here, we don't need getter and setters but would need different constructors for each instance.

Was it helpful?

Solution

You could do something like this, but keep in mind that inheriting builder methods from a superclass means you must set all car-specific fields first (or do lots of casting).

abstract class Vehicle {
    Object vehicleSpecificField1, vehicleSpecificField2;
}

class Car extends Vehicle {
    Object carSpecificField;

    Car(final Object vehicleSpecificField1, final Object vehicleSpecificField2, final Object carSpecificField) {
        this.vehicleSpecificField1 = vehicleSpecificField1;
        this.vehicleSpecificField2 = vehicleSpecificField2;
        this.carSpecificField = carSpecificField;
    }
}

abstract class VehicleBuilder<E extends Vehicle> {
    Object vehicleSpecificField1, vehicleSpecificField2;

    public VehicleBuilder<E> vehicleSpecificField1(final Object vehicleSpecificField1) {
        this.vehicleSpecificField1 = vehicleSpecificField1;
        return this;
    }

    public VehicleBuilder<E> vehicleSpecificField2(final Object vehicleSpecificField2) {
        this.vehicleSpecificField2 = vehicleSpecificField2;
        return this;
    }

    abstract E create();

}

class CarBuilder extends VehicleBuilder<Car> {
    Object carSpecificField;

    public CarBuilder carSpecificField(final Object carSpecificField) {
        this.carSpecificField = carSpecificField;
        return this;
    }

    @Override
    Car create() {
        return new Car(vehicleSpecificField1, vehicleSpecificField2, carSpecificField);
    }
}

public static void main(String[] args) {
    Car car = new CarBuilder().carSpecificField("car").vehicleSpecificField1("foo").vehicleSpecificField2("bar").create();
}

OTHER TIPS

Here's another way to do it:

VehicleFactory<E extends Vehicle> {
    E getVehicle(int serialNo, VehicleProperty<E> ... args);
}
CarFactory extends VehicleFactory<Car>{
    @Override
    Car getVehicle(int serialNo, VehicleProperty<Car> ... args);
}

VehicleProperty<E extends Vehicle>{ /* getters and setters */}
CarProperty extends VehicleProperty<Car>{}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top