Main
This commit is contained in:
Dvurechensky 2024-10-05 09:15:54 +03:00
commit 3a28caed27
94 changed files with 5617 additions and 0 deletions

63
.gitattributes vendored Normal file

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

3
.gitignore vendored Normal file

@ -0,0 +1,3 @@
.vs
Patterns/bin
Patterns/obj

121
LICENSE Normal file

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>_1_Принцип_единственной_обязанности</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,71 @@
/*
* Глава 17: Принцип единственной обязанности (SOLID SRP)
*
* - инкапсуляция сущности с целью организации архитектуры
* приложения, которую будет легко поддерживать и расширять в
* течении всего промежутка эксплуатации
*
* Автор: Роберт Мартин (Дядя Боб)
*
* Принципы:
* 1. Single responsibility - принцип единственной ответственности
* 2. Open-closed - принцип открытости/закрытости
* 3. Liskov substitution - принцип подстановки Барбары Лисков (самый сложный)
* 4. Interface Segregation - принцип разделения интерфейса
* 5. Dependency inversion - принцип инверсии зависисмостей
*/
/*
* Принцип единственной ответственности (англ. single-responsibility principle, SPR) -
* принцип ООП, обозначающий, что каждый объект должен иметь одну ответственность и эта
* ответственность должна быть полностью инкапсулирована в класс.
* Все его поведения должны быть направлены исключительно на обеспечение этой отвественности.
*/
/// <summary>
/// К примеру: Разработать класс который будет работать с изображениями
/// </summary>
abstract class Attach
{
}
class Image : Attach
{
private int width;
private int height;
public int Width => width;
public int Height => height;
private Image(int width, int height) { }
//Добавление других методов предполагающих иной функционал не рационально
//Следуем принципу - декомпозировать - делать максимально минимальные классы под свою ответственность
public static Image CreateImage(int width, int height) { return new Image(width, height); }
}
/// <summary>
/// EMail сервис
/// Если отваливается модуль отправки Email
/// мы чиним только его, нам не требуется разбирать класс Image
/// </summary>
class EmailService
{
private string email;
private string text;
private string subject;
private Attach[] attach;
public EmailService(string email,
string text = "",
string subject = "",
params Attach[] args)
{ }
public void SendTo(string email, string text, string subject) { }
}
class Program
{
public static void Main(string[] argv)
{
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>_2_Принцип_открытости__закрытости</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,55 @@
/*
* Глава 18: Принцип открытости/закрытости (SOLID SRP)
*
* Автор: Роберт Мартин (Дядя Боб)
*
* Постулаты:
* - если какая-то сущность описана, то она уже
* полностью закрыта для каких либо изменений;
* - сущность открыта для модификаций;
*
* Принципы:
* 1. Single responsibility - принцип единственной ответственности
* 2. Open-closed - принцип открытости/закрытости
* 3. Liskov substitution - принцип подстановки Барбары Лисков (самый сложный)
* 4. Interface Segregation - принцип разделения интерфейса
* 5. Dependency inversion - принцип инверсии зависисмостей
*/
public abstract class Attach
{
}
public class Image : Attach
{
private int width;
private int height;
public int Width => width;
public int Height => height;
private Image(int width, int height) { }
private Image(int width, int height, ISave save) { }
public static Image CreateImage(int width, int height) { return new Image(width, height); }
public static Image CreateImage(int width, int height, ISave save) { return new Image(width, height, save); }
public void SaveToFile(string path) { }
}
public interface ISave
{
ISave SaveTo(string path);
}
public class SaveToBmp : ISave
{
public ISave SaveTo(string path)
{
return this;
}
}
public class Program
{
public static void Main(string[] argv)
{
Image.CreateImage(100, 100, new SaveToBmp().SaveTo(""));
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>_3_Принцип_подстановки_Барбары_Лисков</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,127 @@
/*
* Глава 19: Принцип подстановки Барбары Лисков (SOLID SRP)
*
* Автор: Роберт Мартин (Дядя Боб)
*
* Сам принцип:
* - Пусть Q(x) является свойством, верным относительно объектов x некоторого
* типа T. Тогда Q(y) также должно быть верным для объектов y типа S, где S является подтипом T.
*
* или
*
* - Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа, не зная об этом.
* Поведение классов-наследников не должно противоречить поведению, заданному базовым классом
*
* Принципы:
* 1. Single responsibility - принцип единственной ответственности
* 2. Open-closed - принцип открытости/закрытости
* 3. Liskov substitution - принцип подстановки Барбары Лисков (самый сложный)
* 4. Interface Segregation - принцип разделения интерфейса
* 5. Dependency inversion - принцип инверсии зависисмостей
*/
public class Coordinates
{
public int Longtitude { get; set; }
public int Latitude { get; set; }
public override string ToString()
{
return $"Широта: {Longtitude} Долгота: {Latitude}";
}
}
/// <summary>
/// Шаблон летающей птицы
/// </summary>
public class Bird
{
protected Random rand;
public Coordinates Position { get; set; }
protected int speed, spacing;
public int Spacing { get => spacing; }
public Bird()
{
Position = new Coordinates();
rand = new Random();
}
protected void Mark(int x, int y) { }
/// <summary>
/// Полёт птицы
/// </summary>
private void Fly()
{
speed = 1;
switch (rand.Next(2))
{
case 0: Position.Latitude += speed; break;
default: Position.Longtitude += speed; break;
}
spacing++;
Console.SetCursorPosition(Position.Latitude, Position.Longtitude);
Console.WriteLine("B");
}
/// <summary>
/// Движение птицы
/// </summary>
public virtual void Move()
{
Fly();
}
}
/// <summary>
/// Шаблон бегущей птицы
/// </summary>
public class Kiwi : Bird
{
private void Run()
{
speed = 1;
switch (rand.Next(2, 6))
{
case 3: Position.Latitude += speed; break;
default: Position.Longtitude += speed; break;
}
spacing++;
Console.SetCursorPosition(Position.Latitude, Position.Longtitude);
Console.WriteLine("K");
}
public override void Move()
{
Run();
}
}
/// <summary>
/// Шаблон отображеня движения
/// </summary>
class CalculatingDistance
{
private int time;
public CalculatingDistance(int time) { this.time = time; }
public void Calculate(Bird bird)
{
for (int i = 0; i < time; i++)
{
bird.Move();
}
Console.Title = ($"\n\n\nРасстояние: {bird.Spacing} {bird.Position}");
}
}
public class Program
{
public static void Main(string[] argv)
{
var bird = new Bird();
new CalculatingDistance(10).Calculate(bird);
var kiwi = new Kiwi();
new CalculatingDistance(10).Calculate(kiwi);
Console.ReadLine();
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>_4_Принцип_разделения_интерфейсов</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,48 @@
/*
* Глава 20: Принцип разделения интерфейсов (SOLID SRP)
*
* Автор: Роберт Мартин (Дядя Боб)
*
* Сам принцип:
* - клиенты не должны зависеть от методов которые они не используют
*
* или
*
* - если какая-то сущность заявляет о своем функционале, то он должен работать
*
* или
*
* - от реализации исбыточных интерфейсов следует отказаться в пользу специфичных
*
* Принципы:
* 1. Single responsibility - принцип единственной ответственности
* 2. Open-closed - принцип открытости/закрытости
* 3. Liskov substitution - принцип подстановки Барбары Лисков (самый сложный)
* 4. Interface Segregation - принцип разделения интерфейса
* 5. Dependency inversion - принцип инверсии зависисмостей
*/
public abstract class Car
{
public string Model { get; set; }
public string Brand { get; set; }
public Car(string model, string name)
{
Model = model;
Brand = name;
}
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!! вместо огромного набора функций в одном интерфейсе !!!
//!!! в случае если при наследовании от него множество функций не реализуется !!!
//!!! нужно перейти в сторону множественного наследования интерфейсов под каждую из функций !!!
//!!! или под каждый набор функций !!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public class Program
{
public static void Main(string[] argv)
{
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>_5_Принцип_инверсии_зависимостей</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,107 @@
/*
* Глава 21: Принцип инверсии зависимостей (SOLID SRP)
*
* Автор: Роберт Мартин (Дядя Боб)
*
* Сам принцип:
*
* - Модули верхних уровней не должны зависеть от модулей нижних уровней
* (Оба типа должны зависеть от абстракций)
*
* - Абстракции не должны зависеть от деталей
* (Детали должны зависеть от абстракций)
*
* Принципы:
* 1. Single responsibility - принцип единственной ответственности
* 2. Open-closed - принцип открытости/закрытости
* 3. Liskov substitution - принцип подстановки Барбары Лисков (самый сложный)
* 4. Interface Segregation - принцип разделения интерфейса
* 5. Dependency inversion - принцип инверсии зависисмостей
*/
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
/// <summary>
/// Поведение поиска в хранилищах информации
/// </summary>
public interface IFindStorage
{
List<Person> FindAll(Predicate<Person> predicate);
}
/// <summary>
/// Шаблон списка пользователей
/// </summary>
public class ListStorage : IFindStorage
{
private List<Person> storage;
public ListStorage()
{
storage = new List<Person>();
}
public List<Person> GetPersons() => storage;
public void Add(Person p) => storage.Add(p);
public List<Person> FindAll(Predicate<Person> predicate)
{
return storage.Where(e => predicate(e)).ToList();
}
}
/// <summary>
/// Шаблон словаря пользователей
/// </summary>
public class DictionaryStorage : IFindStorage
{
private Dictionary<string, Person> storage;
public DictionaryStorage()
{
storage = new Dictionary<string, Person>();
}
public Dictionary<string, Person> GetPersons() => storage;
public void Add(string key, Person p) => storage.Add(key, p);
public List<Person> FindAll(Predicate<Person> predicate)
{
return storage.Where(e => predicate(e.Value)).Select(e => e.Value).ToList();
}
}
/// <summary>
/// Щаблон поисковика
/// </summary>
public class SearchByAge
{
IFindStorage storage;
public SearchByAge(IFindStorage storage) => this.storage = storage;
public void Search()
{
foreach (var p in storage.FindAll(e => e.Age > 45))
{
Console.WriteLine($"{p.FirstName} {p.Age}");
}
}
}
public class Program
{
public static void Main(string[] argv)
{
Console.WriteLine("DictionaryStorage: ");
var storageDict = new DictionaryStorage();
storageDict.Add("1", new Person() { Age = 90 });
new SearchByAge(storageDict).Search();
Console.WriteLine("ListStorage: ");
var storageList = new ListStorage();
storageList.Add(new Person() { Age = 43 });
new SearchByAge(storageList).Search();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,148 @@
/* Абстрактная фабрика
Предоставляет интерфейс для создания
групп связанных или зависимых объектов,
не указывая их конкретный класс
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var soldier = new Hero(new SoldierFactory());
soldier.Run();
soldier.Hit();
var elf = new Hero(new ElfFactory());
elf.Run();
elf.Hit();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Оружие базовая логика
/// </summary>
abstract class Weapon
{
public abstract void Hit();
}
/// <summary>
/// Движение базовая логика
/// </summary>
abstract class Movement
{
public abstract void Move();
}
/// <summary>
/// Огнестрел
/// </summary>
class Gun : Weapon
{
public override void Hit()
{
Console.WriteLine("Hit Gun");
}
}
/// <summary>
/// Арбалет
/// </summary>
class Arbalet : Weapon
{
public override void Hit()
{
Console.WriteLine("Hit Arbalet");
}
}
/// <summary>
/// Герой летает
/// </summary>
class Fly : Movement
{
public override void Move()
{
Console.WriteLine("Hero Fly");
}
}
/// <summary>
/// Герой бежит
/// </summary>
class Run : Movement
{
public override void Move()
{
Console.WriteLine("Hero Run");
}
}
/// <summary>
/// Супергерой
/// </summary>
class Hero
{
private Weapon Weapon { get; set; }
private Movement Movement { get; set; }
public Hero(HeroFactory factory)
{
Weapon = factory.CreateWeapon();
Movement = factory.CreateMovement();
}
public void Run()
{
Movement.Move();
}
public void Hit()
{
Weapon.Hit();
}
}
/// <summary>
/// Абстракция фабрика героев
/// </summary>
abstract class HeroFactory
{
public abstract Weapon CreateWeapon();
public abstract Movement CreateMovement();
}
/// <summary>
/// Эльфы
/// </summary>
class ElfFactory : HeroFactory
{
public override Movement CreateMovement()
{
return new Fly();
}
public override Weapon CreateWeapon()
{
return new Arbalet();
}
}
/// <summary>
/// Солдаты
/// </summary>
class SoldierFactory : HeroFactory
{
public override Movement CreateMovement()
{
return new Run();
}
public override Weapon CreateWeapon()
{
return new Gun();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,78 @@
/* Адаптер
Конвенртирует интерфейс класса в другой интерфейс,
ожидаемый клиентом. Позволяет классам
с разными интерфейсами работать вместе.
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var man = new Driver();
var car = new Auto(); //машина она едет также как мотоцикл, всё отлично
var camelTransport = //но мы хотим добраться на пешем транспорте (на верблюде)
new CamelToTransport(new Camel());
man.Travel(camelTransport);
man.Travel(car);
Console.ReadKey();
#endregion
}
}
interface ITransport
{
void Drive();
}
/// <summary>
/// Шаблон автомобиля
/// </summary>
class Auto : ITransport
{
public void Drive()
{
Console.WriteLine(GetType().Name + " Move");
}
}
/// <summary>
/// Шаблон верблюда
/// </summary>
class Camel
{
public void Move()
{
Console.WriteLine(GetType().Name + " Move");
}
}
/// <summary>
/// Шаблон движения верблюда
/// </summary>
class CamelToTransport : ITransport
{
Camel camel;
public CamelToTransport(Camel camel)
{
this.camel = camel;
}
public void Drive()
{
camel.Move();
}
}
/// <summary>
/// Шаблон путешественника
/// </summary>
class Driver
{
public void Travel(ITransport transport)
{
transport.Drive();
}
}

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>
</Project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserDetails>
<User userId="Ivan" email="aspkx@mail.ru" />
<User userId="Nikolay" email="aspkx@mail.ru" />
<User userId="Oleg" email="aspkx@mail.ru" />
</UserDetails>

@ -0,0 +1,31 @@
namespace Base.UserLibrary.Tests
{
[TestClass]
public class UnitTest1
{
private TestContext testContextInstance;
public TestContext TestContextInstance
{
get { return testContextInstance; }
set { testContextInstance = value; }
}
private UserManagerMsTest manager = new UserManagerMsTest();
/// <summary>
/// DataSource - îïðåäåëåíèå èñòî÷íèêà äàííûõ
/// 1 ïàðàìåòð - èìÿ ïðîâàéäåðà
/// 2 ïàðàìåòð - ñòðîêà ïîäêëþ÷åíèÿ èëè ïóòü ê ôàéëó
/// 3 ïàðàìåòð - èìÿ òàáëèöû èëè ýëåìåíòà XML
/// 4 ïàðàìåòð - êàê ïðîèñõîäèò äîñòóï ê çàïèñÿì èç èñòî÷íèêà äàííûõ
/// </summary>
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
"TestData.xml",
"User",
DataAccessMethod.Sequential)]
[TestMethod]
public void AddDataTest()
{
string userId = Convert.ToString(TestContextInstance.DataRow["Row1"]);
}
}
}

@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

28
Patterns/Base.cs Normal file

@ -0,0 +1,28 @@
using System;
public class Base
//абстрактный класс
abstract class AbstrTest
{
void Move()
{
}
//реализация по умолчанию
public virtual void Resize()
{
}
void Declare();
}
public class Class_Main : AbstrTest
{
public Class_Main()
{
Declare();
}
}

@ -0,0 +1,26 @@
namespace Base;
public class AssertMsTest
{
/// <summary>
/// Получить квадратный корень
/// </summary>
/// <param name="value">Значение</param>
/// <returns>double</returns>
public static double GetSqrt(double value)
{
return Math.Sqrt(value);
}
/// <summary>
/// Получить приветствие
/// </summary>
/// <param name="name">Имя</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">пустое имя</exception>
public string SayHello(string name)
{
if (name == null) throw new ArgumentNullException("Parameter name can not be null");
return "Hi! " + name;
}
}

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

@ -0,0 +1,17 @@
namespace Base
{
/// <summary>
/// Тестовый класс статических реализаций
/// </summary>
internal static class Extension
{
/// <summary>
/// Тестовый статический метод
/// </summary>
/// <param name="classMain">Представитель определённого поведения</param>
public static void ResizeExt(this IInterTest classMain)
{
Console.WriteLine("Resize Class Extension");
}
}
}

410
Patterns/Base/Program.cs Normal file

@ -0,0 +1,410 @@
using Newtonsoft.Json;
using static Base.Records;
namespace Base;
/// <summary>
/// Важно: ссылочные типы лежат в куче, значимые - ссылка в куче, значение в стеке
/// ***
/// Шаблон, по которому определяется форма объекта
/// Определение:
/// Класс - это ссылочный тип данных, шаблон по которому определяется объект, информацию о себе хранит в куче.
/// </summary>
class Program
{
static void Main()
{
var person = new Person() //реализация record сборки разборки
{
Id = 1,
Name = "john"
};
Console.WriteLine(person.ToString());
var job = new Job()
{
Ida = 786897980,
Names = "Address"
};
Console.WriteLine(job.ToString());
var gl = new GlobalInfo();
person.Deconstruct(out gl.Name, out gl.Id);
job.Deconstruct(out gl.Names, out gl.Ida);
Console.WriteLine($"{gl.Name}/{gl.Names}/{gl.Id}/{gl.Ida}");
IInterTest interTest = new ClassMain();
interTest.ResizeExt(); //методы static
interTest.Relocate(); //метод объявлен и реализован в самом интерфейсе
var Records = new Records(1, "rec1"); //экзмепляр Records (аналог class)
var (NameS, idS) = Records; //можно разложить record на переменные
var RecNew = Records with { Name = "rec2" };//можно инициализировать другой класс на основе данных первого
Console.WriteLine($"{NameS} {idS}");
var (NameS2, idS2) = RecNew; //можно разложить record на переменные
Console.WriteLine($"{NameS2} {idS2}");
Console.WriteLine(Records == RecNew); //можно сравнить record обычными операторами сравнения
Console.WriteLine();
Console.WriteLine(RecNew); //можно напечать JSON представление содержимого record по умолчанию
Console.WriteLine(Records); //можно напечать JSON представление содержимого record по умолчанию
var json = JsonConvert.SerializeObject(Records, Formatting.Indented);
Console.WriteLine(json);
var otherSideRecord = JsonConvert.DeserializeObject<Records>(json);
Console.WriteLine(otherSideRecord);
Records = Records with { Id = 10 };
Console.WriteLine(Records);
Console.ReadKey();
}
}
/// <summary>
/// Абстракция которая отвечает за контракт взаимодействия для различных типов
/// Определение:
/// Интерфейс - это ссылочный тип данных, представляющий контракт взаимодействия (поведение).
/// Этот контракт гласит о том что должен содержать class или struct.
/// Формирует общий признак для разнородных объектов
/// </summary>
public interface IInterTest
{
/// <summary>
/// Декларация - метод без реализации по умолчанию
/// </summary>
/// <param name="build"></param>
void Build(int build = 0);
/// <summary>
/// После C# 8.0 можно указывать реализацию метода в интерфейсе
/// </summary>
void Relocate()
{
Console.WriteLine("-> IInterTest: Relocate");
}
/// <summary>
/// Cигнатура - операция без реализации - абстрактный метод
/// </summary>
abstract void Reload();
/// <summary>
/// Делегат - ссылочный тип
/// </summary>
delegate void Destiny();
/// <summary>
/// Cвойство - ссылочный тип
/// </summary>
string Name { get; set; }
/// <summary>
/// Cвойство - ссылочный тип
/// </summary>
object ID { get; set; }
}
/// <summary>
/// Абстрактный класс
/// Определение:
/// Абстрактный класс - это ссылочный тип данных, для описания общности сущностей, которые не имеют конкретного воплощения
/// </summary>
public abstract class AbstrTest
{
/// <summary>
/// Поле
/// </summary>
public int key = 100;
/// <summary>
/// Свойство
/// </summary>
public string Name { get; set; }
/// <summary>
/// Конструктор без параметров
/// </summary>
public AbstrTest()
{
key = 110;
Name = "Fire";
Console.WriteLine($"->AbstrTest {Name} {key}");
}
/// <summary>
/// Конструктор с параметрами
/// </summary>
/// <param name="key">ключ</param>
public AbstrTest(int key)
{
this.key = key;
Name = "Fire";
Console.WriteLine($"->AbstrTest {Name} {key}");
}
/// <summary>
/// Метод - это фиксированная операция с реализацией по умолчанию
/// </summary>
public void Move()
{
Console.WriteLine("Move Abstr");
}
/// <summary>
/// Виртуальный метод - операция с реализацией по умолчанию
/// </summary>
public virtual void Resize()
{
Console.WriteLine("Resize Abstr");
}
/// <summary>
/// Абстрактный метод - сигнатура - операция без реализации
/// </summary>
public abstract void Open();
}
/// <summary>
/// Определение:
/// Структура - это значимый тип данных, ссылка на структуру хранится в куче, значение в стеке
/// Тот же класс, меняется тип данных
/// </summary>
public struct TestStruct : IInterTest
{
/// <summary>
/// Свойство имени
/// </summary>
public string Name { get; set; }
/// <summary>
/// Свойство идентификатора
/// </summary>
public object ID { get; set; }
/// <summary>
/// Конструктор без параметров
/// </summary>
public TestStruct()
{
Name = "Base";
ID = (object)0;
}
/// <summary>
/// Метод с реализацией с параметрами
/// </summary>
/// <param name="build">#</param>
public void Build(int build = 0)
{
Console.WriteLine($"Build TestStruct {build}");
}
/// <summary>
/// Метод с реализацией без параметров
/// </summary>
public void Reload()
{
Console.WriteLine("Reload TestStruct");
}
}
/// <summary>
/// Реализация поведения класса
/// </summary>
public class ClassMain : AbstrTest, IInterTest
{
/// <summary>
/// Свойство
/// </summary>
public int countBuild { get; set; }
/// <summary>
/// Свойство от интерфейса
/// </summary>
public string Name { get; set; }
/// <summary>
/// Свойство от интерфейса
/// </summary>
public object ID { get; set; }
/// <summary>
/// Конструтор + реализация поведения конструктора абстрактного класса
/// </summary>
public ClassMain() : base (0)
{
TestStruct testStruct = new TestStruct();
Console.WriteLine($"TestStruct: {testStruct.Name}, {testStruct.ID}");
Name = "Base";
ID = (object)0;
Move();
Build();
Reload();
Resize();
Open();
}
/// <summary>
/// Конструтор c параметрами + реализация поведения конструктора абстрактного класса
/// </summary>
/// <param name="build">#</param>
/// <param name="name">#</param>
/// <param name="id">#</param>
public ClassMain(int build, string name, object id) : base(build)
{
countBuild = build;
Name = name;
ID = id;
Move();
Build(build);
Reload();
Resize();
Open();
}
/// <summary>
/// Виртуальный метод
/// </summary>
public virtual void GG()
{
Console.WriteLine("GG Virtual Method Class");
}
/// <summary>
/// Метод с параметрами
/// </summary>
/// <param name="build">#</param>
public void Build(int build = 0)
{
Console.WriteLine($"Build Interface Class {build}");
}
/// <summary>
/// Метод без параметров обязательный к реализации от интерфейса
/// </summary>
public void Reload()
{
Console.WriteLine("Reload Interface Abstract Method Class");
}
/// <summary>
/// Реализация virtual метода абстрактного класса
/// </summary>
public override void Resize()
{
base.Resize();
countBuild--;
Console.WriteLine("Resize Class");
}
/// <summary>
/// Переопределение сигнатуры абстрактного класса
/// </summary>
public override void Open()
{
Console.WriteLine("Open Abstract Method Class");
}
/// <summary>
/// Реализация деструктора класса
/// </summary>
~ClassMain()
{
Console.WriteLine("###Destroy ClassMain");
}
}
/// <summary>
/// Реализация наследования (3 принцип ООП)
/// Определение:
/// Наследование - это возможность создания новых абстракций на основе существующих.
/// Наследование является ключевой функцией объектно-ориентированных языков программирования.
/// Оно позволяет определить базовый класс для определенных функций (доступа к данным или действий),
/// а затем создавать производные классы, которые наследуют или переопределяют функции базового класса.
/// </summary>
public class Nasled : ClassMain
{
/// <summary>
/// Необязательное перепределение виртуального метода главного класса
/// </summary>
public override void GG()
{
base.GG();
}
}
/// <summary>
/// Определение:
/// Records - это ссылочный тип, некая модификация возможностей классов
/// Ключевая особенность - может представлять неизменяемый тип данных (immutable)
/// Также имеет особенность в виде встроенного JSON представления при выводе в строку
/// Имеет возможность управлять своим деконструктором
/// </summary>
public record class Records
{
/// <summary>
/// Свойство идентификатора
/// </summary>
public int Id { get; init; }
/// <summary>
/// Свойство имени
/// </summary>
public string Name { get; init; }
/// <summary>
/// Конструктор с параметрами
/// </summary>
/// <param name="id">идентификатор</param>
/// <param name="name">имя</param>
public Records(int id, string name)
{
Id = id;
Name = name;
Console.WriteLine("Construct");
}
public class GlobalInfo
{
public int Id;
public string Name;
public int Ida;
public string Names;
}
/// <summary>
/// Деконструктор
/// </summary>
/// <param name="name">имя</param>
/// <param name="id">идентификатор</param>
public void Deconstruct(out string name, out int id)
{
name = Name;
id = Id;
Console.WriteLine("Destruct");
}
}
public record class Person
{
public int Id { get; init; }
public string Name { get; init; }
/// <summary>
/// Деконструктор
/// </summary>
/// <param name="name">имя</param>
/// <param name="id">идентификатор</param>
public void Deconstruct(out string name, out int id)
{
name = Name;
id = Id;
Console.WriteLine("Destruct Person");
}
}
public record class Job
{
public int Ida { get; init; }
public string Names { get; init; }
/// <summary>
/// Деконструктор
/// </summary>
/// <param name="name">имя</param>
/// <param name="id">идентификатор</param>
public void Deconstruct(out string name, out int id)
{
name = Names;
id = Ida;
Console.WriteLine("Destruct Job");
}
}

@ -0,0 +1,31 @@
using Base;
namespace BaseTests;
/// <summary>
/// Модульный тест
/// Конфигурирование:
/// Чтобы добавить возможность вызывать методы какого-либо проекта
/// Нажимаем правой кнопкой на зависимости в данном проекте
/// Выбираем пункт - добавить ссылку на проект
/// </summary>
[TestClass]
public class TestsMain
{
/// <summary>
/// Реализация тестового метода модульного теста
/// </summary>
[TestMethod]
public void TestMethod1()
{
// arrange
int expected = 3;
// act
var classMain = new ClassMain(4, "Unit", 10);
int actual = classMain.countBuild;
// assert
Assert.AreEqual(expected, actual, 0.001, "BuildCount not correctly"); //сравниваем полученное значение с требуемым
}
}

@ -0,0 +1,38 @@
using System.Diagnostics;
namespace Base.Tests;
[TestClass]
public class TestInitAndCleanUp
{
private ClassMain main;
private string Name;
/// <summary>
/// Запускается перед каждым тестируемым методом
/// </summary>
[TestInitialize]
public void TestInitialize()
{
Debug.WriteLine("Test Initialize");
main = new ClassMain();
main.Name = "Nikolay";
}
/// <summary>
/// Запускается после каждого завершения тестирования метода
/// </summary>
[TestCleanup]
public void MainCleanUp()
{
Debug.WriteLine("Test CleanUp");
Name = string.Empty;
}
[TestMethod]
public void AddName()
{
Name = "Nikolay";
Assert.AreEqual(Name, main.Name);
}
}

@ -0,0 +1,41 @@

using System.Diagnostics;
using System.Xml.Linq;
namespace Base.Tests;
[TestClass]
public class ClassInitAndCleanUp
{
private static ClassMain main;
/// <summary>
/// Запускается один раз перед тем как запустится один Unit Test
/// Метод должен быть открытым, статическим и принимать параметр типа контекста
/// </summary>
/// <param name="context"></param>
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
main = new ClassMain();
main.Name = "Test";
}
/// <summary>
/// Запускается после последнего тестируемого метода
/// Метод должен быть открытым, статическим и возвращать void
/// </summary>
[ClassCleanup]
public static void MainCleanUp()
{
Debug.WriteLine("Test CleanUp");
main.Name = string.Empty;
}
[TestMethod]
public void AddName()
{
var Name = "Test";
Assert.AreEqual(Name, main.Name);
}
}

@ -0,0 +1,26 @@
namespace Base.Tests;
[TestClass]
public class AssemblyInit
{
/// <summary>
/// Код выполняется один раз на всю сборку
/// Используется во всех Unit тестах во всех тестовых вкладках
/// </summary>
/// <param name="testContext"></param>
[AssemblyInitialize]
public static void TestMethodInit(TestContext testContext)
{
Console.WriteLine("Test AssemblyInitialize: " + testContext.TestName);
}
/// <summary>
/// Код выполняется один раз на всю сборку
/// Используется во всех Unit тестах во всех тестовых вкладках
/// </summary>
[AssemblyCleanup]
public static void TestMethodGlobalCleanUp()
{
Console.WriteLine("Test AssemblyCleanup");
}
}

@ -0,0 +1,65 @@
namespace Base.Tests;
[TestClass]
public class AssertMethods
{
[TestMethod]
public void IsSqrtTest()
{
// arrange
const double input = 4;
const double expected = 2;
// act
var actual = AssertMsTest.GetSqrt(input);
// assert - сравнивает два значения
Assert.AreEqual(expected, actual, $"Sqrt of {input} should have been {expected}");
}
[TestMethod]
public void DeltaTest()
{
const double expected = 3.1;
const double delta = 0.07;
// 3.1622776601683795
// 0.062..
double actual = AssertMsTest.GetSqrt(10);
// Проверка значений на равенство с учётом прогрешлоости delta
Assert.AreEqual(expected, actual, delta, $"Sqrt of {actual} should have been {expected}");
}
[TestMethod]
public void StringAreEqualTest()
{
// arrange
const string expected = "hello";
const string input = "HELLO";
// act and assert
// третий параметр игнорирование регистра
Assert.AreEqual(expected, input, true);
}
[TestMethod]
public void StringAreSameTest()
{
string a = "Hello";
string b = "Hello";
// проверка равенства ссылок
Assert.AreSame(a, b);
}
[TestMethod]
public void IntegerAreSameTest()
{
int a = 10;
int b = 10;
// проверка равенства ссылок
Assert.AreSame(a, b);
}
}

@ -0,0 +1,65 @@
namespace Base.Tests;
/// <summary>
/// Проверяет результат работы с коллекциями
/// </summary>
[TestClass]
public class CollectionAssertMethods
{
public static List<string> employees;
[ClassInitialize]
public static void InitializeCurrentTest(TestContext context)
{
employees = new List<string>();
employees.Add("Nikolay");
employees.Add("Oleg");
}
/// <summary>
/// Проверка значений коллекции на наличие в ней
/// </summary>
[TestMethod]
public void AllItemAreNotNullTest()
{
CollectionAssert.AllItemsAreNotNull(employees, "Not null failed");
}
/// <summary>
/// Проверка значения коллекции на уникальность
/// </summary>
[TestMethod]
public void AllItemsAreUniqueTest()
{
CollectionAssert.AllItemsAreUnique(employees, "Uniqueness failed");
}
/// <summary>
/// Проверяет каждый элемент списка на равенство с входящим списком
/// </summary>
[TestMethod]
public void AreEqualTest()
{
var currList = new List<string>();
currList.Add("Nikolay");
currList.Add("Oleg");
CollectionAssert.AreEqual(currList, employees);
}
/// <summary>
/// Проверяем наличии одного List в другом
/// </summary>
[TestMethod]
public void SubsetTest()
{
var subsetList = new List<string>();
subsetList.Add(employees[1]);
//subsetList.Add("Mig"); //ошибка так как этот элемент не входит в employees
CollectionAssert.IsSubsetOf(subsetList, employees, "not elements subsetList to employees");
}
}

@ -0,0 +1,44 @@
using System.Text.RegularExpressions;
namespace Base.Tests;
[TestClass]
public class StringAssetMethods
{
/// <summary>
/// Проверка подстроки в строке
/// </summary>
[TestMethod]
public void StringContainsTest()
{
StringAssert.Contains("Assert samples", "sam");
}
/// <summary>
/// ПРоверка с использованием регулярного выражения
/// </summary>
[TestMethod]
public void StringMathesTest()
{
// проверяет наличие трёх цифр подряд
StringAssert.Matches("123", new Regex(@"\d{3}"));
}
/// <summary>
/// Проверка начала строки на соответствие условию
/// </summary>
[TestMethod]
public void StringStartsWithTest()
{
StringAssert.StartsWith("Hello London", "H");
}
/// <summary>
/// Проверка конца строки на соответствие условию
/// </summary>
[TestMethod]
public void StringEndWithTest()
{
StringAssert.EndsWith("Hello Moscow", "w");
}
}

@ -0,0 +1,27 @@
namespace Base.Tests;
[TestClass]
public class ExpectingExceptions
{
/// <summary>
/// Проверка метода на возврат исключения
/// </summary>
[ExpectedException(typeof(ArgumentNullException), "Exception was not throw")]
[TestMethod]
public void AssertMsTestExceptionTest()
{
var ms = new AssertMsTest();
ms.SayHello(null);
}
[TestMethod]
public void AssertMsTestReturnTest()
{
var name = "Hi! Nikolay";
var ms = new AssertMsTest();
var actual = ms.SayHello("Nikolay");
Assert.AreEqual(name, actual, $"name: {name} act: {actual}");
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Base\BaseInfo.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,96 @@
/* Мост
Разделяет абстракцию и реализацию так,
чтобы они могли изменяться независимо друг от друга
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var programmer_1 = new FreelancerProgger(new CPPLang());
programmer_1.DoWork();
programmer_1.EarnMoney();
var programmer_2 = new FreelancerProgger(new CSharpLang());
programmer_2.DoWork();
programmer_2.EarnMoney();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Поведение языка
/// </summary>
interface ILanguage
{
void Build();
void Execute();
}
class CPPLang : ILanguage
{
public void Build()
{
Console.WriteLine("C++ compile");
}
public void Execute()
{
Console.WriteLine("C++ Start");
}
}
class CSharpLang : ILanguage
{
public void Build()
{
Console.WriteLine("C# compile");
}
public void Execute()
{
Console.WriteLine("C# Start");
}
}
abstract class Programmer
{
protected ILanguage language;
public ILanguage Language
{
set { language = value; }
}
public Programmer(ILanguage language)
{
Language = language;
}
public virtual void DoWork()
{
language.Build();
language.Execute();
}
public abstract void EarnMoney();
}
class FreelancerProgger : Programmer
{
public FreelancerProgger(ILanguage language) : base(language) { }
public override void EarnMoney()
{
Console.WriteLine("Получаем оплату за заказ");
}
}
class CorporateProgger : Programmer
{
public CorporateProgger(ILanguage language) : base(language) { }
public override void EarnMoney()
{
Console.WriteLine("Получаем оплату в конце месяца");
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

120
Patterns/Builder/Program.cs Normal file

@ -0,0 +1,120 @@
/* Строитель
Разделяет создание сложного объекта
и его инициализацию так, что одинаковый
процесс построения может может создавать
объекты с разным состоянием
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var rx = new Baker();
var bread = rx.Bake(new RBuilderBread());
Console.WriteLine(bread.ToString());
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Мука
/// </summary>
class Floor
{
/// <summary>
/// Сорт муки
/// </summary>
public string Sort { get; set; }
}
/// <summary>
/// Соль
/// </summary>
class Salt
{
/// <summary>
/// Масса
/// </summary>
public double Mass { get; set; }
}
/// <summary>
/// Пищевые добавки
/// </summary>
class Additives
{
/// <summary>
/// Список пищевых добавок
/// </summary>
public string[] Names { get; set; }
}
/// <summary>
/// Xлеб
/// </summary>
class Bread
{
public Floor Floor { get; set; }
public Salt Salt { get; set; }
public Additives Additives { get; set; }
public override string ToString()
{
return $"[F: {Floor.Sort}]---[S: {Salt.Mass}]---[A: {Additives.Names[0]}]";
}
}
/// <summary>
/// Строитель хлеба
/// </summary>
abstract class BreadBuilder
{
public Bread Bread { get; set; }
public void CreateBread()
{
Bread = new Bread();
}
public abstract void SetFloor();
public abstract void SetSalt();
public abstract void SetAdditives();
}
/// <summary>
/// Пекарь
/// </summary>
class Baker
{
public Bread Bake(BreadBuilder breadBuilder)
{
breadBuilder.CreateBread();
breadBuilder.SetFloor();
breadBuilder.SetSalt();
breadBuilder.SetAdditives();
return breadBuilder.Bread;
}
}
/// <summary>
/// Для ржаного хлеба строитель
/// </summary>
class RBuilderBread : BreadBuilder
{
public override void SetAdditives()
{
Bread.Additives = new Additives() { Names = new[] { "E222", "E297" } };
}
public override void SetFloor()
{
Bread.Floor = new Floor() { Sort = "R class" };
}
public override void SetSalt()
{
Bread.Salt = new Salt() { Mass = 3.44 };
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,165 @@
/* Цепочка обязанностей
Избегает связывание отправителя запроса
с его получателем, давая возможность обработать
запрос более чем одному объекту. Связывает
объекты-получатели и передаёт запрос по цепочке
пока объект не обработает его.
*/
class Program
{
public static void GiveCommand(IWorker worker, string command)
{
var str = worker.Execute(command);
if(string.IsNullOrEmpty(str)) Console.WriteLine(command + " - никто не выполнил команду");
else Console.WriteLine(str);
}
static void Main()
{
#region Пример 1 - базовое
Handler h1 = new ConcreateHandler1();
Handler h2 = new ConcreateHandler2();
h1.Successor = h2;
h1.HandleRequest(2); //От первого до второго объекта обработка
Console.WriteLine("Please press Enter...");
Console.ReadKey();
#endregion
#region Пример 2 - этапы строительства дома
var designer = new Designer();
var programmer = new Programmer();
var finishworker = new FinishWorker();
designer.SetNetWorker(finishworker).SetNetWorker(programmer);
GiveCommand(designer, "Спроектировать веранду");
GiveCommand(designer, "Сделать машину времени");
GiveCommand(designer, "Уволить работников");
GiveCommand(designer, "Курить");
#endregion
}
}
/// <summary>
/// Передатчик
/// </summary>
abstract class Handler
{
public Handler Successor { get; set; }
public abstract void HandleRequest(int condition);
}
/// <summary>
/// Обработчик запроса №1
/// </summary>
class ConcreateHandler1 : Handler
{
/// <summary>
/// Обработка запроса
/// </summary>
/// <param name="condition">состояние</param>
public override void HandleRequest(int condition)
{
Console.WriteLine("1");
if(condition == 1) return; //завершаем выполнение
else if(Successor != null)
Successor.HandleRequest(condition); //передача запроса дальше по цепи
}
}
/// <summary>
/// Обработчик запроса №2
/// </summary>
class ConcreateHandler2 : Handler
{
/// <summary>
/// Обработка запроса
/// </summary>
/// <param name="condition">состояние</param>
public override void HandleRequest(int condition)
{
Console.WriteLine("2");
if (condition == 2) return; //завершаем выполнение
else if (Successor != null) //передача запроса дальше по цепи
Successor.HandleRequest(condition);
}
}
/// <summary>
/// Поведение рабочего
/// </summary>
interface IWorker
{
/// <summary>
/// Передача обязанностей следующему рабочему
/// </summary>
/// <param name="worker">следующий рабочий</param >
IWorker SetNetWorker(IWorker worker);
/// <summary>
/// Рабочий принимает команду на исполнение
/// </summary>
/// <param name="command">команда</param>
/// <returns>Резульат принятия</returns>
string Execute(string command);
}
/// <summary>
/// Абстрактный рабочий, базовое описание структуры каждого
/// </summary>
abstract class AbsWorker : IWorker
{
private IWorker nextWorker;
public AbsWorker() => nextWorker = null;
/// <summary>
/// Изменяемый процесс обработки команды в классах наследниках
/// У каждого рабочего свой процесс выполнени
/// </summary>
/// <param name="command">команда</param>
/// <returns>Результат</returns>
public virtual string Execute(string command)
{
if (nextWorker == null) return string.Empty;
return nextWorker.Execute(command);
}
/// <summary>
/// Передача обязанностей другому рабочему
/// </summary>
/// <param name="worker">Другой рабочий</param>
/// <returns>Другой рабочий</returns>
public IWorker SetNetWorker(IWorker worker)
{
nextWorker = worker;
return worker;
}
}
class Designer : AbsWorker
{
public override string Execute(string command)
{
if (command == "Спроектировать веранду")
return "Проектировщик выполнил команду: " + command;
else return base.Execute(command); //если не может выполнить передаёт следующему в цепочке
}
}
class Programmer: AbsWorker
{
public override string Execute(string command)
{
if(command == "Сделать машину времени")
return "Программист выполнил команду: " + command;
else return base.Execute(command);
}
}
class FinishWorker : AbsWorker
{
public override string Execute(string command)
{
if (command == "Уволить работников")
return "Начальник выполнил команду: " + command;
else return base.Execute(command);
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

225
Patterns/Command/Program.cs Normal file

@ -0,0 +1,225 @@
/* Команда
Инкапсулирует запрос в виде объекта
позволяя передавать их клиентам в
качестве параметров, ставить в очередь,
логировать, а также поддерживать отмену
операций
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var initCommand = new Invoker(new ConcreteCommand(new Receiver()));
initCommand.Run();
initCommand.Cancel();
Console.WriteLine("Please press Enter...");
Console.ReadKey();
#endregion
#region Пример 2 - пульт управления конвеерной установкой
var conveyor = new Conveyor(); // создаём конвеер
var multipult = new Multipult(); // создаём пульт управления конвеером
multipult.SetCommand(0, new ConveyorWorkCommand(conveyor));
multipult.SetCommand(1, new ConveyorAjustCommand(conveyor));
multipult.PressOn(0);
multipult.PressOn(1);
multipult.PressCansel();
multipult.PressCansel();
#endregion
}
}
/// <summary>
/// Описания общего поведения объекта
/// </summary>
abstract class Command
{
public abstract void Execute();
public abstract void Undo();
}
/// <summary>
/// Описание процесса создания команды
/// </summary>
class ConcreteCommand : Command
{
Receiver receiver;
public ConcreteCommand(Receiver receiver)
{
this.receiver = receiver;
}
/// <summary>
/// Инициализация команды
/// *вызывает его получателя
/// </summary>
public override void Execute()
{
receiver.Operation();
}
/// <summary>
/// Остановка команды
/// </summary>
public override void Undo()
{
Console.WriteLine("Stop");
}
}
/// <summary>
/// Описание возможностей получателя команды
/// </summary>
class Receiver
{
/// <summary>
/// Обработка получателем команды
/// </summary>
public void Operation()
{
Console.WriteLine("Processing...");
}
}
/// <summary>
/// Описание инициатора команды
/// </summary>
class Invoker
{
Command command;
/// <summary>
/// Принимает в себя команду
/// </summary>
/// <param name="command">#</param>
public Invoker(Command command)
{
this.command = command;
}
/// <summary>
/// Запускает команду
/// </summary>
public void Run()
{
command.Execute();
}
/// <summary>
/// Отменяет выполнение команды
/// </summary>
public void Cancel()
{
command.Undo();
}
}
/// <summary>
/// Поведение команды
/// </summary>
interface ICommand
{
void Positive();
void Negative();
}
/// <summary>
/// Класс конвеера
/// </summary>
class Conveyor
{
public void On() => Console.WriteLine("Включение конвеера");
public void Off() => Console.WriteLine("Выключение конвеера");
public void SpeedIncrease() => Console.WriteLine("Скорость конвеера увеличена");
public void SpeedDecrease() => Console.WriteLine("Скорость конвеера снижена");
}
/// <summary>
/// Класс управления работой конвеера
/// </summary>
class ConveyorWorkCommand : ICommand
{
public Conveyor conveer;
/// <summary>
/// Передача типа конвеера в конструторе
/// </summary>
/// <param name="conveer">тип</param>
public ConveyorWorkCommand(Conveyor conveer) => this.conveer = conveer;
public void Negative() => conveer.Off();
public void Positive() => conveer.On();
}
/// <summary>
/// Класс регулировки конвеера
/// </summary>
class ConveyorAjustCommand : ICommand
{
public Conveyor conveer;
/// <summary>
/// Передача типа конвеера в конструторе
/// </summary>
/// <param name="conveer">тип</param>
public ConveyorAjustCommand(Conveyor conveer) => this.conveer = conveer;
public void Negative() => conveer.SpeedDecrease();
public void Positive() => conveer.SpeedIncrease();
}
/// <summary>
/// Пульт управления конвеером
/// </summary>
class Multipult
{
/// <summary>
/// Все возможные команды
/// </summary>
private List<ICommand> commands;
/// <summary>
/// История выполненных команд для возможной их отмены
/// </summary>
private Stack<ICommand> history;
public Multipult()
{
commands = new List<ICommand>() { null, null };
history = new Stack<ICommand>();
}
/// <summary>
/// Устанавлием список команд по индексу кнопки
/// </summary>
public void SetCommand(int btn, ICommand command) => commands[btn] = command;
/// <summary>
/// Вызывает команду из списка по указанному индексу
/// и запишет в историю команд выполненную команду
/// </summary>
/// <param name="btn">идекс кнопки</param>
public void PressOn(int btn)
{
commands[btn].Positive();
history.Push(commands[btn]);
}
/// <summary>
/// Извлекает команду из истории и отменяет её
/// </summary>
public void PressCansel()
{
if(history.Count == 0) return;
var oldC = history.Pop();
oldC.Negative();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,129 @@
/* Компоновщик
Компонует объекты в древовидную структуру по принципу "часть-целое",
представляя их в виде иерархии. Позволяет
клиенту одинаково обращаться как к отдельному,
так и к целому поддереву
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var paths = new Paths(new Dictionary<int, Directory>());
paths.components.Add(1, new Directory("C"));
paths.components[1].Add(new Folder("SYSTEM"));
paths.components[1].Add(new Folder("DATA"));
paths.components[1].Add(new File("test.txt"));
paths.components.Add(0, new Directory("F"));
paths.components[0].Add(new File("resize.cs"));
paths.Print();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Абстракция компонента файловой системы (дерева) - пути до файла
/// </summary>
abstract class Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
public virtual void Add(Component component) { }
public abstract void Remove(Component component);
public abstract void Print();
}
class Paths : Component
{
public Dictionary<int,Directory> components;
public Paths(Dictionary<int, Directory> components) : base ("")
{
this.components = components;
}
public override void Print()
{
foreach (var component in components)
{
component.Value.Print();
Console.WriteLine();
}
}
public override void Remove(Component component)
{
Console.WriteLine("Delete Path" + this.name);
}
}
class Directory : Component
{
public List<Component> components = new();
public Directory(string name)
: base(name)
{
}
public override void Add(Component component)
{
components.Add(component);
}
public override void Print()
{
Console.Write(this.name + ":");
foreach (var component in components)
{
component.Print();
}
}
public override void Remove(Component component)
{
component.Remove(component);
}
}
class Folder : Component
{
public Folder(string name)
: base(name)
{
}
public override void Print()
{
Console.Write("\\" + this.name);
}
public override void Remove(Component component)
{
Console.WriteLine(this.name + " Delete");
}
}
class File : Component
{
public File(string name)
: base(name)
{
}
public override void Print()
{
Console.Write("\\" + this.name);
}
public override void Remove(Component component)
{
Console.WriteLine(this.name + " Delete");
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,62 @@
/* Декоратор
Динамически предоставляет объекту
дополнительные возможности. Представляет
собой гибкую альтернативу наследованию
для расширения функциональности.
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
Pizza r = new RussianPizza();
Console.WriteLine(r.GetCost());
Pizza i = new TomatoPizza(r);
Console.WriteLine(i.GetCost());
Console.ReadKey();
#endregion
}
}
abstract class Pizza
{
public string Name { get; set; }
public Pizza(string name)
{
Name = name;
}
public abstract int GetCost();
}
class RussianPizza : Pizza
{
public RussianPizza() : base("Russian Pizza")
{
}
public override int GetCost()
{
return 1000;
}
}
abstract class PizzaDecorator : Pizza
{
protected Pizza pizza;
protected PizzaDecorator(string name, Pizza pizza) : base(name)
{
this.pizza = pizza;
}
}
class TomatoPizza : PizzaDecorator
{
public TomatoPizza(Pizza pizza) : base(pizza.Name + ", tomato", pizza)
{
}
public override int GetCost()
{
return pizza.GetCost() + 100;
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
</Project>

116
Patterns/Dict/Program.cs Normal file

@ -0,0 +1,116 @@
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Specialized;
using System.Diagnostics;
class Program
{
/// <summary>
/// Стандартный Dictionary
/// Быстрый поиск с помощью ключей, можно добавлять и удалять элементы
/// </summary>
private static readonly Dictionary<string, object> Dictionary = new();
/// <summary>
/// ListDictionary
/// Он меньше и быстрее, чем Hashtable если количество элементов равно 10 или меньше
/// </summary>
private static readonly ListDictionary LDictionary = new()
{
{ "key", "value"}
};
/// <summary>
/// HybridDictionary
/// Рекомендуется для случаев, когда количество элементов в словаре неизвестно.
/// Он использует улучшенную производительность ListDictionary с небольшими коллекциями
/// и предлагает гибкость переключения на Hashtable , которая обрабатывает большие коллекции лучше
/// </summary>
private static readonly HybridDictionary HDictionary = new()
{
{ "key", "value"}
};
/// <summary>
/// OrderedDictionary
/// Он всегда упорядочен при выводе foreach
/// Ключ не может быть нулевым , но значение может быть.
/// Каждый элемент представляет собой пару ключ/значение, хранящуюся в объекте DictionaryEntry
/// Доступ к элементам возможен либо по ключу, либо по индексу.
/// [!]
/// если элементов больше 20-ти быстрее при цикле for
/// если элементов меньше 15-20 быстрее в foreach чем for
/// </summary>
private static readonly OrderedDictionary ODictionary = new()
{
{"01", "odin"},
{"02", "dva"},
{"03", "tri"},
{"04", "chetiri"},
{"06", "pyat"},
{"07", "pyat"},
{"08", "pyat"},
{"09", "pyat"},
{"10", "pyat"},
{"11", "pyat"},
{"12", "pyat"},
{"13", "pyat"},
{"14", "pyat"},
{"15", "pyat"},
{"16", "pyat"},
{"17", "pyat"},
{"18", "pyat"},
{"19", "pyat"},
{"20", "pyat"},
{"21", "pyat"},
{"22", "pyat"},
{"23", "pyat"},
{"24", "pyat"},
{"25", "pyat"},
{"26", "pyat"},
{"27", "pyat"},
{"28", "pyat"},
{"29", "pyat"},
{"30", "pyat"},
{"31", "pyat"}
};
/// <summary>
/// SortedDictionary
/// Дерево бинарного поиска, в котором все элементы отсортированы на основе ключа
/// Быстрее вставляет и удаляет элементы
/// </summary>
private static readonly SortedDictionary<int, string> SDictionary = new();
/// <summary>
/// ConcurrentDictionary
/// Потокобезопасная коллекция пар "ключ-значение", доступ к которой могут одновременно получать несколько потоков.
/// по умолчанию 4 потока на запись concurrencyLevel = 4
/// первоначальное число элементов 31 сapacity = 31
/// В отличие от обычного Dictionary, можно производить вставку в ConcurrentDictionary или удаление из него прямо во время перечисления
/// </summary>
private static readonly ConcurrentDictionary<int, string> СoncurrentDictionary = new();
static void Main()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for(int i = 0; i < ODictionary.Count; i++)
{
string val = (string)ODictionary[i];
Console.WriteLine(val);
}
stopwatch.Stop();
Console.WriteLine("[for][el > 20]: " + stopwatch.Elapsed);
stopwatch.Reset();
stopwatch.Start();
foreach (DictionaryEntry item in ODictionary)
{
Console.WriteLine(item.Value);
}
stopwatch.Stop();
Console.WriteLine("[foreach][el > 20]: " + stopwatch.Elapsed);
Console.ReadKey();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,55 @@
/* Фасад
Предоставляет единый интерфейс к группе
интерфейсов подсистемы. Определяет высокоуровневый
интерфейс, делая систему проще для использования.
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var facade = new Facade(new A(), new B());
facade.Start();
Console.ReadKey();
#endregion
}
}
class Facade
{
ILogic logic1;
ILogic logic2;
public Facade(ILogic logic1, ILogic logic2)
{
this.logic1 = logic1;
this.logic2 = logic2;
}
public void Start()
{
logic1.Process();
logic2.Process();
}
}
interface ILogic
{
void Process();
}
class A : ILogic
{
public void Process()
{
Console.WriteLine("Some Process " + GetType().Name);
}
}
class B : ILogic
{
public void Process()
{
Console.WriteLine("Some Process " + GetType().Name);
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,120 @@
/* Фабричный метод
Определяет интерфейс для создания объекта,
но позволяет подклассам решать, какой класс создавать.
Позволяет делегировать создание класса
объектам класса.
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var ltd = new WoodDeveloper();
ltd.Create();
var rss = new OfficeDeveloper();
rss.Create();
Creator<WoodDeveloper> ltdEx = new Creator<WoodDeveloper>();
var a1 = ltdEx.FactoryMethod();
a1.Create();
Creator<OfficeDeveloper> rssEx = new Creator<OfficeDeveloper>();
var a2 = rssEx.FactoryMethod();
a2.Create();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// *** представления через обобщения (нельзя инициализировать через параметризированный конструктор)
/// </summary>
/// <typeparam name="T">обобщающий тип</typeparam>
class Creator<T> where T : Developer, new()
{
public T FactoryMethod() { return new T(); }
}
/// <summary>
/// Cтроительная компания - базовая логика
/// </summary>
abstract class Developer
{
protected string Name { get; set; }
public Developer(string name)
{
Name = name;
}
/// <summary>
/// Фабричный метод
/// </summary>
/// <returns>House</returns>
public abstract House Create();
}
class WoodDeveloper : Developer
{
public WoodDeveloper() : base("Wood Develop LTD")
{
}
public override House Create()
{
return new PanelHouse();
}
}
class OfficeDeveloper : Developer
{
public OfficeDeveloper() : base("Office Develop RSS")
{
}
public override House Create()
{
return new OfficeHouse();
}
}
/// <summary>
/// Общая логика операций над строением
/// </summary>
abstract class House
{
public abstract void Build();
}
/// <summary>
/// Панельный дом
/// </summary>
class PanelHouse : House
{
public PanelHouse()
{
Build();
}
public override void Build()
{
Console.WriteLine("Build Panel House");
}
}
/// <summary>
/// Офисное здание
/// </summary>
class OfficeHouse : House
{
public OfficeHouse()
{
Build();
}
public override void Build()
{
Console.WriteLine("Build Office House");
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,68 @@
/* Гибкий(плавный, текучий) строитель (интерфейс)
Позволяет упростить процесс создания сложных
объектов с помощью методов-цепочек, которые
наделяют объект каким-то определенным качеством
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
User user = new User().Create().SetName("Alex").SetPassword("admin");
Console.WriteLine(user);
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Шаблон пользователя
/// </summary>
class User
{
public string Name { get; set; }
public string Password { get; set; }
public UserBuilder Create()
{
return new UserBuilder();
}
public override string ToString()
{
return $"Name {Name}, Password {Password}";
}
}
/// <summary>
/// Шаблон гибкого строителя конфигурации пользователя
/// </summary>
class UserBuilder
{
private User CurrentUser { get; set; }
public UserBuilder()
{
CurrentUser = new User();
}
public UserBuilder SetName(string name)
{
CurrentUser.Name = name;
return this;
}
public UserBuilder SetPassword(string password)
{
CurrentUser.Password = password;
return this;
}
/// <summary>
/// преобразуем тип Builder в тип User для которого он использовался
/// </summary>
/// <param name="builder">строитель</param>
public static implicit operator User(UserBuilder builder)
{
return builder.CurrentUser;
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,97 @@
/* Приспособленец
Благодаря совместному использованию,
поддерживает эффективную работу
с большим количеством объектов.
(для оптимизации работы с памятью)
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
double longtitude = 22.33;
double latitude = 55.11;
HouseFactory houseFactory = new HouseFactory();
for (int i = 0; i < 10; i++)
{
House panelH = houseFactory.GetHouse("Panel");
if(panelH != null)
panelH.Build(longtitude, latitude);
longtitude += 0.1;
latitude += 0.1;
}
for (int i = 0; i < 10; i++)
{
House officeH = houseFactory.GetHouse("Office");
if (officeH != null)
officeH.Build(longtitude, latitude);
longtitude += 0.1;
latitude += 0.1;
}
Console.ReadKey();
#endregion
}
}
abstract class House
{
/// <summary>
/// Кол-во этажей - внутреннее состояние
/// </summary>
protected int stages;
/// <summary>
/// Внешнее состояние действия
/// </summary>
/// <param name="latitude"></param>
/// <param name="longitude"></param>
public abstract void Build(double latitude, double longitude);
}
class PanelHouse : House
{
public PanelHouse()
{
stages = 5;
}
public override void Build(double latitude, double longitude)
{
Console.WriteLine($"PanelHouse Build stages-{stages} {latitude}, {longitude}");
}
}
class OfficeHouse : House
{
public OfficeHouse()
{
stages = 50;
}
public override void Build(double latitude, double longitude)
{
Console.WriteLine($"OfficeHouse Build stages-{stages} {latitude}, {longitude}");
}
}
class HouseFactory
{
Dictionary<string, House> houses = new Dictionary<string, House>();
public HouseFactory()
{
houses.Add("Panel", new PanelHouse());
houses.Add("Office", new OfficeHouse());
}
public House GetHouse(string key)
{
if (houses.ContainsKey(key))
return houses[key];
else
return null;
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,148 @@
/* Интерпретатор
Получая формальный язык, определяет
представление его грамматики и интерпретатор,
использующий это представление для обработки
выражений языка (Применяется для часто повторяющихся операций)
*/
class Program
{
public static void Main(string[] args)
{
#region Пример 1 - базовое
var context = new Context();
//создаём переменные
int x = 5;
int y = 8;
int z = 2;
int k = 10;
//задаём переменные в контекст
context.SetVariable("x", x);
context.SetVariable("y", y);
context.SetVariable("z", z);
context.SetVariable("k", k);
//(x + y - z) * k
var expressionAdd = new AddExpression(new NumberExpression("x"),
new NumberExpression("y"));
var expressionSub = new SubstructExpression(expressionAdd,
new NumberExpression("z"));
var expressionPow = new PowExpression(expressionSub, new NumberExpression("k"));
Console.WriteLine(expressionPow.Interpret(context));
Console.WriteLine("Please press Enter...");
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Агрегатор выражений
/// </summary>
class Context
{
Dictionary<string, int> variables;
public Context()
{
variables = new Dictionary<string, int>();
}
public int GetVariable(string name)
{
if(variables.ContainsKey(name))
return variables[name];
else
return -1;
}
public void SetVariable(string name, int value)
{
if(variables.ContainsKey(name))
variables[name] = value;
else
variables.Add(name, value);
}
}
/// <summary>
/// Поведение интерпретатора
/// </summary>
interface IExpression
{
int Interpret(Context context);
}
/// <summary>
/// Терминальное выражение
/// </summary>
class NumberExpression : IExpression
{
string Name { get; set; }
public NumberExpression(string name)
{
Name = name;
}
public int Interpret(Context context)
{
return context.GetVariable(Name);
}
}
/// <summary>
/// Нетерминальное выражение для сложения
/// </summary>
class AddExpression : IExpression
{
IExpression LeftExpression { get; set; }
IExpression RightExpression { get; set; }
public AddExpression(IExpression left, IExpression right)
{
LeftExpression = left;
RightExpression = right;
}
public int Interpret(Context context)
{
return LeftExpression.Interpret(context) + RightExpression.Interpret(context);
}
}
/// <summary>
/// Нетерминальное выражение для умножения
/// </summary>
class PowExpression : IExpression
{
IExpression LeftExpression { get; set; }
IExpression RightExpression { get; set; }
public PowExpression(IExpression left, IExpression right)
{
LeftExpression = left;
RightExpression = right;
}
public int Interpret(Context context)
{
return LeftExpression.Interpret(context) * RightExpression.Interpret(context);
}
}
/// <summary>
/// Нетерминальное выражение для вычитания
/// </summary>
class SubstructExpression : IExpression
{
IExpression LeftExpression { get; set; }
IExpression RightExpression { get; set; }
public SubstructExpression(IExpression left, IExpression right)
{
LeftExpression = left;
RightExpression = right;
}
public int Interpret(Context context)
{
return LeftExpression.Interpret(context) - RightExpression.Interpret(context);
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,263 @@
/* Итератор
Предоставляет способ последовательного
доступа к множеству, независимо от его
внутреннего устройства
*/
class Program
{
public static void Main(string[] args)
{
#region Пример 1 - базовое
Library library = new Library();
Reader reader = new Reader();
reader.SetBooks(library);
Console.ReadKey();
#endregion
#region Пример 2 - пример работы стека
DataStack stack = new DataStack();
for (int i = 0; i < 5; i++)
stack.Push(i);
DataStack stackCopy = new DataStack(stack);
Console.WriteLine(stack == stackCopy); //true
stackCopy.Push(10);
Console.WriteLine(stack == stackCopy); //false
#endregion
}
}
/// <summary>
/// Читатель
/// </summary>
class Reader
{
public void SetBooks(Library library)
{
IBookIterator iterator = library.CreateNumerator();
while(iterator.HasNext())
{
Book book = iterator.Next();
Console.WriteLine(book.Name);
}
}
}
/// <summary>
/// Поведение поиска библиотеки
/// </summary>
interface IBookIterator
{
bool HasNext();
Book Next();
}
/// <summary>
/// Поведение библиотеки
/// </summary>
interface IBookNumerable
{
IBookIterator CreateNumerator();
int Count { get; }
Book this[int index] { get; }
}
/// <summary>
/// Класс книги
/// </summary>
class Book
{
public string Name { get; set; }
}
/// <summary>
/// Класс библиотеки книг
/// </summary>
class Library : IBookNumerable
{
private Book[] Books { get; set; }
public Library()
{
Books = new Book[]
{
new Book(){ Name = "James"},
new Book(){ Name = "Karl"},
new Book(){ Name = "Rogan"}
};
}
/// <summary>
/// Вызов книги
/// </summary>
/// <param name="index">индекс в библиотеке</param>
/// <returns>Book</returns>
public Book this[int index] => Books[index];
/// <summary>
/// Количество книг в библиотеке
/// </summary>
public int Count => Books.Length;
/// <summary>
/// Перейти к следующей библиотеке
/// </summary>
/// <returns>IBookIterator(LibraryNumenator)</returns>
public IBookIterator CreateNumerator() => new LibraryNumenator(this);
}
class LibraryNumenator : IBookIterator
{
IBookNumerable Aggregate { get; set; }
int index = 0;
/// <summary>
/// Передача коллекции книг в Library
/// </summary>
/// <param name="bookNumerable"></param>
public LibraryNumenator(IBookNumerable bookNumerable)
{
Aggregate = bookNumerable;
}
public bool HasNext() => index < Aggregate.Count;
public Book Next() => Aggregate[index++];
}
/// <summary>
/// Класс стека данных
/// </summary>
public class DataStack
{
private int[] items = new int[10];
/// <summary>
/// Длинна массива данных в этом стеке
/// </summary>
private int lenght;
public DataStack() => lenght = -1;
/// <summary>
/// Для копирования экземпляра класса
/// </summary>
/// <param name="myStack">Экземпляр данного класса</param>
public DataStack(DataStack myStack)
{
this.items = myStack.items;
this.lenght = myStack.lenght;
}
/// <summary>
/// Свойство геттера для поля items
/// </summary>
public int[] Items { get => items; }
/// <summary>
/// Свойство геттера для поля lenght
/// </summary>
public int Lenght { get => lenght; }
/// <summary>
/// Добавление элементов в массив
/// </summary>
/// <param name="value">значение</param>
public void Push(int value) => items[++lenght] = value;
/// <summary>
/// Получение последнего элемента
/// </summary>
/// <returns>значение</returns>
public int Pop() => items[lenght--];
/// <summary>
/// Переопределение оператора сравнения двух экземпляров данного класса
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns>bool</returns>
public static bool operator ==(DataStack left, DataStack right)
{
StackIterator it1 = new StackIterator(left),
it2 = new StackIterator(right);
while (it1.IsEnd() || it2.IsEnd())
{
if (it1.Get() != it2.Get()) break;
it1++;
it2++;
}
return !it1.IsEnd() && !it2.IsEnd();
}
/// <summary>
/// Переопределение оператора сравнения двух экземпляров данного класса
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns>bool</returns>
public static bool operator !=(DataStack left, DataStack right)
{
StackIterator it1 = new StackIterator(left),
it2 = new StackIterator(right);
while (it1.IsEnd() || it2.IsEnd())
{
if (it1.Get() != it2.Get()) break;
it1++;
it2++;
}
return !it1.IsEnd() && !it2.IsEnd();
}
}
/// <summary>
/// Перечислитель
/// </summary>
class StackIterator
{
private DataStack stack;
private int index;
/// <summary>
/// Инициализируем поля перечислителя
/// </summary>
/// <param name="dataStack">данные</param>
public StackIterator(DataStack dataStack)
{
this.stack = dataStack;
this.index = 0;
}
/// <summary>
/// Переопределение опреатора инкрементирования
/// </summary>
/// <param name="s">новый переданный экземпляр класса</param>
/// <returns>экземпляр класса с инкрементированым значением index</returns>
public static StackIterator operator ++(StackIterator s)
{
s.index++;
return s;
}
/// <summary>
/// Возвращает значение элемента поля стека
/// через его свойство по текущему индексу
/// </summary>
/// <returns></returns>
public int Get()
{
if(index < stack.Lenght) return stack.Items[index];
return 0;
}
/// <summary>
/// Возвращет true при достижении предельного размера стека
/// </summary>
/// <returns>bool</returns>
public bool IsEnd() => index != stack.Lenght + 1;
}

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LetCode\LetCode.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,65 @@
namespace LetCode.Tests
{
[TestClass]
public class Tests
{
/// <summary>
/// Èíäåêñû ÷èñåë â ìàññèâå îáðàçóþùèõ ÷èñëî target
/// </summary>
[TestMethod]
public void TwoSumTest()
{
// arrange
int[] input = { 1, 2, 3 };
int[] expected = { 0, 2 };
// act
var actual = LetCodeTasks.TwoSum(input, 4);
// arrange
CollectionAssert.AreEqual(expected, actual, $"actual: {string.Join(',', actual)}, expected: {string.Join(',', expected)}");
}
[TestMethod]
public void IsPalindromeTest()
{
// arrange
int input = 99;
bool expected = true;
// act
var actual = LetCodeTasks.IsPalindrome(input);
// arrange
Assert.AreEqual(expected, actual, $"actual: {actual}, expected: {expected}");
}
[TestMethod]
public void RomanToIntTest()
{
// arrange
string input = "MCMXCIV";
int expected = 1994;
// act
var actual = LetCodeTasks.RomanToInt(input);
// arrange
Assert.AreEqual(expected, actual, $"actual: {actual}, expected: {expected}");
}
[TestMethod]
public void LongestCommonPrefixTest()
{
// arrange
string[] input = { "XXVIII", "XX", "XXII" };
string expected = "XX";
// act
var actual = LetCodeTasks.LongestCommonPrefix(input);
// arrange
Assert.AreEqual(expected, actual, $"actual: {actual}, expected: {expected}");
}
}
}

@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

160
Patterns/LetCode/Program.cs Normal file

@ -0,0 +1,160 @@
public static class LetCodeTasks
{
/// <summary>
/// Какие числа массива дают в сумме указанное число
/// </summary>
/// <param name="nums">Массив чисел</param>
/// <param name="target">Искомая сумма</param>
/// <returns>Массив индексов чисел</returns>
public static int[] TwoSum(int[] nums, int target)
{
int countNew = 0;
int[] weeks = { };
for (int k = 0; k < nums.Length-1; k++)
{
for(int i = 1; i < nums.Length; i++)
{
int a1 = nums[k];
int a2 = nums[i];
if (a1 + a2 == target)
{
if(k != i && k < i)
{
countNew++;
Array.Resize(ref weeks, weeks.Length + 2);
weeks[weeks.Length - 2] = k;
weeks[weeks.Length - 1] = i;
}
}
}
}
return weeks;
}
/// <summary>
/// Проверяет число на верность свойствам полиндрома
/// </summary>
/// <param name="x">Число</param>
/// <returns>Полиндром или нет</returns>
public static bool IsPalindrome(int x)
{
if(x.ToString().Length > 3)
{
for (int i = 0; i < x.ToString().Length; i++)
{
if (x.ToString()[i] != x.ToString()[x.ToString().Length - (i + 1)])
return false;
}
}
if(x >= 0 && x.ToString()[0] == x.ToString()[x.ToString().Length-1])
return true;
return false;
}
/// <summary>
/// Переводит римские цифры в реальное число
/// </summary>
/// <param name="s">Римский символ</param>
/// <returns>Число</returns>
public static int RomanToInt(string s)
{
var mapNumbers = new Dictionary<int, char>()
{
{ 1, 'I' }, { 5, 'V' }, { 10, 'X' }, { 50, 'L' }, { 100, 'C' }, { 500, 'D' }, { 1000, 'M' }
};
char symTmp = ' ';
int[] sumArray = { };
for (int i = 0; i < s.Length; i++)
{
foreach (var number in mapNumbers.Values)
{
if(number == s[i])
{
int numberRes = 0;
switch($"{symTmp}{number}")
{
case "IV":
numberRes = 4;
Array.Resize(ref sumArray, sumArray.Length - 1);
break;
case "IX":
numberRes = 9;
Array.Resize(ref sumArray, sumArray.Length - 1);
break;
case "XL":
numberRes = 40;
Array.Resize(ref sumArray, sumArray.Length - 1);
break;
case "XC":
numberRes = 90;
Array.Resize(ref sumArray, sumArray.Length - 1);
break;
case "CD":
numberRes = 400;
Array.Resize(ref sumArray, sumArray.Length - 1);
break;
case "CM":
numberRes = 900;
Array.Resize(ref sumArray, sumArray.Length - 1);
break;
}
if(numberRes == 0)
numberRes = mapNumbers.Where(x => x.Value == number).FirstOrDefault().Key;
Array.Resize(ref sumArray, sumArray.Length + 1);
sumArray[sumArray.Length - 1] = numberRes;
symTmp = number;
}
}
}
return sumArray.Sum();
}
/// <summary>
/// Вычисляет совпадение частей слов в массиве слов
/// </summary>
/// <param name="strs">Массив слов</param>
/// <returns>Подстрока обобщающая все слова</returns>
public static string LongestCommonPrefix(string[] strs)
{
if (strs.Length == 0)
return "";
if(strs.Length == 1)
return strs[0];
string prefix = string.Empty;
int[] leghts = { };
int tmpIndex = 0;
for (int i = 1; i < strs.Length; i++)
{
char[] word1 = strs[i-1].ToCharArray();
char[] word2 = strs[i].ToCharArray();
tmpIndex = 0;
for (int j = 0; j < word1.Length; j++)
{
if (word2.Length >= j + 1 && word1[j] == word2[j])
{
tmpIndex++;
if (prefix.Length < j + 1)
prefix += word1[j];
}
else
{
if (tmpIndex == 0)
return "";
break;
}
}
Array.Resize(ref leghts, leghts.Length + 1);
leghts[leghts.Length - 1] = tmpIndex;
}
if (prefix.Length > 0)
prefix = prefix.Substring(0, leghts.Min());
else
return "";
return prefix;
}
static void Main()
{
Console.ReadKey();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,112 @@
/* Посредник
Определяет объект инкапсулирующий способ
взаимодействия объектов. Обеспечивает слабую связь,
избавляя их от необходимости ссылаться друг на друга
и даёт возможность независимо изменять их взаимодействие.
*/
class Program
{
public static void Main(string[] args)
{
#region Пример 1 - базовое
ManagerMediator mediator = new ManagerMediator();
Colleague customer = new CustomerCollegue(mediator);
Colleague programmer = new ProgrammerCollegue(mediator);
Colleague tester = new TesterCollegue(mediator);
mediator.Customer = customer;
mediator.Programmer = programmer;
mediator.Tester = tester;
customer.Send("Есть заказ! Нужно сделать REST API");
programmer.Send("REST API готов, нужно протестировать swagger");
tester.Send("Тест прошёл успешно, документация отличная!");
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Интерфейс для взаимодействия с посредником
/// </summary>
abstract class Mediator
{
public abstract void Send(string message, Colleague colleague);
}
/// <summary>
/// Интерфейс для взаимодействия с коллегами
/// </summary>
abstract class Colleague
{
Mediator Mediator { get; set; }
public Colleague(Mediator mediator)
{
Mediator = mediator;
}
public virtual void Send(string message)
{
Mediator.Send(message, this);
}
public abstract void Notify(string message);
}
/// <summary>
/// Непосредственный заказчик
/// </summary>
class CustomerCollegue : Colleague
{
public CustomerCollegue(Mediator mediator) : base(mediator) {}
public override void Notify(string message)
{
Console.WriteLine($"Сообщение заказчику: {message}");
}
}
/// <summary>
/// Программист
/// </summary>
class ProgrammerCollegue : Colleague
{
public ProgrammerCollegue(Mediator mediator) : base(mediator) { }
public override void Notify(string message)
{
Console.WriteLine($"Сообщение программисту: {message}");
}
}
/// <summary>
/// Тестировщик
/// </summary>
class TesterCollegue : Colleague
{
public TesterCollegue(Mediator mediator) : base(mediator) { }
public override void Notify(string message)
{
Console.WriteLine($"Сообщение тестировщику: {message}");
}
}
/// <summary>
/// Посредник
/// </summary>
class ManagerMediator : Mediator
{
public Colleague Customer { get; set; }
public Colleague Programmer { get; set; }
public Colleague Tester { get; set; }
public override void Send(string message, Colleague colleague)
{
if(Customer == colleague) //если отправитель заказчик значит есть новый заказ
Programmer.Notify(message); //отправляем сообщение программисту - сделать заказ
else if(Programmer == colleague) //если отправитель программист
Tester.Notify(message); //отправляем сообщение тестировщику
else if(Tester == colleague) //если отправитель тестировщик
Customer.Notify(message); //значит оповещаем заказчика
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
</Project>

119
Patterns/Memento/Program.cs Normal file

@ -0,0 +1,119 @@
/* Хранитель + Одиночка
Не нарушая инкапсуляцию, определяет
и сохраняет внутреннее состояние объекта и
позволяет позже восстановить объект в этом
состоянии
*/
class Program
{
public static void Main(string[] args)
{
#region Пример 1 - базовое
using (var hero = new Hero())
{
hero.Shoot();
}
using (var heroMan = new Hero())
{
heroMan.RestoreState(GameHistory.Instance.History.Pop());
heroMan.Shoot();
}
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Класс героя
/// </summary>
class Hero : IDisposable
{
/// <summary>
/// Количество патронов
/// </summary>
private int patrons = 10;
/// <summary>
/// Выстрел
/// </summary>
public void Shoot()
{
if(patrons > 0)
{
patrons--;
Console.WriteLine($"Осталось {patrons} патронов...");
}
else
Console.WriteLine("Нет патронов");
}
/// <summary>
/// Сохранение состояния
/// </summary>
/// <returns></returns>
public HeroMemento SaveState()
{
Console.WriteLine($"Сохранено - {patrons}");
return new HeroMemento(patrons);
}
/// <summary>
/// Восстановление состояния
/// </summary>
/// <param name="memento">Хранитель состояния</param>
public void RestoreState(HeroMemento memento)
{
patrons = memento.Patrons;
Console.WriteLine($"Загружено - {patrons}");
}
/// <summary>
/// Удаление из памяти + сохранение в истории последнего состояния
/// </summary>
public void Dispose()
{
GameHistory.Instance.History.Push(SaveState());
}
}
/// <summary>
/// Memento - Хранитель состояния
/// </summary>
class HeroMemento
{
public int Patrons { get; private set; }
public HeroMemento(int patrons)
{
Patrons = patrons;
}
}
/// <summary>
/// Caretaker - смотритель состояния
/// </summary>
class GameHistory
{
private static GameHistory instance;
public Stack<HeroMemento> History { get; set; }
private GameHistory()
{
History = new Stack<HeroMemento>();
}
public static GameHistory Instance
{
get
{
if(instance == null)
instance = new GameHistory();
return instance;
}
}
public void Clear()
{
History.Clear();
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,103 @@
/* Наблюдатель
Определяет зависимость один ко многим
между объектами так, что когда один меняет
своё состояние, все зависимые объекты оповещаются
и обновляются автоматически
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var concreteObservable = new ConcreteObservable();
concreteObservable.AddObserver(new Observer("Job"));
concreteObservable.AddObserver(new Observer("Robin"));
concreteObservable.AddObserver(new Observer("Jaz"));
concreteObservable.AddObserver(new Observer("John"));
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Поведение наблюдателя
/// </summary>
interface IObservable
{
/// <summary>
/// Добавить наблюдаемого
/// </summary>
/// <param name="observer">Наблюдаемый</param>
void AddObserver(IObserver observer);
/// <summary>
/// Удалить наблюдаемого
/// </summary>
/// <param name="observer">Наблюдаемый</param>
void RemoveObserver(IObserver observer);
/// <summary>
/// Оповестить всех наблюдаемых
/// </summary>
void NotifyObservers();
}
/// <summary>
/// Реализация конкретного наблюдателя
/// </summary>
class ConcreteObservable : IObservable
{
/// <summary>
/// Список наблюдаемых
/// </summary>
private List<IObserver> _observers;
public ConcreteObservable()
{
_observers = new List<IObserver>();
}
public void AddObserver(IObserver observer)
{
Console.WriteLine("Event Add Observer");
NotifyObservers();
_observers.Add(observer);
}
public void NotifyObservers()
{
if(_observers.Count == 0) Console.WriteLine("Не кого оповещать...");
foreach (var observer in _observers)
observer.Update();
}
public void RemoveObserver(IObserver observer)
{
_observers.Remove(observer);
NotifyObservers();
}
}
/// <summary>
/// Поведение наблюдаемого
/// </summary>
interface IObserver
{
void Update();
}
/// <summary>
/// Наблюдаемый
/// </summary>
class Observer : IObserver
{
public string Name { get; set; }
public Observer(string name)
{
Name = name;
}
public void Update()
{
Console.WriteLine($"Update {Name}");
}
}

@ -0,0 +1,269 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Behavioral(Поведенческие)", "Behavioral(Поведенческие)", "{749199BB-F36F-4019-BFEB-B04475AB5140}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Structural(Структурные)", "Structural(Структурные)", "{3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Creational(Порождающие)", "Creational(Порождающие)", "{6B6B76CA-287A-4FA5-99FE-8098611020F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Memento", "Memento\Memento.csproj", "{B4BD097B-27B4-4AAE-AC40-E0CA633B2A32}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChainOfResponsibility", "ChainOfResponsibility\ChainOfResponsibility.csproj", "{CFC9F6BF-FC2B-446E-8FB5-92A1E06CAE91}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Observer", "Observer\Observer.csproj", "{72179984-1F4B-4C89-8E29-49D8C8B18A94}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Command", "Command\Command.csproj", "{C4EBB3CE-6BBD-473E-8CAC-012015F8FEA1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "State", "State\State.csproj", "{5EA8980C-B0B1-4C20-93C8-92EFE4B88708}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Interpreter", "Interpreter\Interpreter.csproj", "{E470CB5E-7369-44DB-8192-5A2567865A83}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strategy", "Strategy\Strategy.csproj", "{6566D5A3-F886-4E66-9E98-7FA536D7B4D4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Iterator", "Iterator\Iterator.csproj", "{2BFCAE0E-EBBC-4673-AC56-AA007679A15F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TemplateMethod", "TemplateMethod\TemplateMethod.csproj", "{2411F3F1-D28B-4939-85D9-921847678065}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mediator", "Mediator\Mediator.csproj", "{09C6E1FA-6553-4C92-9D38-613A9A8D155B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Visitor", "Visitor\Visitor.csproj", "{737EB7A2-98B4-473A-81B9-9CAB3BEB69CF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base Logic(Базовые понятия)", "Base Logic(Базовые понятия)", "{4FF822AA-F380-4D92-86B0-50FE5CE6BCEE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaseInfo", "Base\BaseInfo.csproj", "{3E397CB2-2AAF-4D66-855D-E2BA198C380E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Base.Tests", "BaseTests\Base.Tests.csproj", "{90CB9984-E9D1-4821-BA45-D2C668A81813}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DictionaryInfo", "Dict\DictionaryInfo.csproj", "{279CA287-2FCE-45C7-BBD8-4E3941B09028}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetCode", "LetCode\LetCode.csproj", "{71DA93E5-2EB8-4C26-9537-3C1F18DFEC15}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Adapter", "Adapter\Adapter.csproj", "{467EF678-626C-4CBB-B608-234CA2DD8613}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Proxy", "Proxy\Proxy.csproj", "{6BED2E46-471C-484E-A7BA-EFD41A981EF3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bridge", "Bridge\Bridge.csproj", "{47297A10-E472-454B-B333-5554789B8D21}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Composite", "Composite\Composite.csproj", "{34A7974D-A37A-4D79-AF2A-5EECC9295884}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Decorator", "Decorator\Decorator.csproj", "{751A645A-8E65-4556-A322-5170CC3CA905}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facade", "Facade\Facade.csproj", "{770B90B9-DD17-4279-AE68-FCC6E3783D05}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flyweight", "Flyweight\Flyweight.csproj", "{A0DB1337-5532-49C3-99DD-BEBE27F9B382}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AbstractFactory", "AbstractFactory\AbstractFactory.csproj", "{28A8AFD1-7FDB-45E4-A349-1BDD1FEB53C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FactoryMethod", "FactoryMethod\FactoryMethod.csproj", "{206CBCB3-8D1F-47A7-B510-AC9D34C8CBD3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Builder", "Builder\Builder.csproj", "{B4567CE3-9BEC-445E-8830-B4B206FA7641}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentBuilder", "FluentBuilder\FluentBuilder.csproj", "{BA3B2D0E-484B-4075-92F5-D84B10EFDE4D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Prototype", "Prototype\Prototype.csproj", "{F92E5A05-034A-43E4-A7DB-0073C3E322EC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Singleton", "Singleton\Singleton.csproj", "{E17B2354-AD60-4083-BA38-6A9BD85F81B3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetCode.Tests", "LetCode.Tests\LetCode.Tests.csproj", "{34F0E125-BE37-42FF-A679-4EBA9F29D86D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Принципы проектирования", "Принципы проектирования", "{941BD935-75AD-4FEC-8D97-FD5D55905CF1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "1_Принцип единственной обязанности", "1_Принцип единственной обязанности\1_Принцип единственной обязанности.csproj", "{4CEA5C3D-9E87-4AF9-8683-905A46D7006C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "2_Принцип открытости, закрытости", "2_Принцип открытости, закрытости\2_Принцип открытости, закрытости.csproj", "{9CB78E60-6FFB-47C3-9BF3-F20FD7573C80}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "3_Принцип подстановки Барбары Лисков", "3_Принцип подстановки Барбары Лисков\3_Принцип подстановки Барбары Лисков.csproj", "{9A9FCDC5-8E2E-4CD1-9DCB-204A6A166732}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "4_Принцип разделения интерфейсов", "4_Принцип разделения интерфейсов\4_Принцип разделения интерфейсов.csproj", "{0268644C-135F-4217-AC55-B9139E2EA41B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "5_Принцип инверсии зависимостей", "5_Принцип инверсии зависимостей\5_Принцип инверсии зависимостей.csproj", "{C7CF08B8-7D0D-47D0-BA43-2488EF6E16E6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B4BD097B-27B4-4AAE-AC40-E0CA633B2A32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B4BD097B-27B4-4AAE-AC40-E0CA633B2A32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4BD097B-27B4-4AAE-AC40-E0CA633B2A32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4BD097B-27B4-4AAE-AC40-E0CA633B2A32}.Release|Any CPU.Build.0 = Release|Any CPU
{CFC9F6BF-FC2B-446E-8FB5-92A1E06CAE91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CFC9F6BF-FC2B-446E-8FB5-92A1E06CAE91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CFC9F6BF-FC2B-446E-8FB5-92A1E06CAE91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CFC9F6BF-FC2B-446E-8FB5-92A1E06CAE91}.Release|Any CPU.Build.0 = Release|Any CPU
{72179984-1F4B-4C89-8E29-49D8C8B18A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72179984-1F4B-4C89-8E29-49D8C8B18A94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72179984-1F4B-4C89-8E29-49D8C8B18A94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72179984-1F4B-4C89-8E29-49D8C8B18A94}.Release|Any CPU.Build.0 = Release|Any CPU
{C4EBB3CE-6BBD-473E-8CAC-012015F8FEA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4EBB3CE-6BBD-473E-8CAC-012015F8FEA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4EBB3CE-6BBD-473E-8CAC-012015F8FEA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4EBB3CE-6BBD-473E-8CAC-012015F8FEA1}.Release|Any CPU.Build.0 = Release|Any CPU
{5EA8980C-B0B1-4C20-93C8-92EFE4B88708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5EA8980C-B0B1-4C20-93C8-92EFE4B88708}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5EA8980C-B0B1-4C20-93C8-92EFE4B88708}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5EA8980C-B0B1-4C20-93C8-92EFE4B88708}.Release|Any CPU.Build.0 = Release|Any CPU
{E470CB5E-7369-44DB-8192-5A2567865A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E470CB5E-7369-44DB-8192-5A2567865A83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E470CB5E-7369-44DB-8192-5A2567865A83}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E470CB5E-7369-44DB-8192-5A2567865A83}.Release|Any CPU.Build.0 = Release|Any CPU
{6566D5A3-F886-4E66-9E98-7FA536D7B4D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6566D5A3-F886-4E66-9E98-7FA536D7B4D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6566D5A3-F886-4E66-9E98-7FA536D7B4D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6566D5A3-F886-4E66-9E98-7FA536D7B4D4}.Release|Any CPU.Build.0 = Release|Any CPU
{2BFCAE0E-EBBC-4673-AC56-AA007679A15F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BFCAE0E-EBBC-4673-AC56-AA007679A15F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BFCAE0E-EBBC-4673-AC56-AA007679A15F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BFCAE0E-EBBC-4673-AC56-AA007679A15F}.Release|Any CPU.Build.0 = Release|Any CPU
{2411F3F1-D28B-4939-85D9-921847678065}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2411F3F1-D28B-4939-85D9-921847678065}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2411F3F1-D28B-4939-85D9-921847678065}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2411F3F1-D28B-4939-85D9-921847678065}.Release|Any CPU.Build.0 = Release|Any CPU
{09C6E1FA-6553-4C92-9D38-613A9A8D155B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09C6E1FA-6553-4C92-9D38-613A9A8D155B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09C6E1FA-6553-4C92-9D38-613A9A8D155B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09C6E1FA-6553-4C92-9D38-613A9A8D155B}.Release|Any CPU.Build.0 = Release|Any CPU
{737EB7A2-98B4-473A-81B9-9CAB3BEB69CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{737EB7A2-98B4-473A-81B9-9CAB3BEB69CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{737EB7A2-98B4-473A-81B9-9CAB3BEB69CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{737EB7A2-98B4-473A-81B9-9CAB3BEB69CF}.Release|Any CPU.Build.0 = Release|Any CPU
{3E397CB2-2AAF-4D66-855D-E2BA198C380E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E397CB2-2AAF-4D66-855D-E2BA198C380E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E397CB2-2AAF-4D66-855D-E2BA198C380E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E397CB2-2AAF-4D66-855D-E2BA198C380E}.Release|Any CPU.Build.0 = Release|Any CPU
{90CB9984-E9D1-4821-BA45-D2C668A81813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90CB9984-E9D1-4821-BA45-D2C668A81813}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90CB9984-E9D1-4821-BA45-D2C668A81813}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90CB9984-E9D1-4821-BA45-D2C668A81813}.Release|Any CPU.Build.0 = Release|Any CPU
{279CA287-2FCE-45C7-BBD8-4E3941B09028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{279CA287-2FCE-45C7-BBD8-4E3941B09028}.Debug|Any CPU.Build.0 = Debug|Any CPU
{279CA287-2FCE-45C7-BBD8-4E3941B09028}.Release|Any CPU.ActiveCfg = Release|Any CPU
{279CA287-2FCE-45C7-BBD8-4E3941B09028}.Release|Any CPU.Build.0 = Release|Any CPU
{71DA93E5-2EB8-4C26-9537-3C1F18DFEC15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71DA93E5-2EB8-4C26-9537-3C1F18DFEC15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71DA93E5-2EB8-4C26-9537-3C1F18DFEC15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71DA93E5-2EB8-4C26-9537-3C1F18DFEC15}.Release|Any CPU.Build.0 = Release|Any CPU
{467EF678-626C-4CBB-B608-234CA2DD8613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{467EF678-626C-4CBB-B608-234CA2DD8613}.Debug|Any CPU.Build.0 = Debug|Any CPU
{467EF678-626C-4CBB-B608-234CA2DD8613}.Release|Any CPU.ActiveCfg = Release|Any CPU
{467EF678-626C-4CBB-B608-234CA2DD8613}.Release|Any CPU.Build.0 = Release|Any CPU
{6BED2E46-471C-484E-A7BA-EFD41A981EF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BED2E46-471C-484E-A7BA-EFD41A981EF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BED2E46-471C-484E-A7BA-EFD41A981EF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BED2E46-471C-484E-A7BA-EFD41A981EF3}.Release|Any CPU.Build.0 = Release|Any CPU
{47297A10-E472-454B-B333-5554789B8D21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47297A10-E472-454B-B333-5554789B8D21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47297A10-E472-454B-B333-5554789B8D21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47297A10-E472-454B-B333-5554789B8D21}.Release|Any CPU.Build.0 = Release|Any CPU
{34A7974D-A37A-4D79-AF2A-5EECC9295884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34A7974D-A37A-4D79-AF2A-5EECC9295884}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34A7974D-A37A-4D79-AF2A-5EECC9295884}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34A7974D-A37A-4D79-AF2A-5EECC9295884}.Release|Any CPU.Build.0 = Release|Any CPU
{751A645A-8E65-4556-A322-5170CC3CA905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{751A645A-8E65-4556-A322-5170CC3CA905}.Debug|Any CPU.Build.0 = Debug|Any CPU
{751A645A-8E65-4556-A322-5170CC3CA905}.Release|Any CPU.ActiveCfg = Release|Any CPU
{751A645A-8E65-4556-A322-5170CC3CA905}.Release|Any CPU.Build.0 = Release|Any CPU
{770B90B9-DD17-4279-AE68-FCC6E3783D05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{770B90B9-DD17-4279-AE68-FCC6E3783D05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{770B90B9-DD17-4279-AE68-FCC6E3783D05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{770B90B9-DD17-4279-AE68-FCC6E3783D05}.Release|Any CPU.Build.0 = Release|Any CPU
{A0DB1337-5532-49C3-99DD-BEBE27F9B382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0DB1337-5532-49C3-99DD-BEBE27F9B382}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0DB1337-5532-49C3-99DD-BEBE27F9B382}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0DB1337-5532-49C3-99DD-BEBE27F9B382}.Release|Any CPU.Build.0 = Release|Any CPU
{28A8AFD1-7FDB-45E4-A349-1BDD1FEB53C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28A8AFD1-7FDB-45E4-A349-1BDD1FEB53C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28A8AFD1-7FDB-45E4-A349-1BDD1FEB53C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28A8AFD1-7FDB-45E4-A349-1BDD1FEB53C2}.Release|Any CPU.Build.0 = Release|Any CPU
{206CBCB3-8D1F-47A7-B510-AC9D34C8CBD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{206CBCB3-8D1F-47A7-B510-AC9D34C8CBD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{206CBCB3-8D1F-47A7-B510-AC9D34C8CBD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{206CBCB3-8D1F-47A7-B510-AC9D34C8CBD3}.Release|Any CPU.Build.0 = Release|Any CPU
{B4567CE3-9BEC-445E-8830-B4B206FA7641}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B4567CE3-9BEC-445E-8830-B4B206FA7641}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4567CE3-9BEC-445E-8830-B4B206FA7641}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4567CE3-9BEC-445E-8830-B4B206FA7641}.Release|Any CPU.Build.0 = Release|Any CPU
{BA3B2D0E-484B-4075-92F5-D84B10EFDE4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA3B2D0E-484B-4075-92F5-D84B10EFDE4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA3B2D0E-484B-4075-92F5-D84B10EFDE4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA3B2D0E-484B-4075-92F5-D84B10EFDE4D}.Release|Any CPU.Build.0 = Release|Any CPU
{F92E5A05-034A-43E4-A7DB-0073C3E322EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F92E5A05-034A-43E4-A7DB-0073C3E322EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F92E5A05-034A-43E4-A7DB-0073C3E322EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F92E5A05-034A-43E4-A7DB-0073C3E322EC}.Release|Any CPU.Build.0 = Release|Any CPU
{E17B2354-AD60-4083-BA38-6A9BD85F81B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E17B2354-AD60-4083-BA38-6A9BD85F81B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E17B2354-AD60-4083-BA38-6A9BD85F81B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E17B2354-AD60-4083-BA38-6A9BD85F81B3}.Release|Any CPU.Build.0 = Release|Any CPU
{34F0E125-BE37-42FF-A679-4EBA9F29D86D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34F0E125-BE37-42FF-A679-4EBA9F29D86D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34F0E125-BE37-42FF-A679-4EBA9F29D86D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34F0E125-BE37-42FF-A679-4EBA9F29D86D}.Release|Any CPU.Build.0 = Release|Any CPU
{4CEA5C3D-9E87-4AF9-8683-905A46D7006C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CEA5C3D-9E87-4AF9-8683-905A46D7006C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CEA5C3D-9E87-4AF9-8683-905A46D7006C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CEA5C3D-9E87-4AF9-8683-905A46D7006C}.Release|Any CPU.Build.0 = Release|Any CPU
{9CB78E60-6FFB-47C3-9BF3-F20FD7573C80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9CB78E60-6FFB-47C3-9BF3-F20FD7573C80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CB78E60-6FFB-47C3-9BF3-F20FD7573C80}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CB78E60-6FFB-47C3-9BF3-F20FD7573C80}.Release|Any CPU.Build.0 = Release|Any CPU
{9A9FCDC5-8E2E-4CD1-9DCB-204A6A166732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A9FCDC5-8E2E-4CD1-9DCB-204A6A166732}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A9FCDC5-8E2E-4CD1-9DCB-204A6A166732}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A9FCDC5-8E2E-4CD1-9DCB-204A6A166732}.Release|Any CPU.Build.0 = Release|Any CPU
{0268644C-135F-4217-AC55-B9139E2EA41B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0268644C-135F-4217-AC55-B9139E2EA41B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0268644C-135F-4217-AC55-B9139E2EA41B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0268644C-135F-4217-AC55-B9139E2EA41B}.Release|Any CPU.Build.0 = Release|Any CPU
{C7CF08B8-7D0D-47D0-BA43-2488EF6E16E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7CF08B8-7D0D-47D0-BA43-2488EF6E16E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7CF08B8-7D0D-47D0-BA43-2488EF6E16E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7CF08B8-7D0D-47D0-BA43-2488EF6E16E6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B4BD097B-27B4-4AAE-AC40-E0CA633B2A32} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{CFC9F6BF-FC2B-446E-8FB5-92A1E06CAE91} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{72179984-1F4B-4C89-8E29-49D8C8B18A94} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{C4EBB3CE-6BBD-473E-8CAC-012015F8FEA1} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{5EA8980C-B0B1-4C20-93C8-92EFE4B88708} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{E470CB5E-7369-44DB-8192-5A2567865A83} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{6566D5A3-F886-4E66-9E98-7FA536D7B4D4} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{2BFCAE0E-EBBC-4673-AC56-AA007679A15F} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{2411F3F1-D28B-4939-85D9-921847678065} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{09C6E1FA-6553-4C92-9D38-613A9A8D155B} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{737EB7A2-98B4-473A-81B9-9CAB3BEB69CF} = {749199BB-F36F-4019-BFEB-B04475AB5140}
{3E397CB2-2AAF-4D66-855D-E2BA198C380E} = {4FF822AA-F380-4D92-86B0-50FE5CE6BCEE}
{90CB9984-E9D1-4821-BA45-D2C668A81813} = {4FF822AA-F380-4D92-86B0-50FE5CE6BCEE}
{279CA287-2FCE-45C7-BBD8-4E3941B09028} = {4FF822AA-F380-4D92-86B0-50FE5CE6BCEE}
{71DA93E5-2EB8-4C26-9537-3C1F18DFEC15} = {4FF822AA-F380-4D92-86B0-50FE5CE6BCEE}
{467EF678-626C-4CBB-B608-234CA2DD8613} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{6BED2E46-471C-484E-A7BA-EFD41A981EF3} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{47297A10-E472-454B-B333-5554789B8D21} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{34A7974D-A37A-4D79-AF2A-5EECC9295884} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{751A645A-8E65-4556-A322-5170CC3CA905} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{770B90B9-DD17-4279-AE68-FCC6E3783D05} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{A0DB1337-5532-49C3-99DD-BEBE27F9B382} = {3E3D01F2-BFF2-417A-BEAD-0E0AD3547A8D}
{28A8AFD1-7FDB-45E4-A349-1BDD1FEB53C2} = {6B6B76CA-287A-4FA5-99FE-8098611020F9}
{206CBCB3-8D1F-47A7-B510-AC9D34C8CBD3} = {6B6B76CA-287A-4FA5-99FE-8098611020F9}
{B4567CE3-9BEC-445E-8830-B4B206FA7641} = {6B6B76CA-287A-4FA5-99FE-8098611020F9}
{BA3B2D0E-484B-4075-92F5-D84B10EFDE4D} = {6B6B76CA-287A-4FA5-99FE-8098611020F9}
{F92E5A05-034A-43E4-A7DB-0073C3E322EC} = {6B6B76CA-287A-4FA5-99FE-8098611020F9}
{E17B2354-AD60-4083-BA38-6A9BD85F81B3} = {6B6B76CA-287A-4FA5-99FE-8098611020F9}
{34F0E125-BE37-42FF-A679-4EBA9F29D86D} = {4FF822AA-F380-4D92-86B0-50FE5CE6BCEE}
{4CEA5C3D-9E87-4AF9-8683-905A46D7006C} = {941BD935-75AD-4FEC-8D97-FD5D55905CF1}
{9CB78E60-6FFB-47C3-9BF3-F20FD7573C80} = {941BD935-75AD-4FEC-8D97-FD5D55905CF1}
{9A9FCDC5-8E2E-4CD1-9DCB-204A6A166732} = {941BD935-75AD-4FEC-8D97-FD5D55905CF1}
{0268644C-135F-4217-AC55-B9139E2EA41B} = {941BD935-75AD-4FEC-8D97-FD5D55905CF1}
{C7CF08B8-7D0D-47D0-BA43-2488EF6E16E6} = {941BD935-75AD-4FEC-8D97-FD5D55905CF1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6A7DE462-3436-49E8-A6F0-59158DFB417F}
EndGlobalSection
EndGlobal

@ -0,0 +1,132 @@
/* Прототип
Определяет несколько видов объектов,
чтобы при создании использовать объект-прототип
и создаёт новые объекты, копируя прототип
(техника клонирования объектов)
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
IFigure cube = new Cube(10, 10);
IFigure cloneCube = cube.Clone();
IFigure cloneMemberCube = cube.CloneMember();
cube.GetInfo();
cloneCube.GetInfo();
cloneMemberCube.GetInfo();
#endregion
#region Пример 2
IEntity entity = new Predator(10, 1000);
var clone = entity.CloneEntity();
entity.GetInfo();
clone.GetInfo();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Поведение фигуры
/// </summary>
interface IFigure
{
IFigure Clone();
IFigure? CloneMember();
void GetInfo();
}
/// <summary>
/// Шаблон куба
/// </summary>
class Cube : IFigure
{
int Width { get; set; }
int Height { get; set; }
public Cube(int width, int heght)
{
Width = width;
Height = heght;
}
public IFigure Clone()
{
return new Cube(Width, Height);
}
public IFigure? CloneMember()
{
return this.MemberwiseClone() as IFigure;
}
public void GetInfo()
{
Console.WriteLine($"Cube {Width}/{Height}");
}
}
/// <summary>
/// Треугольник
/// </summary>
class Rect : IFigure
{
int Width { get; set; }
int Height { get; set; }
public Rect(int width, int heght)
{
Width = width;
Height = heght;
}
public IFigure Clone()
{
return new Rect(Width, Height);
}
public IFigure? CloneMember()
{
return this.MemberwiseClone() as IFigure;
}
public void GetInfo()
{
Console.WriteLine($"Rect {Width}/{Height}");
}
}
/// <summary>
/// Поведение сущности
/// </summary>
interface IEntity
{
IEntity CloneEntity();
void GetInfo();
}
abstract record Animal(int Paws, int Weight) : IEntity
{
public abstract IEntity CloneEntity();
public abstract void GetInfo();
}
record Predator(int Paws, int Weight) : Animal(Paws, Weight)
{
public override IEntity CloneEntity()
=> this with { };
public override void GetInfo()
=> Console.WriteLine($"Predator w={Weight} p={Paws}");
}
record Person(int IQ) : IEntity
{
public IEntity CloneEntity()
=> this with { };
public void GetInfo()
=> Console.WriteLine($"Peaple with IQ={IQ}");
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

94
Patterns/Proxy/Program.cs Normal file

@ -0,0 +1,94 @@
using Microsoft.EntityFrameworkCore;
/* Заместитель
Предоставляет объект-заместитель другого объекта
для контроля доступа к нему
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
using (IBook book = new BookStoreProxy())
{
//читаем первую страницу
Page page1 = book.GetPage(1);
Console.WriteLine(page1.Text);
//читаем первую страницу
Page page2 = book.GetPage(2);
Console.WriteLine(page1.Text);
//возвращаемся на первую страницу
page1 = book.GetPage(1);
Console.WriteLine(page1.Text);
}
Console.ReadKey();
#endregion
}
}
/// <summary>
/// отдельная страница книги
/// </summary>
/// <param name="Id">Идентификатор</param>
/// <param name="Number">Номер</param>
/// <param name="Text">Содержимое</param>
record Page(int Id, int Number, string Text);
class PageContext : DbContext
{
public DbSet<Page> Pages { get; set; }
}
interface IBook : IDisposable
{
Page GetPage(int number);
}
class BookStore : IBook
{
PageContext db;
public BookStore()
{
db = new PageContext();
}
public void Dispose()
{
db.Dispose();
}
public Page GetPage(int number)
{
return db.Pages.FirstOrDefault(p => p.Number == number);
}
}
class BookStoreProxy : IBook
{
List<Page> Pages;
BookStore bookStore;
public BookStoreProxy()
{
Pages = new List<Page>();
}
public void Dispose()
{
if (bookStore != null)
bookStore.Dispose();
}
public Page GetPage(int number)
{
Page page = Pages.FirstOrDefault(p => p.Number == number);
if(page == null)
{
if(bookStore == null)
bookStore = new BookStore();
page = bookStore.GetPage(number);
Pages.Add(page);
}
return page;
}
}

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.8" />
</ItemGroup>
</Project>

@ -0,0 +1,44 @@
/* Одиночка
Гарантирует что класс имеет только
один экземпляр и представляет глобальную
точку доступа к нему
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
(new Thread(() =>
{
Console.WriteLine(GameHistory.Instance.History[1]);
})).Start();
Console.WriteLine(GameHistory.Instance.History[0]);
Console.ReadKey();
#endregion
}
}
class GameHistory
{
private static object syncRoot = new();
private static GameHistory _instance;
public static GameHistory Instance
{
get
{
lock(syncRoot)
{
if(_instance == null)
_instance = new GameHistory();
}
return _instance;
}
}
public string[] History { get; set; }
private GameHistory()
{
History = new[] { "One History",
"Two History"};
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

76
Patterns/State/Program.cs Normal file

@ -0,0 +1,76 @@
/* Состояние
Позволяет объекту изменять
своё поведение в зависимости от
внутреннего состояния
*/
class Program
{
static void Main()
{
#region Пример 1 - базовое
var contextA = new Context(new StateA());
var contextB = new Context(new StateB());
contextA.Request();
contextB.Request();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Абстракция состояния
/// </summary>
abstract class State
{
public abstract void Handle(Context context);
}
/// <summary>
/// Реализация состояния A
/// </summary>
class StateA : State
{
public StateA()
{
Console.WriteLine("State-A Create...");
}
public override void Handle(Context context)
{
context.State = new StateB();
}
}
/// <summary>
/// Реализация состояния B
/// </summary>
class StateB : State
{
public StateB()
{
Console.WriteLine("State-B Create...");
}
public override void Handle(Context context)
{
context.State = new StateA();
}
}
/// <summary>
/// Контекст со своим состоянием
/// </summary>
class Context
{
public State State { get; set; }
public Context(State state)
{
State = state;
}
public void Request()
{
State.Handle(this);
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,6 @@
namespace Strategy;
internal interface ILogReader
{
List<LogEntry> Read();
}

@ -0,0 +1,15 @@
namespace Strategy;
public enum LogType
{
Debug,
Warning,
Fatal
}
public struct LogEntry
{
public DateTime DateTime { get; set; }
public LogType LogType { get; set; }
public string Message { get; set; }
}

@ -0,0 +1,17 @@
namespace Strategy;
public class LogFileReader : ILogReader
{
public List<LogEntry> Read()
{
return new List<LogEntry>()
{
new LogEntry()
{
DateTime = DateTime.Now,
LogType = LogType.Debug,
Message = GetType().Name
}
};
}
}

@ -0,0 +1,21 @@
namespace Strategy;
public class LogProcessor
{
private readonly Func<List<LogEntry>> _logimporter;
public LogProcessor(Func<List<LogEntry>> logImporter)
{
_logimporter = logImporter;
}
public void ProcessLogs()
{
foreach (var logEntry in _logimporter.Invoke())
{
Console.WriteLine(logEntry.DateTime);
Console.WriteLine(logEntry.LogType);
Console.WriteLine(logEntry.Message);
}
}
}

@ -0,0 +1,218 @@
/* Стратегия
Определяет группу алгоритмов,
инкапсулирует их и делает взаимозаменяемыми.
Позволяет изменять алгоритм независимо от клиентов,
его использующих.
*/
/*
* На чем строилось:
* СЕРГЕЙ ТЕПЛЯКОВ - Паттерны проектирования на платформе .Net
* ШЕВЧУК, АХРИМЕНКО, КАСЬЯНОВ - Приемы объектно-ориентированного проектирования
*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
* Паттерн 1: Стратегия
*
* - является более контекстно зависимой операцией
*
* Причины применения:
* 1.необходимость инкапсуляции поведения или алгоритма
* 2.необходимость замены поведения или алгоритма во время исполнения
*
* Другими словами, стратегия обеспечивает точку расширения системы
* в определенной плоскости: класс-контекст (LogProcessor) принимает экземпляр стратегии (LogFileReader)
* и не знает, какой вариант стратегии он собирается использовать.
*
* Особенность:
* Передача интерфейса ILogReader классу LogProcessor увеличивает гибкость,
* но в то же время повышает сложность.
* Теперь клиентам класса LogProcessor нужно решить, какую реализацию использовать,
* или переложить эту ответственность на вызывающий код.
*/
/*
* ВМЕСТО
* классической стратегии на основе наследования
* можно использовать стратегию на основе делегатов
*
* ПРИМЕР: Стратегия сортировки
*/
/*
* ВАЖНО: Гибкость не бывает бесплатной, поэтому выделять стратегии стоит тогда,
* когда действительно нужна замена поведения во время исполнения.
*/
using Strategy;
class Program
{
#region Пример 3 - Сomparer
public static void SortListId(List<Employee> list)
{
list.Sort(new EmployeeByIdComparer()); //используем функтор
}
public static void SortListName(List<Employee> list)
{
list.Sort((x, y) => x.Name.CompareTo(y.Name)); //используем делегат
}
#endregion
public static void Main(string[] args)
{
#region Пример 1 - базовое
var car = new Car(new PetrolMove());
car.Move();
car.Movable = new ElectronicMove();
car.Move();
Console.ReadKey();
#endregion
#region Пример 2 - ILogReader
LogFileReader logFileReader = new LogFileReader();
//создали делегат который принимает в себя метод,
//в результате выполнения которого возвращается List<LogEntry>
Func<List<LogEntry>> _import = () => logFileReader.Read();
LogProcessor processor = new LogProcessor(_import);
processor.ProcessLogs();
#endregion
#region Пример 3 - Сomparer
List<Employee> employees = new List<Employee>
{
new Employee
{
Id = 8,
Name = "asmus"
},
new Employee
{
Id = 1,
Name = "robin"
},
new Employee
{
Id = 2,
Name = "satan"
},
new Employee
{
Id = 5,
Name = "dastin"
}
};
SortListId(employees); //отсортировали по id через функтор
SortListName(employees); //отсортировали по Name через делегат
Console.WriteLine();
var comparer = new EmployeeByIdComparer();
var set = new SortedSet<Employee>(comparer); //конструктор принимает IComparable
//нет конструктора, принимающего делегат Comparison<T>
//можно создать небольшой адаптерный фабричный класс
var comparer_factory = ComparerFactory.Create<Employee>((x, y) => x.Id.CompareTo(y.Id));
//он помещает сюда фабрику
var set_factory = new SortedSet<Employee>(comparer_factory);
#endregion
}
}
/// <summary>
/// Поведение движения
/// </summary>
interface IMovable
{
void Move();
}
/// <summary>
/// Бензиновый двигатель
/// </summary>
class PetrolMove : IMovable
{
public void Move()
{
Console.WriteLine("Движение на бензине");
}
}
/// <summary>
/// Электродвигатель
/// </summary>
class ElectronicMove : IMovable
{
public void Move()
{
Console.WriteLine("Движение на электричестве");
}
}
/// <summary>
/// Автомобиль
/// </summary>
class Car
{
/// <summary>
/// Cпособ передвижения автомобиля
/// </summary>
public IMovable Movable { private get; set; }
public Car(IMovable movable)
{
Movable = movable;
}
public void Move()
{
Movable.Move();
}
}
class Employee
{
public int Id { get; set; }
public string? Name { get; set; }
public override string ToString()
{
return string.Format($"ID={Id}, Name={Name}");
}
}
/// <summary>
/// Реализует интерфейс сортировки
/// Добавлет возможность сортировки по ID по возрастающей
/// </summary>
class EmployeeByIdComparer : IComparer<Employee>
{
int IComparer<Employee>.Compare(Employee? x, Employee? y)
{
if (x is Employee xx && y is Employee yy)
return xx.Id.CompareTo(yy.Id);
else
return 0;
}
}
/// <summary>
/// Фабричный шаблон для создания экземпляров IComparer
/// </summary>
class ComparerFactory
{
public static IComparer<T> Create<T>(Comparison<T> comparer)
{
return new DelegateComparer<T>(comparer);
}
private class DelegateComparer<T> : IComparer<T>
{
private readonly Comparison<T> _comparer;
public DelegateComparer(Comparison<T> comparer)
{
_comparer = comparer;
}
public int Compare(T? x, T? y)
{
if (x == null || y == null)
return 0;
return _comparer(x, y);
}
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,17 @@
namespace Strategy;
public class WindowsEventLogReader : ILogReader
{
public List<LogEntry> Read()
{
return new List<LogEntry>()
{
new LogEntry()
{
DateTime = DateTime.Now,
Message = GetType().Name,
LogType = LogType.Debug
}
};
}
}

@ -0,0 +1,115 @@
/* Шаблонный метод
Определяет алгоритм, некоторые этапы которого
делегируются подклассам. Позволяет подклассам
переопределить эти этапы, не меняя структуру алгоритма.
*/
class Program
{
public static void Main(string[] args)
{
#region Пример 1 - базовое
new School().Learn();
new University().Learn();
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Представление образовательного процесса
/// </summary>
abstract class Education
{
/// <summary>
/// Обучение
/// </summary>
public virtual void Learn()
{
Enter();
Study();
PassExams();
GetDocument();
}
/// <summary>
/// Получение документа об окончании образования
/// </summary>
protected abstract void GetDocument();
/// <summary>
/// Cдача экзаменов в учебном заведении
/// </summary>
protected abstract void PassExams();
/// <summary>
/// Обучение в учебном заведении
/// </summary>
protected abstract void Study();
/// <summary>
/// Поступление в учебное заведение
/// </summary>
protected abstract void Enter();
}
/// <summary>
/// Школа реализовывающее процесс образования со своими дополнениями
/// </summary>
class School : Education
{
protected override void Enter()
{
Console.WriteLine("Поступил в школу");
}
protected override void GetDocument()
{
Console.WriteLine("Получил аттестат");
}
protected override void PassExams()
{
Console.WriteLine("Сдал ЕГЭ и ОГЭ");
}
public void ExtraExams()
{
Console.WriteLine("Ходил на олимпиады");
}
protected override void Study()
{
Console.WriteLine("Обучился 11 классов");
}
public override void Learn()
{
base.Learn();
ExtraExams();
}
}
/// <summary>
/// Университет реализовывающий процесса образования
/// </summary>
class University : Education
{
protected override void Enter()
{
Console.WriteLine("Поступил в университет");
}
protected override void GetDocument()
{
Console.WriteLine("Получил диплом");
}
protected override void PassExams()
{
Console.WriteLine("Сдал экзамены и зачёты");
}
protected override void Study()
{
Console.WriteLine("Ходил на пары");
Console.WriteLine("Ходил на лекции");
Console.WriteLine("Сдавал лабораторные работы");
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

138
Patterns/Visitor/Program.cs Normal file

@ -0,0 +1,138 @@
/* Посетитель
Представляет собой операцию, которая
будет выполнена над объектами группы классов.
Даёт возможность определить новую операцию
без изменения кода классов, над которыми
эта операция производит.
*/
class Program
{
public static void Main(string[] args)
{
#region Пример 1 - базовое
var bank = new Bank();
bank.Add(new Person(Name: "Joshua", Number: 1997));
bank.Add(new Company(Name: "Microsoft", Number: 1904));
bank.Accept(new HtmlVisitor());
bank.Accept(new XmlVisitor());
Console.ReadKey();
#endregion
}
}
/// <summary>
/// Поведение посетителя
/// отделяет логику сериализации от классов в которых она применима
/// </summary>
interface IVisitor
{
void VisitPersonAcc(Person person);
void VisitCompanyAcc(Company company);
}
/// <summary>
/// Поведение аккаунта
/// </summary>
interface IAccaunt
{
void Accept(IVisitor visitor);
}
/// <summary>
/// Шаблон банка
/// </summary>
class Bank
{
List<IAccaunt> Accaunts;
public Bank()
{
Accaunts = new List<IAccaunt>();
}
/// <summary>
/// Добавить аккаунт
/// </summary>
/// <param name="accaunt">аккаунт</param>
public void Add(IAccaunt accaunt)
{
Accaunts.Add(accaunt);
}
/// <summary>
/// Удаллить аккаунт
/// </summary>
/// <param name="accaunt">аккаунт</param>
public void Remove(IAccaunt accaunt)
{
Accaunts.Remove(accaunt);
}
/// <summary>
/// Получить доступ к своему аккаунту
/// </summary>
/// <param name="visitor">пользователь</param>
public void Accept(IVisitor visitor)
{
foreach (var accaunt in Accaunts)
accaunt.Accept(visitor);
}
}
/// <summary>
/// Пользователь
/// </summary>
/// <param name="Name">Имя</param>
/// <param name="Number">Номер</param>
record Person(string Name, int Number) : IAccaunt
{
public void Accept(IVisitor visitor)
{
visitor.VisitPersonAcc(this);
}
}
/// <summary>
/// Компания
/// </summary>
/// <param name="Name">Имя</param>
/// <param name="Number">Номер</param>
record Company(string Name, int Number) : IAccaunt
{
public void Accept(IVisitor visitor)
{
visitor.VisitCompanyAcc(this);
}
}
/// <summary>
/// HTML сериализатор
/// </summary>
class HtmlVisitor : IVisitor
{
public void VisitCompanyAcc(Company company)
{
Console.WriteLine($"[HTML] {company}");
}
public void VisitPersonAcc(Person person)
{
Console.WriteLine($"[HTML] {person}");
}
}
/// <summary>
/// XML сериализатор
/// </summary>
class XmlVisitor : IVisitor
{
public void VisitCompanyAcc(Company company)
{
Console.WriteLine($"[XML] {company}");
}
public void VisitPersonAcc(Person person)
{
Console.WriteLine($"[XML] {person}");
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

156
README.md Normal file

@ -0,0 +1,156 @@
<p align="center">
<!-- <p align="center">
<img src="/" width="100%" alt="Banner">
<a></a> -->
<!-- </p> -->
<p align="center">
<a href="https://git.io/typing-svg"><img src="https://readme-typing-svg.demolab.com?font=Fira+Code&pause=1000&center=true&vCenter=true&width=435&lines=%D0%9F%D0%BE%D0%B2%D1%82%D0%BE%D1%80%D0%B5%D0%BD%D0%B8%D0%B5+-+%D0%BC%D0%B0%D1%82%D1%8C+%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F" alt="Typing SVG" /></a>
</p>
<p align="center">
<a href="https://sites.google.com/view/dvurechensky" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Dvurechensky-N-blue"></a>
<img src="https://img.shields.io/badge/Csharp-VS2022-blue?logo=csharp&logoColor=FFFF00">
</p>
</p>
<p align="center">
<h1 align="center">🔱 Шаблоны проектирования 🔱<h1>
</p>
## Описание содержимого 💼
- ⌛ Определения: **class, abstract class, struct, interface, record**
- ⌛ Разбор: **принципы SOLID, наследование, типы Dictionary, Unit тестирование**
- ⌛ Бонус: **решение [LetCode](https://leetcode.com/) задач**
- 😈 Такие паттерны как:
>
<h1 align="center">🌐 Behavioral - Поведенческие [11]🌐<h1><br>
<table align="center">
<thead>
<tr>
<th>Паттерн</th>
<th>Краткое определение</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/ChainOfResponsibility/Program.cs">ChainOfResponsibility</a> - Цепочка обязанностей</td>
<td style="width: 500px; padding: 18px;">🔎 Избегает связывание отправителя запроса с его получателем, давая возможность обработать запрос более чем одному объекту.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Command/Program.cs">Command</a> - Команда</td>
<td style="width: 500px; padding: 18px;">🔎 Инкапсулирует запрос в виде объекта позволяя передавать их клиентам в качестве параметров, ставить в очередь, логировать, а также поддерживать отмену операций.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Interpreter/Program.cs">Interpreter</a> - Интерпретатор</td>
<td style="width: 500px; padding: 18px;">🔎 Получая формальный язык, определяет представление его грамматики и интерпретатор, использующий это представление для обработки выражений языка.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Iterator/Program.cs">Iterator</a> - Итератор</td>
<td style="width: 500px; padding: 18px;">🔎 Предоставляет способ последовательного доступа к множеству, независимо от его внутреннего устройства.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Mediator/Program.cs">Mediator</a> - Посредник</td>
<td style="width: 500px; padding: 18px;">🔎 Определяет объект инкапсулирующий способ взаимодействия объектов. Обеспечивает слабую связь, избавляя их от необходимости ссылаться друг на друга и даёт возможность независимо изменять их взаимодействие.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Memento/Program.cs">Memento</a> - Хранитель</td>
<td style="width: 500px; padding: 18px;">🔎 Не нарушая инкапсуляцию, определяет и сохраняет внутреннее состояние объекта и позволяет позже восстановить объект в этом состоянии.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Observer/Program.cs">Observer</a> - Наблюдатель</td>
<td style="width: 500px; padding: 18px;">🔎 Определяет зависимость один ко многим между объектами так, что когда один меняет своё состояние, все зависимые объекты оповещаются и обновляются автоматически.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/State/Program.cs">State</a> - Состояние</td>
<td style="width: 500px; padding: 18px;">🔎 Позволяет объекту изменять своё поведение в зависимости от внутреннего состояния.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Strategy/Program.cs">Strategy</a> - Стратегия</td>
<td style="width: 500px; padding: 18px;">🔎 Определяет группу алгоритмов, инкапсулирует их и делает взаимозаменяемыми. Позволяет изменять алгоритм независимо от клиентов, его использующих.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/TemplateMethod/Program.cs">TemplateMethod</a> - Шаблонный метод</td>
<td style="width: 500px; padding: 18px;">🔎 Определяет алгоритм, некоторые этапы которого делегируются подклассам. Позволяет подклассам переопределить эти этапы, не меняя структуру алгоритма.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Visitor/Program.cs">Visitor</a> - Посетитель</td>
<td style="width: 500px; padding: 18px;">🔎 Представляет собой операцию, которая будет выполнена над объектами группы классов. Даёт возможность определить новую операцию без изменения кода классов, над которыми эта операция производитcя.</td>
</tr>
</tbody>
</table>
<br>
<h1 align="center">💡 Creational - Порождающие [6]💡<h1><br>
<table align="center">
<thead>
<tr>
<th>Паттерн</th>
<th>Краткое определение</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/AbstractFactory/Program.cs">AbstractFactory</a> - Абстрактная фабрика</td>
<td style="width: 500px; padding: 18px;">🔎 Предоставляет интерфейс для создания групп связанных или зависимых объектов, не указывая их конкретный класс.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Builder/Program.cs">Builder</a> - Строитель</td>
<td style="width: 500px; padding: 18px;">🔎 Разделяет создание сложного объекта и его инициализацию так, что одинаковый процесс построения может может создавать объекты с разным состоянием.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/FactoryMethod/Program.cs">FactoryMethod</a> - Фабричный метод</td>
<td style="width: 500px; padding: 18px;">🔎 Определяет интерфейс для создания объекта, но позволяет подклассам решать, какой класс создавать. Позволяет делегировать создание класса объектам класса.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/FluentBuilder/Program.cs">FluentBuilder</a> - Гибкий(плавный, текучий) строитель</td>
<td style="width: 500px; padding: 18px;">🔎 Позволяет упростить процесс создания сложных объектов с помощью методов-цепочек, которые наделяют объект каким-то определенным качеством.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Prototype/Program.cs">Prototype</a> - Прототип</td>
<td style="width: 500px; padding: 18px;">🔎 Определяет несколько видов объектов, чтобы при создании использовать объект-прототип и создаёт новые объекты, копируя прототип (техника клонирования объектов).</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Singleton/Program.cs">Singleton</a> - Одиночка</td>
<td style="width: 500px; padding: 18px;">🔎 Гарантирует что класс имеет только один экземпляр и представляет глобальную точку доступа к нему.</td>
</tr>
</tbody>
</table>
<br>
<h1 align="center">🏩 Structural - Структурные [7]🏩<h1><br>
<table align="center">
<thead>
<tr>
<th>Паттерн</th>
<th>Краткое определение</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Adapter/Program.cs">Adapter</a> - Адаптер</td>
<td style="width: 500px; padding: 18px;">🔎 Конвенртирует интерфейс класса в другой интерфейс, ожидаемый клиентом. Позволяет классам с разными интерфейсами работать вместе.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Bridge/Program.cs">Bridge</a> - Мост</td>
<td style="width: 500px; padding: 18px;">🔎 Разделяет абстракцию и реализацию так, чтобы они могли изменяться независимо друг от друга.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Composite/Program.cs">Composite</a> - Компоновщик</td>
<td style="width: 500px; padding: 18px;">🔎 Компонует объекты в древовидную структуру по принципу "часть-целое", представляя их в виде иерархии. Позволяет клиенту одинаково обращаться как к отдельному, так и к целому поддереву.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Decorator/Program.cs">Decorator</a> - Декоратор</td>
<td style="width: 500px; padding: 18px;">🔎 Динамически предоставляет объекту дополнительные возможности. Представляет собой гибкую альтернативу наследованию для расширения функциональности.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Facade/Program.cs">Facade</a> - Фасад</td>
<td style="width: 500px; padding: 18px;">🔎 Предоставляет единый интерфейс к группе интерфейсов подсистемы. Определяет высокоуровневый интерфейс, делая систему проще для использования.</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Flyweight/Program.cs">Flyweight</a> - Приспособленец</td>
<td style="width: 500px; padding: 18px;">🔎 Благодаря совместному использованию, поддерживает эффективную работу с большим количеством объектов. (для оптимизации работы с памятью)</td>
</tr>
<tr>
<td style="width: 500px; padding: 18px;">💢 <a href="/Patterns/Proxy/Program.cs">Proxy</a> - Заместитель</td>
<td style="width: 500px; padding: 18px;">🔎 Предоставляет объект-заместитель другого объекта для контроля доступа к нему.</td>
</tr>
</tbody>
</table>