|
15 | 15 | 2. [Одиночка (Singleton)](#Одиночка)
|
16 | 16 | 3. [Строитель (Builder)](#Строитель)
|
17 | 17 | 4. [Прототип (Prototype)](#Прототип)
|
| 18 | + 5. [Фабричный метод (Factory Method)](#Фабричный-метод) |
18 | 19 | 2. [Структурные паттерны](#Структурные-паттерны)
|
19 | 20 | 1. [Адаптер (Adapter)](#Адаптер)
|
20 | 21 | 2. [Декоратор (Decorator)](#Декоратор)
|
@@ -265,7 +266,7 @@ public class SectionDatabase
|
265 | 266 |
|
266 | 267 | return Database;
|
267 | 268 | }
|
268 |
| - } |
| 269 | +} |
269 | 270 | ```
|
270 | 271 | :white_check_mark: __Преимущества паттерна Singleton__: класс гарантированно имеет только один экземпляр и не более, у нас есть точка доступа к единственному экземпляру (в нашем случае это метод Initialize) <br>
|
271 | 272 | :x: __Недостатки__: нарушение принципа единой ответственности (Single Responsibility Principle), требуется особая обработка в многопоточной среде.
|
@@ -467,7 +468,120 @@ public class Director
|
467 | 468 | :x: __Недостатки__: жесткая связка конкретного Builder и продукта, который он создает.
|
468 | 469 | ___
|
469 | 470 | ### Прототип
|
470 |
| -__Прототип (Prototype)__ - это такой паттерн, который используется для создания новых объектов с помощью клонирования существующих. |
| 471 | +__Прототип (Prototype)__ - это такой паттерн, который используется для создания новых объектов с помощью клонирования существующих. Для того, чтобы определение паттерна было более понятно, приведу конкретный пример.<br> |
| 472 | +Предположим, что у нас есть биржа фриланса, где есть заказчики и исполнители.<br> |
| 473 | +:one: Для начала создадим абстрактный класс User - пользователь биржи фриланса. У пользователя будут идентификатор, ФИО и абстрактный метод Clone. Это означает, что мы обязательно должны реализовать его в классе-наследнике. |
| 474 | +```C# |
| 475 | +/// <summary> |
| 476 | +/// Пользователь |
| 477 | +/// </summary> |
| 478 | +public abstract class User |
| 479 | +{ |
| 480 | + /// <summary> |
| 481 | + /// Идентификатор. |
| 482 | + /// </summary> |
| 483 | + public int Id { get; set; } |
| 484 | + |
| 485 | + /// <summary> |
| 486 | + /// Имя. |
| 487 | + /// </summary> |
| 488 | + public string FirstName { get; set; } |
| 489 | + |
| 490 | + /// <summary> |
| 491 | + /// Фамилия. |
| 492 | + /// </summary> |
| 493 | + public string LastName { get; set; } |
| 494 | + |
| 495 | + /// <summary> |
| 496 | + /// Отчество. |
| 497 | + /// </summary> |
| 498 | + public string Patronymic { get; set; } |
| 499 | + |
| 500 | + /// <summary> |
| 501 | + /// Клонирование пользователя. |
| 502 | + /// </summary> |
| 503 | + /// <returns>Нового пользователя.</returns> |
| 504 | + public abstract User Clone(); |
| 505 | + |
| 506 | + /// <summary> |
| 507 | + /// Строковое представления объекта пользователя. |
| 508 | + /// </summary> |
| 509 | + /// <returns>Данные пользователя в виде строки.</returns> |
| 510 | + public override string ToString() => $"Идентификатор - {Id} Имя - {FirstName} Фамилия - {LastName} Отчество - {Patronymic}"; |
| 511 | +} |
| 512 | +``` |
| 513 | +:two: Теперь реализуем класс-наследник исполнителя: в него не будем добавлять дополнительные свойства. Реализация метода Clone будет выглядеть так: |
| 514 | +```C# |
| 515 | +/// <summary> |
| 516 | +/// Исполнитель. |
| 517 | +/// </summary> |
| 518 | +public class Executor : User |
| 519 | +{ |
| 520 | + /// <summary> |
| 521 | + /// Клонирование пользователя. |
| 522 | + /// </summary> |
| 523 | + /// <returns>Нового пользователя.</returns> |
| 524 | + public override User Clone() => (Executor)MemberwiseClone(); |
| 525 | + |
| 526 | + /// <summary> |
| 527 | + /// Строковое представления объекта исполнителя. |
| 528 | + /// </summary> |
| 529 | + /// <returns>Данные исполнителя в виде строки.</returns> |
| 530 | + public override string ToString() => $"Данные исполнителя: {base.ToString()}"; |
| 531 | +} |
| 532 | +``` |
| 533 | +> В данном случае мы можем выполнить неполное (поверхностное) копирование. Это подходит тогда, когда у нас все поля Executor являются значимыми типами (исключение: string). |
| 534 | +
|
| 535 | +Теперь рассмотрим второй класс-наследник: Customer. |
| 536 | +```C# |
| 537 | +/// <summary> |
| 538 | +/// Заказчик |
| 539 | +/// </summary> |
| 540 | +public class Customer : User |
| 541 | +{ |
| 542 | + /// <summary> |
| 543 | + /// Паспорт. |
| 544 | + /// </summary> |
| 545 | + public Passport Passport { get; set; } |
| 546 | + |
| 547 | + /// <summary> |
| 548 | + /// Создание пользователя. |
| 549 | + /// </summary> |
| 550 | + public Customer() |
| 551 | + { |
| 552 | + Passport = new Passport(); |
| 553 | + } |
| 554 | + |
| 555 | + /// <summary> |
| 556 | + /// Клонирование пользователя. |
| 557 | + /// </summary> |
| 558 | + /// <returns>Нового пользователя.</returns> |
| 559 | + public override User Clone() |
| 560 | + { |
| 561 | + var customer = (Customer)MemberwiseClone(); |
| 562 | + customer.Passport = new Passport(); |
| 563 | + customer.Passport.Series = Passport.Series; |
| 564 | + customer.Passport.Number = Passport.Number; |
| 565 | + customer.Passport.ReceiptPlace = Passport.ReceiptPlace; |
| 566 | + |
| 567 | + return customer; |
| 568 | + } |
| 569 | + |
| 570 | + /// <summary> |
| 571 | + /// Строковое представления объекта заказчика. |
| 572 | + /// </summary> |
| 573 | + /// <returns>Данные заказчика в виде строки.</returns> |
| 574 | + public override string ToString() => $"Данные заказчика: {base.ToString()} {Passport}"; |
| 575 | +} |
| 576 | +``` |
| 577 | +> Здесь у нас уже присутствует класс Passport - это ссылочный тип, соответсвенно, мы не можем использовать неполное копирование. Если мы будем использовать неполное копирование, то у нас будет два заказчика ссылаться на один и тот же объект паспортных данных. Поэтому нам придется создать новый объект паспорта и вручную его проинициализировать. |
| 578 | +
|
| 579 | +Также, чтобы убедиться в том, что у нас создаются два абсолютно разных объекта, которые не ссылаются на одни и те же поля, рекомендую запустить тесты в проекте PrototypeTests, где происходит данная проверка.<br><br> |
| 580 | +:white_check_mark: __Преимущества паттерна Prototype__: клонирование объектов без привязки к конкретным классам, сокращение кода инициализации экземплятор классов<br> |
| 581 | +:x: __Недостатки__: Проблемы с клонированием составных объектов, то есть, тех объектов, которые внутри содержат другие объекты. |
| 582 | +___ |
| 583 | +### Фабричный метод |
| 584 | +__Фабричный метод (Factory Method)__ - |
471 | 585 | ## Структурные паттерны
|
472 | 586 | __Структурные паттерны__ (Structural) - цель их применения заключается в том, что благодаря им вы можете совмещать и сочетать сущности вместе.
|
473 | 587 | ___
|
@@ -999,6 +1113,7 @@ public class User : IObserver<Message>
|
999 | 1113 | Console.WriteLine($"Полученное уведомление: {Environment.NewLine}{value}{Environment.NewLine}" +
|
1000 | 1114 | $"Логин получателя: {_login}");
|
1001 | 1115 | }
|
| 1116 | + } |
1002 | 1117 | ```
|
1003 | 1118 | :three: Теперь создадим класс нашего корпоративного портала, реализующий интерфейс IObservable (наблюдаемый объект). В качестве параметра также выступает тип данных Message - тип сообщения для подписчиков.
|
1004 | 1119 | ```C#
|
|
0 commit comments