Skip to content

Commit 4f48659

Browse files
2 parents 21a989b + 495215e commit 4f48659

File tree

1 file changed

+117
-2
lines changed

1 file changed

+117
-2
lines changed

README.md

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
2. [Одиночка (Singleton)](#Одиночка)
1616
3. [Строитель (Builder)](#Строитель)
1717
4. [Прототип (Prototype)](#Прототип)
18+
5. [Фабричный метод (Factory Method)](#Фабричный-метод)
1819
2. [Структурные паттерны](#Структурные-паттерны)
1920
1. [Адаптер (Adapter)](#Адаптер)
2021
2. [Декоратор (Decorator)](#Декоратор)
@@ -265,7 +266,7 @@ public class SectionDatabase
265266

266267
return Database;
267268
}
268-
}
269+
}
269270
```
270271
:white_check_mark: __Преимущества паттерна Singleton__: класс гарантированно имеет только один экземпляр и не более, у нас есть точка доступа к единственному экземпляру (в нашем случае это метод Initialize) <br>
271272
:x: __Недостатки__: нарушение принципа единой ответственности (Single Responsibility Principle), требуется особая обработка в многопоточной среде.
@@ -467,7 +468,120 @@ public class Director
467468
:x: __Недостатки__: жесткая связка конкретного Builder и продукта, который он создает.
468469
___
469470
### Прототип
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)__ -
471585
## Структурные паттерны
472586
__Структурные паттерны__ (Structural) - цель их применения заключается в том, что благодаря им вы можете совмещать и сочетать сущности вместе.
473587
___
@@ -999,6 +1113,7 @@ public class User : IObserver<Message>
9991113
Console.WriteLine($"Полученное уведомление: {Environment.NewLine}{value}{Environment.NewLine}" +
10001114
$"Логин получателя: {_login}");
10011115
}
1116+
}
10021117
```
10031118
:three: Теперь создадим класс нашего корпоративного портала, реализующий интерфейс IObservable (наблюдаемый объект). В качестве параметра также выступает тип данных Message - тип сообщения для подписчиков.
10041119
```C#

0 commit comments

Comments
 (0)