Это вторая часть моего выступления « Шаблоны проектирования в 21 веке» .
Этот шаблон используется повсеместно в коде Java, особенно в более «корпоративных» кодах. Он включает в себя интерфейс и реализацию. Интерфейс выглядит примерно так:
1
2
3
4
|
public interface Bakery { Pastry bakePastry(Topping topping); Cake bakeCake(); } |
И реализация:
1
2
3
4
5
6
7
8
9
|
public class DanishBakery implements Bakery { @Override public Pastry bakePastry(Topping topping) { return new DanishPastry(topping); } @Override public Cake bakeCake() { return new Aeblekage(); // mmmm, apple cake... } } |
В более общем смысле шаблон абстрактной фабрики обычно реализуется в соответствии с этой структурой.
В этом примере Pastry
и Cake
являются «абстрактными продуктами», а Bakery
— «абстрактными фабриками». Их реализации являются конкретными вариантами.
Это довольно общий пример.
На самом деле, большинство фабрик имеет только один метод «создания».
1
2
3
4
|
@FunctionalInterface public interface Bakery { Pastry bakePastry(Topping topping); } |
О, смотри, это функция.
Этот случай вырождения довольно распространен в паттерне абстрактной фабрики, как и во многих других. В то время как большинство из них предоставляют множество отдельных функциональных возможностей и поэтому имеют множество методов, мы часто склонны разбивать их на типы с одним методом, либо для гибкости, либо потому, что нам просто не нужно больше одного время.
Итак, как бы мы внедрили этого кондитера?
1
2
3
4
5
|
public class DanishBakery implements Bakery { @Override public Pastry apply(Topping topping) { return new DanishPastry(Topping topping); } } |
ОК, конечно, это было легко. Он выглядит так же, как и в предыдущей DanishBakery
за исключением того, что он не может сделать торт. Вкусный яблочный пирог … какой в этом смысл?
Ну, если вы помните, в Bakery
есть один абстрактный метод . Это означает, что это функциональный интерфейс .
Так что же это за функциональный эквивалент?
1
|
Bakery danishBakery = topping -> new DanishPastry(topping); |
Или даже:
1
|
Bakery danishBakery = DanishPastry:: new ; |
Вуаля. Наш класс DanishBakery
исчез.
Но мы можем пойти дальше.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
package java.util.function; /** * Represents a function that * accepts one argument and produces a result. * * @since 1.8 */ @FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. */ R apply(T t); ... } |
Мы можем заменить Bakery
с помощью Function<Topping, Pastry>
; у них одинаковые типы.
1
|
Function<Topping, Pastry> danishBakery = DanishPastry:: new ; |
В этом случае мы можем захотеть сохранить его, так как он имеет имя, относящееся к нашему бизнесу, но часто Factory
объекты не преследуют никакой цели, кроме как помогают нам отделить наш код. ( UserServiceFactory
, кто-нибудь?) Это замечательно, но в таких случаях нам не нужны явные классы для него — в Java 8 встроено множество интерфейсов, таких как Function
, Supplier
и многие другие в java.util.function
пакет, который удовлетворяет нашим потребностям довольно хорошо.
Вот наша обновленная UML-диаграмма:
Aaaaaah. Намного лучше.
Ссылка: | Шаблоны проектирования в XXI веке: абстрактный шаблон фабрики от нашего партнера JCG Самира Талвара в блоге Crafted Software . |