Factory

Factory is a creational design pattern. It is used to delegate the creation of objects to other classes, so that a developer can create an object by calling a single method. Factory pattern encapsulates the creation of objects, so a developer which is using factory doesn’t know how particular object is created and what values of fields it has. In factory we use abstractions, so we create objects of abstraction type, not of specific class. Let’s see an example. We want to create two factories, first one will be producing cars with steering wheel position on the right, let’s call it CommonwealthFactory, and second one will be producing cars with steering wheel position on the left, we’ll call it ContinentalFactory. Let’s create an enum for steering wheel position.

package FactoryTask;

public enum SteeringWheelPosition {
LEFT, RIGHT;
}

Now we need an abstract class of a car, which will have four private fields. The first one will store a value of engine capacity, the second one will store a value of fuel type, the third one will store a value of production year and the fourth one will store a value of steering wheel position which will be our enum. Let’s create also a constructor and getters.

package FactoryTask;

abstract public class Car {
private final float engineCapacity;
private final String fuelType;
private final int productionYear;
private final SteeringWheelPosition steeringWheelPosition;

protected Car(float engineCapacity, String fuelType, int productionYear, SteeringWheelPosition steeringWheelPosition) {
this.engineCapacity = engineCapacity;
this.fuelType = fuelType;
this.productionYear = productionYear;
this.steeringWheelPosition = steeringWheelPosition;
}

public float getEngineCapacity() {
return engineCapacity;
}

public String getFuelType() {
return fuelType;
}

public int getProductionYear() {
return productionYear;
}

public SteeringWheelPosition getSteeringWheelPosition() {
return steeringWheelPosition;
}
}

We need to determine what cars we will be producing, let’s assume that we have contracts with Opel and Toyota. Let’s make a class for Opel which extends our abstract class of a car.

package FactoryTask;

public class Opel extends Car {
Opel(float engineCapacity, String fuelType, int productionYear, SteeringWheelPosition steeringWheelPosition) {
super(engineCapacity, fuelType, productionYear, steeringWheelPosition);
}
}

And the same for Toyota.

package FactoryTask;

public class Toyota extends Car {
Toyota(float engineCapacity, String fuelType, int productionYear, SteeringWheelPosition steeringWheelPosition) {
super(engineCapacity, fuelType, productionYear, steeringWheelPosition);
}
}

For each brand we will be producing two models. Let’s create enums for these models. First for Opel.

package FactoryTask;

public enum OpelModel {
INSIGNIA, VECTRA;
}

And for Toyota.

package FactoryTask;

public enum ToyotaModel {
AVENSIS, AYGO;
}

We need an interface for our factories to implement. Let’s create it with two methods, each of them will return an abstract object of a car. First method will be creating cars for Toyota and second one for Opel. We need to pass an enum to tell method what model should it create.

package FactoryTask;

public interface Factory {
Car createToyota(ToyotaModel toyotaModel);
Car createOpel(OpelModel opelModel);
}

Now it’s time for our two factories. First one will be for our british friends with steering wheel position on the right. Our createToyota and createOpel methods will be very similar, they will be creating particular models with particular values of fields. We use switch statement for this task and when developer passes wrong model we will throw an exception.

package FactoryTask;

public class CommonwealthFactory implements Factory {
SteeringWheelPosition steeringWheelPosition = SteeringWheelPosition.RIGHT;

@Override
public Car createToyota(ToyotaModel toyotaModel) {
switch (toyotaModel) {
case AVENSIS:
return new Toyota(2.0f, "Gas", 2024, steeringWheelPosition);
case AYGO:
return new Toyota(1.0f, "Diesel", 2024, steeringWheelPosition);
default:
throw new UnsupportedOperationException("No such model!");
}
}

@Override
public Car createOpel(OpelModel opelModel) {
switch (opelModel) {
case INSIGNIA:
return new Opel(1.4f, "gas", 2024, steeringWheelPosition);
case VECTRA:
return new Opel(1.8f, "gas", 2024, steeringWheelPosition);
default:
throw new UnsupportedOperationException("No such model!");
}
}
}

And our factory which will be producing cars with steering wheel on the left.

package FactoryTask;

public class ContinentalFactory implements Factory {
SteeringWheelPosition steeringWheelPosition = SteeringWheelPosition.LEFT;

@Override
public Car createToyota(ToyotaModel toyotaModel) {
switch (toyotaModel) {
case AVENSIS:
return new Toyota(2.0f, "Gas", 2024, steeringWheelPosition);
case AYGO:
return new Toyota(1.0f, "Diesel", 2024, steeringWheelPosition);
default:
throw new UnsupportedOperationException("No such model!");
}
}

@Override
public Car createOpel(OpelModel opelModel) {
switch (opelModel) {
case INSIGNIA:
return new Opel(1.4f, "Gas", 2024, steeringWheelPosition);
case VECTRA:
return new Opel(1.6f, "Gas", 2024, steeringWheelPosition);
default:
throw new UnsupportedOperationException("No such model!");
}
}
}

Let’s create a program which will use our factories. First we need to create two factories. Then we create two cars, each of them by calling a method from one of our factory. In the end let’s print the steering wheel position for each of these cars.

import FactoryTask.*;

public class Main {
public static void main(String[] args) {
Factory commonwealthFactory = new CommonwealthFactory();
Factory continentalFactory = new ContinentalFactory();

Car toyotaAvensisRight = commonwealthFactory.createToyota(ToyotaModel.AVENSIS);
Car opelInsigniaLeft = continentalFactory.createOpel(OpelModel.INSIGNIA);

System.out.println(toyotaAvensisRight.getSteeringWheelPosition());
System.out.println(opelInsigniaLeft.getSteeringWheelPosition());
}
}

And when we run this program we get following.

RIGHT
LEFT

Process finished with exit code 0

Everything works as expected.

Leave a Comment

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Scroll to Top