Приведи явный пример реализации паттерна строитель
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Реализация паттерна Строитель (Builder) на C#
Паттерн Строитель (Builder) — это порождающий шаблон проектирования, который позволяет создавать сложные объекты пошагово, отделяя конструирование объекта от его представления. Это особенно полезно, когда объект имеет множество полей, некоторые из которых опциональны, или когда процесс создания состоит из нескольких шагов.
Ключевые компоненты паттерна:
- Продукт (Product) — создаваемый сложный объект.
- Строитель (Builder) — интерфейс, определяющий шаги для построения продукта.
- Конкретный строитель (Concrete Builder) — реализует интерфейс Builder, предоставляя конкретные реализации шагов. Хранит создаваемый объект.
- Директор (Director) — отвечает за последовательность шагов построения. Он знает, какой строитель использовать для получения нужного продукта.
- Клиент (Client) — использует директора и строителя для создания объекта.
Явный пример: Построение отчета (Report)
Рассмотрим задачу создания сложного отчета, который может иметь заголовок, тело, список графиков и подвал. Не все части обязательны.
1. Продукт (Product) — Класс Report
public class Report
{
public string Title { get; set; }
public string Body { get; set; }
public List<string> Charts { get; set; } = new List<string>();
public string Footer { get; set; }
public DateTime GeneratedAt { get; set; }
public void Display()
{
Console.WriteLine($"=== {Title} ===");
Console.WriteLine($"Сгенерирован: {GeneratedAt}");
Console.WriteLine($"\nТело отчета:\n{Body}");
if (Charts.Any())
{
Console.WriteLine("\nГрафики:");
foreach (var chart in Charts)
Console.WriteLine($" - {chart}");
}
if (!string.IsNullOrEmpty(Footer))
Console.WriteLine($"\nПримечание: {Footer}");
}
}
2. Строитель (Builder) — Интерфейс IReportBuilder
public interface IReportBuilder
{
void SetTitle(string title);
void SetBody(string body);
void AddChart(string chartTitle);
void SetFooter(string footer);
void SetGenerationDate();
Report GetReport();
}
3. Конкретный строитель (Concrete Builder) — PdfReportBuilder
public class PdfReportBuilder : IReportBuilder
{
private Report _report = new Report();
public PdfReportBuilder()
{
this.Reset();
}
private void Reset()
{
_report = new Report();
}
public void SetTitle(string title)
{
_report.Title = $"PDF: {title}";
}
public void SetBody(string body)
{
_report.Body = body + "\n[Форматировано для PDF]";
}
public void AddChart(string chartTitle)
{
_report.Charts.Add($"PDF-график: '{chartTitle}'");
}
public void SetFooter(string footer)
{
_report.Footer = $"{footer} | Конфиденциально";
}
public void SetGenerationDate()
{
_report.GeneratedAt = DateTime.UtcNow;
}
// Метод GetReport возвращает готовый продукт и обычно сбрасывает строитель
public Report GetReport()
{
Report finishedReport = _report;
this.Reset(); // Готовим строитель к созданию нового отчета
return finishedReport;
}
}
4. Директор (Director) — ReportDirector
Директор инкапсулирует логику сборки конкретных конфигураций продукта.
public class ReportDirector
{
private IReportBuilder _builder;
public ReportDirector(IReportBuilder builder)
{
_builder = builder;
}
// Метод для построения полного отчета
public void BuildFullReport(string title, string body)
{
_builder.SetGenerationDate();
_builder.SetTitle(title);
_builder.SetBody(body);
_builder.AddChart("Динамика продаж");
_builder.AddChart("Распределение рынка");
_builder.SetFooter("Отдел аналитики");
}
// Метод для построения минимального отчета
public void BuildMinimalReport(string title, string body)
{
_builder.SetGenerationDate();
_builder.SetTitle(title);
_builder.SetBody(body);
// Графики и подвал не добавляем
}
// Метод для кастомной пошаговой сборки (без предопределенной логики)
public void CustomBuild(Action<IReportBuilder> buildSteps)
{
buildSteps(_builder);
}
}
5. Клиент (Client) — Использование
class Program
{
static void Main(string[] args)
{
// 1. Создаем конкретного строителя
var pdfBuilder = new PdfReportBuilder();
// 2. Создаем директора, передаем ему строителя
var director = new ReportDirector(pdfBuilder);
// 3. Директор управляет процессом построения
Console.WriteLine("== Полный отчет ==");
director.BuildFullReport("Годовой отчет 2023", "Продажи выросли на 15%...");
var fullReport = pdfBuilder.GetReport();
fullReport.Display();
Console.WriteLine("\n\n== Минимальный отчет ==");
director.BuildMinimalReport("Еженедельный дайджест", "Стабильные показатели...");
var minimalReport = pdfBuilder.GetReport();
minimalReport.Display();
// 4. Использование без директора (ручное построение)
Console.WriteLine("\n\n== Кастомный отчет (без директора) ==");
var customBuilder = new PdfReportBuilder();
customBuilder.SetTitle("Специальный анализ");
customBuilder.SetBody("Детальные метрики...");
customBuilder.AddChart("Пользовательская активность");
customBuilder.SetGenerationDate();
var customReport = customBuilder.GetReport();
customReport.Display();
// 5. Кастомная сборка через директор
Console.WriteLine("\n\n== Кастомный отчет (через директор) ==");
director.CustomBuild(builder =>
{
builder.SetTitle("Отчет по запросу");
builder.SetBody("Данные...");
builder.SetFooter("Срочно");
});
var onDemandReport = pdfBuilder.GetReport();
onDemandReport.Display();
}
}
Преимущества реализации:
- Пошаговое конструирование: Объект создается последовательно, шаг за шагом.
- Изоляция сложной логики: Код сборки объекта изолирован в директоре и строителе.
- Гибкость: Можно создавать различные представления одного продукта (например, добавив
ExcelReportBuilderс той же последовательностью шагов). - Читаемость клиентского кода: Клиентский код не загроможден множеством параметров конструктора.
- Контроль процесса: Можно создавать разные конфигурации объекта, используя один и тот же процесс построения.
Вариант с Fluent Interface (Цепочка вызовов)
Часто строитель реализуют с Fluent Interface для улучшения читаемости:
public class FluentReportBuilder
{
private Report _report = new Report();
public FluentReportBuilder SetTitle(string title)
{
_report.Title = title;
return this;
}
public FluentReportBuilder SetBody(string body)
{
_report.Body = body;
return this;
}
public Report Build()
{
_report.GeneratedAt = DateTime.Now;
return _report;
}
}
// Использование
var report = new FluentReportBuilder()
.SetTitle("Fluent Report")
.SetBody("Content")
.Build();
Данный пример демонстрирует классическую реализацию паттерна Строитель с директором, а также популярный вариант с цепочкой вызовов, который часто используется в реальных проектах C# для конфигурации сложных объектов.