Статьи

Сделайте ваши фабрики красивыми

ansiktsmask Каждый Java-программист, достойный этого имени, знает о Factory Pattern . Это удобный и стандартизированный способ уменьшить сцепление, научив компонент ловить рыбу, а не отдавать его им. Однако при работе с большими системами шаблон добавляет много стандартного кода в систему. Для каждой сущности вам нужно несколько разных фабрик для производства разных реализаций этой сущности, что утомительно и не нужно писать. Это только один из многих новых паттернов, которые мы стали использовать на Speedment .

Вот типичный пример, когда вы хотите, чтобы автомобильный трейдер мог создавать экземпляры интерфейса Car не зная точной реализации.

Car.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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

1
2
3
4
5
6
7
8
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

1
2
3
4
5
6
7
8
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

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

TeslaFactory.java

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

CarTrader.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
...
        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);
    ...

Одна вещь, которую вы, возможно, еще не заметили, это то, что большинство этих компонентов являются избыточными с Java 8 и выше. Поскольку интерфейс фабрики может рассматриваться как @FunctionalInterface нам не нужны фабрики, мы можем просто указать конструктор реализующих классов в качестве ссылки на метод!

Car.java

1
2
3
4
5
6
7
8
public abstract class Car {
    private final Color color;
 
    @FunctionalInterface
    public interface Factory {
        Car make(Color color);
    }
}

Main.java

1
2
3
4
...
        trader.setSupplier(Volvo::new);
        trader.setSupplier(Tesla::new);
    ...

Обратите внимание, что не требуется никаких изменений для классов реализации Volvo и Tesla . Обе фабрики теперь можно убрать, и у вас останется гораздо более конкретная система!

(Для простых примеров, таких как этот, Factory-интерфейс вообще не нужен. Вы также можете заставить CarTrader использовать Function<Color , Car> . Преимущество указания интерфейса для фабрики состоит в том, что и то, и другое проще понять, и это позволяет изменить параметры конструктора без изменения кода, который использует фабрику.)

Ссылка: Сделайте ваши фабрики красивыми от нашего партнера JCG Эмиля Форслунда из блога Age of Java .