Fluent builder (шаблон проєктування)
Fluent builder — твірний шаблон проєктування, який спрощує процес створення об'єктів.
Мотивація[ред. | ред. код]
Спростити процес створення важких об'єктів. Розв'язує проблему перевантажених конструкторів, а також проблему великої кількості аргументів в конструкторах.
Опис[ред. | ред. код]
Нехай дано клас User
public class User { // FIELDS private string name; private string surname; private int age; private bool isMarried; // CONSTRUCTORS public User() { this.name = string.Empty; this.surname = string.Empty; this.age = 18; this.isMarried = false; } public User(string name, string surname, int age, bool isMarried) { this.name = name; this.surname = surname; this.age = age > 18 ? age : 18; this.isMarried = isMarried; } }
Його конструктор приймає чотири аргументи, що вже здається надлишковістю. Крім того кількість полів та аргументів може бути значно більшою, а для полів можуть бути присутні різноманітні перевірки.
Додамо клас, який буде відповідати за побудову нашого об'єкта
public class UserBuilder { // FIELDS private User user; // CONSTRUCTORS public UserBuilder() { user = new User(); } // METHODS public UserBuilder SetName(string name) { user.name = name; return this; } public UserBuilder SetSurname(string surname) { user.surname = surname; return this; } public UserBuilder SetAge(int age) { user.age = age > 18 ? age : 18; return this; } public UserBuilder SetIsMarried(bool isMerried) { user.isMarried = isMerried; return this; } // BUILDING public User Build() { return user; } }
Цей клас вміє лише будувати нашого User'a. Важливо відмітити, що кожний Set метод повертає this, тобто посилання на об'єкт будівельника. Це дозволить нам використати Fluent interface.
User user = new User.UserBuilder() .SetName("John") .SetSurname("Doe") .Build();
Звісно це не є обов'язковою вимогою шаблону.
Переваги та недоліки[ред. | ред. код]
Переваги[ред. | ред. код]
- спрощує процес створення об'єкта
- спрощує конструктор об'єкта
- спрощує код
Недоліки[ред. | ред. код]
- додає клас будівельник, для складних об'єктів
- не завжди будівельник має доступ до полів об'єкта. В деяких випадках, аби досягти цього, варто порушити інкапсуляцію, що не завжди є прийнятним рішенням
Зв'язок з іншими патернами[ред. | ред. код]
- Будівник та Fluent Builder використовують з однаковою метою — боротьба з анти-шаблоном "телескопічний конструктор". Але варто розуміти, що Будівник надає інтерфейс для реалізації алгоритмів побудови складних об'єктів. Користувач працює із об'єктами-спадкоємцями через цей інтерфейс доступу. Fluent Builder надає користувачеві методи ініціалізації полів.
Реалізація[ред. | ред. код]
C#[ред. | ред. код]
namespace FluentBuilder { public class User { // FIELDS private string name; private string surname; private int age; private bool isMarried; // CONSTRUCTORS public User() { this.name = string.Empty; this.surname = string.Empty; this.age = 18; this.isMarried = false; } public User(string name, string surname, int age, bool isMarried) { this.name = name; this.surname = surname; this.age = age > 18 ? age : 18; this.isMarried = isMarried; } public static UserBuilder CreateBuilder() { return new UserBuilder(); } // INNER CLASSES public class UserBuilder { // FIELDS private User user; // CONSTRUCTORS public UserBuilder() { user = new User(); } // METHODS public UserBuilder SetName(string name) { user.name = name; return this; } public UserBuilder SetSurname(string surname) { user.surname = surname; return this; } public UserBuilder SetAge(int age) { user.age = age > 18 ? age : 18; return this; } public UserBuilder SetIsMarried(bool isMerried) { user.isMarried = isMerried; return this; } // BUILDING public User Build() { return user; } public static implicit operator User(UserBuilder builder) { return builder.user; } } } class Program { static void Main(string[] args) { // different ways of creating a builder // user builder's constructor User user1 = new User.UserBuilder() .SetName("John") .SetSurname("Doe") .Build(); // user's static method User user2 = User.CreateBuilder() .SetName("John") .SetSurname("Doe") .Build(); // different ways of building user // build method User user3 = new User.UserBuilder() .SetName("John") .SetSurname("Doe") .Build(); // conversion User user4 = new User.UserBuilder() .SetName("John") .SetSurname("Doe"); System.Console.Read(); } } }
Див.також[ред. | ред. код]
Джерела[ред. | ред. код]
- A Fluent Builder in C# [Архівовано 15 березня 2019 у Wayback Machine.]
- FluentBuilder [Архівовано 30 березня 2019 у Wayback Machine.]
- C# Design Patterns – Fluent Builder Interface With Recursive Generics [Архівовано 30 березня 2019 у Wayback Machine.]