Over a million developers have joined DZone.

Make Your Java Factories Beautiful

If you're a Java programmer, you probably are at least familiar with the Factory Pattern. It's a great method for reducing coupling. Here's hot to make your Java Factories beautiful, a necessity when using large systems.

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

Make Your Java Factories Beautiful

Every Java programmer worth the name knows about the Factory Pattern. It is a convenient and standardized way to reduce coupling by teaching a component how to fish rather than giving it to them. When working with large systems, the pattern does, however, add a lot of boilerplate code to the system. For every entity, you need a number of different factories for producing different implementations of that entity, which is both tiresome and unnecessary to write.

Here is a typical example where you want a car trader to be able to create instances of the Car interface without knowing the exact implementation.

Car.java

public abstract class Car {
    private final Color color;

    public interface Factory {
        Car make(Color color);
    }

    protected Car(Color color) {
        this.color = color;
    }

    public abstract String getModel();
    public abstract int getPrice();
}

Volvo.java

public final class Volvo extends Car {
    public Volvo(Color color) {
        super(color);
    }

    public String getModel() { return "Volvo"; }
    public int getPrice() { return 10_000; } // USD
}

Tesla.java

public final class Tesla extends Car {
    public Tesla(Color color) {
        super(color);
    }

    public String getModel() { return "Tesla"; }
    public int getPrice() { return 86_000; } // USD
}

VolvoFactory.java

public final class VolvoFactory implements Car.Factory {
    public Car make(Color color) { return new Volvo(color); }
}

TeslaFactory.java

public final class TeslaFactory implements Car.Factory {
    public Car make(Color color) { return new Tesla(color); }
}

CarTrader.java

public final class CarTrader {

    private Car.Factory factory;
    private int cash;

    public void setSupplier(Car.Factory factory) {
        this.factory = factory;
    }

    public Car buyCar(Color color) {
        final Car car = factory.make(color);
        cash += car.getPrice();
        return car;
    }
}

Main.java

    ...
        final CarTrader trader = new CarTrader();
        trader.setSupplier(new VolvoFactory());
        final Car a = trader.buyCar(Color.BLACK);
        final Car b = trader.buyCar(Color.RED);
        trader.setSupplier(new TeslaFactory());
        final Car c = trader.buyCar(Color.WHITE);
    ...

One thing you might not have noticed yet is that most of these components are redundant from Java 8 and up. Since the factory interface might be considered a @FunctionalInterface we don’t need the factories, we can simply specify the constructor of the implementing classes as a method reference!

Car.java

public abstract class Car {
    private final Color color;

    @FunctionalInterface
    public interface Factory {
        Car make(Color color);
    }
}

Main.java

    ...
        trader.setSupplier(Volvo::new);
        trader.setSupplier(Tesla::new);
    ...

Notice that no changes are needed to the implementing classes Volvo and Tesla. Both the factories can now be removed and you are left with a much more concrete system!

(For simple examples such as this, the Factory interface is not needed at all. You could just as well make CarTrader take a Function<Color, Car>. The advantage of specifying an interface for the factory is that it is both easier to understand and it allows you to change the parameters of the constructor without changing the code that uses the factory).

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
lambda ,stream ,design ,api ,java 8 ,java

Published at DZone with permission of Emil Forslund, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}