По этой теме было написано много постов (в подавляющем большинстве), но я просто хотел поделиться своими двумя центами и написать короткий пост о том, как я использую шаблон создания объектов Fluent или конструкторы объектов в Java для создания экземпляров Value Objects.
Значения Объекты — это абстракции, которые определяются своим состоянием (значением), а не адресом в памяти. Примерами объектов стоимости являются такие вещи, как деньги, число, координата и т. Д. Они используются не для описания бизнес-объектов, а для описания конкретных неделимых сущностей. Кроме того, они являются отличными кандидатами для добавления их в коллекции и карты.
В Java Value Objects должны быть объявлены как final и не предоставлять методов установки, в основном делая их неизменяемыми после создания, это очень важно
требование. Объявление их окончательными делает их неспособными служить родительскими объектами. Это сделано по замыслу, поскольку объекты значения должны моделировать маленькие и конкретные объекты. Причина в том, что мы должны иметь возможность создавать и сравнивать несколько копий этих объектов, что всегда делается по состоянию, а не по ссылке. Кроме того, вы должны объявить надлежащие методы equals () и hashCode (), чтобы претендовать на правильный объект значения. В C ++ применяются те же принципы. В C ++ вы должны использовать конструктор копирования и перегружать операторы присваивания и сравнения. Шаблон Fluent Object Creation делает создание объекта значения элегантным и чистым. Как мы вскоре увидим, использование беглого создания объектов дает много преимуществ.
Конечный результат применения этого шаблона с точки зрения пользователя API будет выглядеть следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
|
Money fiveEuros = new Money.Builder() .currency(Currency.EURO) .value(5.0L) .countryOfOrigin("Spain") .type("Coin") .reverse("Map of Europe") .obverse("Map of Spain") .addColor("Bronze") .addColor("Silver") .year("1880").build(); |
Я думаю, вы согласитесь с тем, что этот шаблон выглядит намного более плавным, чем этот:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
Money fiveEuros = new Money();fiveEuros.setCurrency(Currency.EURO);fiveEuros.setValue(5.0L);fiveEuros.countryOfOrigin("Spain");fiveEuros.type("Coin");fiveEuros.reverse("Map of Europe");fiveEuros.obverse("Map of Spain");List<String> colors = new ArrayList<String>();for(String color: new String[] {"Bronze", "Silver"}) { colors.add(color);}fiveEuros.setColors(colors);fiveEuros.setYear("1880"); |
Который кажется сломанным и имеет много печатания и повторения. На мой взгляд, это пример создания довольно крупного объекта стоимости, большинство из которых, как правило, очень маленькие. Прежде чем мы поговорим о преимуществах создания объектов таким образом, давайте посмотрим на структуру этого шаблона:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
public final class Money { private Long value; private String countryOfOrigin; private Currency currency; private String type; private String reverse; private String obverse; private List<String> colors; private Date year; private Money() { } // -- getters, hashCode, equals -- // // Static inner Builder class public static class Builder { private Money _temp = new Money();public Builder value(Long val) {_temp.value = val;return this;}public Builder countryOfOrigin(String countryOfOrigin) {_temp.contryOfOrigin = countryOfOrigin; return this;}public Builder currency(Currency c) {_temp.currency = c;return this;}public Builder type(String t) {_temp.type = t;return this;}public Builder reverse(String r) {_temp.reverse = r;return this;} public Builder obverse(String o) {_temp.obverse = o;return this;}public Builder addColor(String c) {if(_temp.colors == null) { _temp.colors = new ArrayList<String>(); } _temp.colors.add(c);return this;} public Builder year(String y) { if(y == null || y.isEmpty()) { _temp.year = new Date(); } else { _temp.year = DateFormat.parse(y); }return this;}public Money build() { // Validate object if(Strings.isNullOrEmpty(_temp.name) || _temp.currency == null) { throw new IllegalArgumentException("Coin currency and value required"); }return _temp;} }} |
Это тоже дело вкуса, но я предпочитаю статический подход внутреннего класса . Мне нравится канонический характер обращения к застройщику как
Money.Builder. Требуется также сделать его статическим, поскольку экземпляр компоновщика должен жить независимо от окружающего класса. Мне нравится этот шаблон, потому что он имеет следующие преимущества:
- Большая инкапсуляция объектов: я могу легко навязать конструкцию объекта с помощью компоновщиков, сделав конструктор Money закрытым (это просто стилистически). Это полностью скрывает все тонкости создания этого объекта: создание списка, разбор даты и т. Д. С точки зрения пользователя мы получаем объект, который легко создать. Моя иллюстрация очень простая, но представьте более сложные графы объектов.
- Читаемость кода: использование этого шаблона для создания объектов, делает модульные тесты и код очень легкими для чтения и отслеживания.
- Меньше набора текста в долгосрочной перспективе: несмотря на то, что для каждого добавленного атрибута вам нужно добавить дополнительный метод компоновщика, объем печати, сохраняемый в долгосрочной перспективе, оправдывает себя.
Вывод
Использование беглого паттерна создания — это более сложная работа, но в конечном итоге его преимущества окупаются. Это делает экземпляры объектов очень элегантными и чистыми. Вам не нужно использовать его с объектами-значениями , большинство преимуществ использования Fluent Object Creation заключается в том, что вам нужно строить довольно сложные графы объектов, но я хотел показать, что он также может подойти объекты малого значения.
Ссылка: Свободное создание объектов от нашего партнера JCG Луиса Атенсио в блоге Reflective Thought .