Про паттерни та контекст
Шаблони/паттерни — елементи, що можна перевикористати, але при цьому вони недостатньо прості, щоб їх можна було реалізувати на рівні мови програмування чи бібліотеки. Часте визначення, але воно не дає однозначності. Інше визначення: типове рішення (певної типової) проблеми. Вже краще, але не пояснює різницю паттерну від тактики, архітектурного стилю чи тієї ж бібліотечної функції. Тут нам може допомогти спосіб опису шаблонів (як пропонує те ж SEI) — контекст, проблема, рішення. Часто контекст неявно включають в проблему. А ще частіше фокусуються на рішенні, лише побічно згадуючи проблему та ігноруючи контекст.
Розглянемо простий Java клас.
public class Person {
private String firstName;
private String lastName;
public Person() {
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName() {
return firstName + " " + lastName;
}
}
Цей клас виглядає як DTO, Value object, Java bean, а з незначними модифікаціями (додавання унікального ідентифікатора) може бути й Entity. І не лише виглядає, а і може мати різні назви для паттерну, що вирішує ту ж проблеми, і так було 20+ років тому, див. Note 2013-08-11.
В чому ж різниця в реалізації DTO та Value object? Value object скоріше за все буде іммутабельним, але не обов’язково. DTO теж може бути іммутабельним. Обидва мали б мати методи equals/hashCode, яких не було в прикладі лише для економії місця. Можемо сказати, що обчислюваного метода getFullName у DTO не мало б бути на відміну від Value object, але ця “заборона” не є обов’язковою, і скоріше неявно може витікати з проблеми, яку вирішує DTO — передача даних між процесами. Саме “процеси” були початковим контекстом для появи цього паттерну. З часом цей контекст еволюціонував в “передачу даних між браузером та бекендом” чи “передачу даних між системами”. І цей контекст дасть нам ще одну неявну вимогу — об’єкт має бути серіалізованим. Хоча якщо подивитись в глибину, то не має, бо може бути зовнішній клас, що серіалізує наш DTO для передачі по мережі (насправді таке рішення буде навіть гнучкіше). Десь років 8-10 тому бачив підхід де DTO взагалі використовувались для передачі даних між шарами в 3-шаровій архітектурі, тобто в рамках того самого процесу.
Отже ми повернулись до того з чого почали. Наш клас може бути як DTO, так і Value object. Аналогічно і Java bean. З Entity не все так просто, бо маємо додати ідентифікатор. Але ідентифікатором може бути як поле id, так і email чи обчислюване значення getFullName (це щоправда не найкраще рішення).
Але яке значення має те, який саме паттерн реалізує наш клас Person? І навіть коли ми визначили, що хочемо застосувати певний шаблон під певну проблему, то чи маємо ми дотримуватись усіх рекомендацій, які прочитали в розумній книжці поважного пана або ще гірше — десь в інтернеті?
На прикладах шаблонів, ми маємо вчитись вирішувати проблеми. Бачити контекст, розуміти його подібність чи відмінність з контекстом нашої проблеми. Непотрібно застосовувати паттерн до проблеми, потрібно вирішувати конкретну проблему в конкретному контексті на основі знань, що ви отримали зі знайомством з паттерном (чи кейсом у ширшому випадку).
Enjoy Reading This Article?
Here are some more articles you might like to read next: