I am attempting to implement my first Factory Design Pattern, and I'm not sure how to avoid using instanceof when adding the factory-made objects to lists. This is what I'm trying to do:
for (Blueprint bp : blueprints) {
Vehicle v = VehicleFactory.buildVehicle(bp);
allVehicles.add(v);
// Can I accomplish this without using 'instanceof'?
if (v instanceof Car) {
cars.add((Car) v);
} else if (v instanceof Boat) {
boats.add((Boat) v);
} else if (v instanceof Plane) {
planes.add((Plane) v);
}
}
From what I've read on Stack Overflow, using 'instanceof' is a code smell. Is there a better way to check the type of vehicle that was created by the factory without using 'instanceof'?
I welcome any feedback/suggestions on my implementation as I'm not even sure if I'm going about this the right way.
Full example below:
import java.util.ArrayList;
class VehicleManager {
public static void main(String[] args) {
ArrayList<Blueprint> blueprints = new ArrayList<Blueprint>();
ArrayList<Vehicle> allVehicles = new ArrayList<Vehicle>();
ArrayList<Car> cars = new ArrayList<Car>();
ArrayList<Boat> boats = new ArrayList<Boat>();
ArrayList<Plane> planes = new ArrayList<Plane>();
/*
* In my application I have to access the blueprints through an API
* b/c they have already been created and stored in a data file.
* I'm creating them here just for example.
*/
Blueprint bp0 = new Blueprint(0);
Blueprint bp1 = new Blueprint(1);
Blueprint bp2 = new Blueprint(2);
blueprints.add(bp0);
blueprints.add(bp1);
blueprints.add(bp2);
for (Blueprint bp : blueprints) {
Vehicle v = VehicleFactory.buildVehicle(bp);
allVehicles.add(v);
// Can I accomplish this without using 'instanceof'?
if (v instanceof Car) {
cars.add((Car) v);
} else if (v instanceof Boat) {
boats.add((Boat) v);
} else if (v instanceof Plane) {
planes.add((Plane) v);
}
}
System.out.println("All Vehicles:");
for (Vehicle v : allVehicles) {
System.out.println("Vehicle: " + v + ", maxSpeed: " + v.maxSpeed);
}
System.out.println("Cars:");
for (Car c : cars) {
System.out.println("Car: " + c + ", numCylinders: " + c.numCylinders);
}
System.out.println("Boats:");
for (Boat b : boats) {
System.out.println("Boat: " + b + ", numRudders: " + b.numRudders);
}
System.out.println("Planes:");
for (Plane p : planes) {
System.out.println("Plane: " + p + ", numPropellers: " + p.numPropellers);
}
}
}
class Vehicle {
double maxSpeed;
Vehicle(double maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
class Car extends Vehicle {
int numCylinders;
Car(double maxSpeed, int numCylinders) {
super(maxSpeed);
this.numCylinders = numCylinders;
}
}
class Boat extends Vehicle {
int numRudders;
Boat(double maxSpeed, int numRudders) {
super(maxSpeed);
this.numRudders = numRudders;
}
}
class Plane extends Vehicle {
int numPropellers;
Plane(double maxSpeed, int numPropellers) {
super(maxSpeed);
this.numPropellers = numPropellers;
}
}
class VehicleFactory {
public static Vehicle buildVehicle(Blueprint blueprint) {
switch (blueprint.type) {
case 0:
return new Car(100.0, 4);
case 1:
return new Boat(65.0, 1);
case 2:
return new Plane(600.0, 2);
default:
return new Vehicle(0.0);
}
}
}
class Blueprint {
int type; // 0 = car; // 1 = boat; // 2 = plane;
Blueprint(int type) {
this.type = type;
}
}
maxSpeed
andnumPropellers
. This is known as information hiding. You can read more on this here : en.wikipedia.org/wiki/Information_hiding. Next, you can define an Enum called VehicleType instead of using numbers such as 0 or 1 to represent a vehicle type. This will make the code more readable. – MarmaraAVehicle
subclass overridetoString()
? Then you could print them all out without worrying about the type. If there's another reason why the caller needs to know the type, let us know and we can make other suggestions. – HampsteadAVehicle
from the programmer using it (keyword encapsulation). Are you sure the factory pattern is the correct design pattern for you? – Gershom