Main
This commit is contained in:
Dvurechensky 2024-10-05 09:30:14 +03:00
commit a4cd4b4ced
48 changed files with 3665 additions and 0 deletions

2
.gitattributes vendored Normal file

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

226
.gitignore vendored Normal file

@ -0,0 +1,226 @@
# The following command works for downloading when using Git for Windows:
# curl -LOf http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore
#
# Download this file using PowerShell v3 under Windows with the following comand:
# Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore
#
# or wget:
# wget --no-check-certificate http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
[Bb]in/
[Oo]bj/
# build folder is nowadays used for build scripts and should not be ignored
#build/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
modulesbin/
tempbin/
# EPiServer Site file (VPP)
AppData/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# vim
*.txt~
*.swp
*.swo
# Temp files when opening LibreOffice on ubuntu
.~lock.*
# svn
.svn
# CVS - Source Control
**/CVS/
# Remainings from resolving conflicts in Source Control
*.orig
# SQL Server files
**/App_Data/*.mdf
**/App_Data/*.ldf
**/App_Data/*.sdf
#LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
# =========================
# Windows detritus
# =========================
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# OS generated files #
Icon?
# Mac desktop service store files
.DS_Store
# SASS Compiler cache
.sass-cache
# Visual Studio 2014 CTP
**/*.sln.ide
# Visual Studio temp something
.vs/
# dotnet stuff
project.lock.json
# VS 2015+
*.vc.vc.opendb
*.vc.db
# Rider
.idea/
# Visual Studio Code
.vscode/
# Output folder used by Webpack or other FE stuff
**/node_modules/*
**/wwwroot/*
# SpecFlow specific
*.feature.cs
*.feature.xlsx.*
*.Specs_*.html
# UWP Projects
AppPackages/
#####
# End of core ignore list, below put you custom 'per project' settings (patterns or path)
#####

121
LICENCE 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>Pattern_1_Адаптер_Adapter_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,59 @@
/*
* СТРУКТУРНЫЕ ПАТТЕРНЫ
*
* Глава_12: Адаптер (Adapter)
*
* - преобразует интерфейс одного класса в интерфейс другого, который
* ожидают клиенты. Адаптер делает возможной совместную работу
* классов с несовместимыми интерфейсами
*/
class Motorcycle { }
/// <summary>
/// Что адаптируем
/// </summary>
class Voskhod : Motorcycle
{
public void Sound() => Console.WriteLine("DRDRDR");
}
/// <summary>
/// Цель на которую нужно ориентироваться при адаптации
/// </summary>
interface Isport
{
void MakeNoise();
}
/// <summary>
/// Пример готового объекта aдаптированного под цель
/// </summary>
class Honda : Motorcycle, Isport
{
public void MakeNoise() => Console.WriteLine("hooondaaa");
}
/// <summary>
/// Адаптер
/// Адаптирует простой класс под цель
/// </summary>
class TuningVoskhod : Isport
{
Voskhod moto;
public TuningVoskhod(Voskhod moto) => this.moto = moto;
public void MakeNoise()
{
Console.WriteLine("trsh");
moto.Sound();
}
}
class Program
{
public static void Main(string[] args)
{
var tun = new TuningVoskhod(new Voskhod());
tun.MakeNoise();
}
}

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>Мой сниппет</Title>
<Author>Николай</Author>
<Shortcut>CR</Shortcut>
<Description>генерация void метода</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>имя</ID>
<Default>sb</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[Console.ReadLine();]]>
</Code>
<Imports>
<Import>
<Namespace>System</Namespace>
</Import>
</Imports>
</Snippet>
</CodeSnippet>

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_1_Синглтон_Singleton_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,33 @@
/*
* ПОРОЖДАЮЩИЕ ПАТТЕРНЫ
*
* Глава_8: Сиглтон, Одиночка (Singleton)
*
* - гантирует, что у класса есть только один экземпляр,
* и предоставляет глобальную точку доступа к нему
*/
class Singleton
{
private Singleton()
{
Data = 28;
MoreData = 90;
}
public int Data { get; set; }
public int MoreData { get; set; }
/// <summary>
/// Отложенный синглтон (ленивый одиночка)
/// </summary>
static Lazy<Singleton> uniqueInstance = new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance => uniqueInstance.Value;
}
class Program
{
public static void Main()
{
Console.WriteLine(Singleton.Instance.Data);
}
}

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<Header>
<Title>Мой сниппет</Title>
<Author>Николай</Author>
<Shortcut>void</Shortcut>
<Description>генерация void метода</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>public</ID>
<ToolTip>Модификатор доступности</ToolTip>
<Default>public</Default>
</Literal>
<Literal>
<ID>void</ID>
<ToolTip>Тип возвращаемого значения</ToolTip>
<Default>void</Default>
</Literal>
<Literal>
<ID>name</ID>
<ToolTip>Имя метода</ToolTip>
<Default>name</Default>
</Literal>
<Literal>
<ID>value</ID>
<ToolTip>Возвращаемое значение</ToolTip>
<Default>value</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[
$public$ $void$ $name$()
{
return $value$;
}]]>
</Code>
</Snippet>
</CodeSnippet>

@ -0,0 +1,7 @@

namespace Behavioral;
public interface ILogReader
{
List<LogEntry> Read();
}

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

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

@ -0,0 +1,21 @@
namespace Behavioral;
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.Severity);
Console.WriteLine(logEntry.Message);
}
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_1-Стратегия</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,157 @@
namespace Behavioral;
/*
* На чем строилось:
* СЕРГЕЙ ТЕПЛЯКОВ - Паттерны проектирования на платформе .Net
* ШЕВЧУК, АХРИМЕНКО, КАСЬЯНОВ - Приемы объектно-ориентированного проектирования
*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
* Паттерн_1: Стратегия
*
* ! является более контекстно зависимой операцией
*
* Причины применения:
* 1.необходимость инкапсуляции поведения или алгоритма
* 2.необходимость замены поведения или алгоритма во время исполнения
*
* Другими словами, стратегия обеспечивает точку расширения системы
* в определенной плоскости: класс-контекст (LogProcessor) принимает экземпляр стратегии (LogFileReader)
* и не знает, какой вариант стратегии он собирается использовать.
*
* Особенность:
* Передача интерфейса ILogReader классу LogProcessor увеличивает гибкость,
* но в то же время повышает сложность.
* Теперь клиентам класса LogProcessor нужно решить, какую реализацию использовать,
* или переложить эту ответственность на вызывающий код.
*/
/*
* ВМЕСТО
* классической стратегии на основе наследования
* можно использовать стратегию на основе делегатов
*
* ПРИМЕР: Стратегия сортировки
*/
/*
* ВАЖНО: Гибкость не бывает бесплатной, поэтому выделять стратегии стоит тогда,
* когда действительно нужна замена поведения во время исполнения.
*/
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);
}
}
}
class Program
{
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)); //используем делегат
}
static void Main(string[] args)
{
var logFileReader = new LogFileReader();
/*
создали делегат который принимает в себя метод,
в результате выполнения которого возвращается List<LogEntry>
*/
Func<List<LogEntry>> _import = () => logFileReader.Read();
new LogProcessor(_import).ProcessLogs();
var 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); //он помещает сюда фабрику - ту что умеет создавать
}
}

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

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_2_Абстрактная_фабрика_Abstract_Factory_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
</ItemGroup>
</Project>

@ -0,0 +1,129 @@
/*
* ПОРОЖДАЮЩИЕ ПАТТЕРНЫ
*
* Глава_9: Абстрактная фабрика (Abstract Factory)
*
* - скрыть сложную логику инициализации
* - упростить поддержку функционала и его дополнение
* (крайне рекдо используется)
*/
using BenchmarkDotNet.Attributes;
/// <summary>
/// Фабрика
/// </summary>
interface ICar
{
void Drive();
}
class RacingCar : ICar
{
public void Drive() => Console.WriteLine("Ты на гоночном болиде едешь!");
}
class ConcreteCar : ICar
{
public void Drive() => Console.WriteLine("Ты на бетономешалке едешь!");
}
class UnknownCar : ICar
{
public void Drive() => Console.WriteLine("Ты на неизвестном едешь!");
}
enum TypeCar
{
Truck,
Racing
}
class CarFactory
{
public static ICar ProductCar(TypeCar type)
{
switch (type)
{
case TypeCar.Truck: return new RacingCar();
case TypeCar.Racing: return new ConcreteCar();
default: return new UnknownCar();
}
}
}
[MemoryDiagnoser]
[RankColumn]
public class Benchmark
{
[Benchmark]
public void ArrayListBench()
{
CarFactory.ProductCar(TypeCar.Truck).Drive();
}
[Benchmark]
public void ListBench()
{
var test = CarFactory.ProductCar(TypeCar.Truck);
test.Drive();
}
}
/// <summary>
/// Абстрактная фабрика
/// </summary>
interface ICarFactory
{
ICar ProductCar(TypeCar type);
}
class CarFactory_abstr : ICarFactory
{
public ICar ProductCar(TypeCar type)
{
switch (type)
{
case TypeCar.Truck: return new ConcreteCar();
case TypeCar.Racing: return new RacingCar();
default: return new UnknownCar();
}
}
}
class TuningCarFactory_abstr : ICarFactory
{
public ICar ProductCar(TypeCar type)
{
switch (type)
{
case TypeCar.Truck: return new ConcreteCar();
case TypeCar.Racing: return new RacingCar();
default: return new UnknownCar();
}
}
}
class AbstractFactory
{
public static ICarFactory GetFactory(bool tuning)
=> tuning ? new TuningCarFactory_abstr() : new CarFactory_abstr();
}
class Program
{
public static void Main(string[] args)
{
//BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
CarFactory.ProductCar(TypeCar.Truck).Drive();
CarFactory.ProductCar(TypeCar.Racing).Drive();
CarFactory.ProductCar((TypeCar)4).Drive();
AbstractFactory.GetFactory(true).ProductCar(TypeCar.Truck).Drive();
var factory = AbstractFactory.GetFactory(false);
ICar car = factory.ProductCar(TypeCar.Racing);
car.Drive();
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_2_Фасад_Facade_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,88 @@
/*
* СТРУКТУРНЫЕ ПАТТЕРНЫ
*
* Глава_13: Фасад (Facade)
*
* - предоставляет унифицированный интерфейс вместо набора
* интерфейсов некоторой подсистемы. Фасад определяет
* интерфейс более высокого уровня, который упрощает использование подсистемы
*/
class NICPc
{
public void C0()
=> Console.WriteLine("осуществляется программирование регистров микросхемы Host Bridge");
public void C1()
=> Console.WriteLine("с помощью последовательных циклов запись/чтение определяется тип памяти");
public void C2()
=> Console.WriteLine("проверяются первые 256 Кб памяти, для использования как транзитный буфер");
public void C6()
=> Console.WriteLine("по спец. алгоритму определяется наличие, тип и параметры External Cache.");
public void CF()
=> Console.WriteLine("определяется тип процессора, а результат помещается в CMOS");
public void Step05()
=> Console.WriteLine("осуществляется проверка и инициализация контроллера клавиатуры");
public void Step07()
=> Console.WriteLine("проверяется функционирование CMOS и напряжение питания батареи");
public void StepBE()
=> Console.WriteLine("программируются конфигурационные регистры Host Bridge и PIIX значениями, взятыми из BIOS");
public void Step0A()
=> Console.WriteLine("генерируется таблица векторов прерываний, а также первичная настройка подсистемы управления");
public void Step0B()
=> Console.WriteLine("проверяется контрольная сумма блока ячеек BIOS");
public void Step0C()
=> Console.WriteLine("инициализируется блок переменных BIOS");
public void Step0D0E()
=> Console.WriteLine("определяется наличие видеоадаптера путём проверки наличия сигнатуры 55AA");
public void Step3031()
=> Console.WriteLine("определяется объём Base Memory и External Memory, вступительный экран");
public void Step3D()
=> Console.WriteLine("инициализируется PS/2 mouse.");
public void Step41()
=> Console.WriteLine("производится инициализация подсистемы гибких дисков.");
public void Step45()
=> Console.WriteLine("инициализируется сопроцессор FPU");
public void StepF()
=> Console.WriteLine("Приветствие");
}
class Facade
{
NICPc pc;
public Facade(NICPc pc)
{
this.pc = pc;
}
public void Power()
{
pc.C0();
pc.C1();
pc.C2();
pc.C6();
pc.CF();
pc.Step05();
pc.Step07();
pc.StepBE();
pc.Step0A();
pc.Step0B();
pc.Step0C();
pc.Step0D0E();
pc.Step3031();
pc.Step3D();
pc.Step41();
pc.Step45();
pc.StepF();
}
}
class Program
{
public static void Main(string[] args)
{
new Facade(new NICPc()).Power();
}
}

@ -0,0 +1,6 @@
namespace Creational;
public struct ExceptionLogEntry
{
public string Message { get; set; }
}

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_2_Шаблонный_метод</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ServiceModel.Primitives" Version="4.9.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Pattern_1-Стратегия\Pattern_1-Стратегия(Strategy).csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,227 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_2 и 10: Фабричный метод(виртуальный конструктор) и Шаблонный метод (Паттерн поведения)
*
* это каркас, в который наследники могут
* подставить реализации недостающих элементов.
*
* - позволяет более четко определить «контракт» между базовым классом и потомками
*/
using Behavioral;
using Creational;
using System.ServiceModel;
using System.Text;
/*
* Теперь все реализации читателей логов будут вынуждены следовать согласованному протоколу
*/
public abstract class LogReader
{
private int _currentPosition;
/// <summary>
/// Определяет алгоритм импорта
/// </summary>
/// <returns></returns>
public IEnumerable<LogEntry> ReadLogEntry()
{
return ReadEntries(ref _currentPosition).Select(ParseLogEntry);
}
protected abstract IEnumerable<string> ReadEntries(ref int position);
protected abstract LogEntry ParseLogEntry(string stringEntry);
}
/*
* 2.1: Локальный шаблонный метод на основе делегатов
*
* ! является более контекстно зависимой операцией
*
* Использование наследования является слишком тяжеловесным решением,
* поэтому в таких случаях применяется подход, при котором переменный шаг алгоритма задается делегатом
*/
/// <summary>
/// Поведение сервиса сохранения записей
/// </summary>
interface ILogSaver
{
void UploadLogEntries(IEnumerable<LogEntry>logEntries);
void UploadExceptions(IEnumerable<ExceptionLogEntry> exceptions);
}
/// <summary>
/// Прокси - класс инкапсулирует особенности работы
/// с WCF - инфраструктурой
/// </summary>
class LogSaverProxy : ILogSaver
{
/// <summary>
/// Подключение к службе
/// </summary>
class LogSaverClient : ClientBase<ILogSaver>
{
public ILogSaver LogSaver
{
get { return Channel; }
}
}
public void UploadExceptions(IEnumerable<ExceptionLogEntry> exceptions)
{
UseProxyClient(c => c.UploadExceptions(exceptions));
}
public void UploadLogEntries(IEnumerable<LogEntry> logEntries)
{
UseProxyClient(c => c.UploadLogEntries(logEntries));
}
private void UseProxyClient(Action<ILogSaver> accessor)
{
var client = new LogSaverClient();
try
{
accessor(client.LogSaver);
client.Close();
}
catch (CommunicationException e)
{
client.Abort();
Console.WriteLine(e.Message);
}
}
}
/*
* Подход на основе делегатов может не только применяться для определения
* локальных действий внутри класса, но и передаваться извне другому объекту
* в аргументах конструктора.
*/
/*
* 2.2: Шаблонный метод на основе методов расширения
*/
public abstract class LogEntryBase
{
public DateTime EntryDateTime { get; internal set; }
public LogType Severity { get; internal set; }
public string? Message { get; internal set; }
/// <summary>
/// ExceptionLogEntry - будет возвращать информацию об исключении
/// </summary>
public string? AdditionalInformation { get; internal set; }
}
public static class LogEntryBaseEx
{
public static string GetText(this LogEntryBase logEntry)
{
var sb = new StringBuilder();
sb.AppendFormat("{0}", logEntry.EntryDateTime)
.AppendFormat("{0}", logEntry.Severity)
.AppendLine(logEntry.Message)
.AppendLine(logEntry.AdditionalInformation);
return sb.ToString();
}
}
/// <summary>
/// Абстракция для взаимодействия с фабриками
/// </summary>
public abstract class Creator
{
private Product? product;
public abstract Product ProductFactoryMethod(int x, int y);
public abstract Product ProductFactoryMethod_2(int x, int y);
public void AnProductOperation(int x, int y)
{
product = ProductFactoryMethod(x, y);
}
public void AnProductOperation_2(int x, int y)
{
product = ProductFactoryMethod_2(x, y);
}
}
/// <summary>
/// Конкретная фабрика
/// </summary>
public class ConcreteCreator : Creator
{
public override Product ProductFactoryMethod(int x, int y)
{
return new ConcreteProduct(x, y);
}
public override Product ProductFactoryMethod_2(int x, int y)
{
return new ConcreteProduct_2(x, y);
}
}
/// <summary>
/// Абстракция для взаимодействия с продуктами
/// </summary>
public abstract class Product
{
public abstract void GetText();
}
/// <summary>
/// Конкретный продукт
/// </summary>
public class ConcreteProduct : Product
{
public ConcreteProduct(int x, int y)
{
Console.WriteLine($"x {x} y {y}");
}
public override void GetText()
{
Console.WriteLine("1");
}
}
public class ConcreteProduct_2 : Product
{
public ConcreteProduct_2(int x, int y)
{
Console.WriteLine($"x2 {x} y2 {y}");
}
public override void GetText()
{
Console.WriteLine("2");
}
}
public class Program
{
public static void Main(string[] args)
{
Product product1 = null;
Product product2 = null;
var creator = new ConcreteCreator(); //Инициализирую фабрику
product1 = creator.ProductFactoryMethod(1, 2);
product2 = creator.ProductFactoryMethod_2(1, 2);
Console.WriteLine($"{product1.GetType().Name} {product2.GetType().Name}");
product1.GetText();
product2.GetText();
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_3_Декоратор_Decorator_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,144 @@
/*
* СТРУКТУРНЫЕ ПАТТЕРНЫ
*
* Глава_14: Декоратор (Decorator)
*
* - динамически добавляет объекту новые обязанности. Является гибкой
* альтернативой порождению подклассов с целью расширения функциональности
*/
/// <summary>
/// Пример №1
/// </summary>
public sealed class Car
{
public string Model { get; set; }
public Car(string model, IEnumerable<string> options)
{
}
public List<string> Options { get; protected set; }
public int GetPrice() { return 0; }
public void Move() { }
public void Stop() { }
public override string ToString()
{
return base.ToString();
}
}
class MyCar
{
protected Car baseCar;
public MyCar(string model, IEnumerable<string> options)
{
baseCar = new Car(model, options);
}
public List<string> Options { get => baseCar.Options; }
public int GetPrice() => baseCar.GetPrice() + 100;
public void Move() { baseCar.Move(); }
public void Stop() { baseCar.Stop(); }
public override string ToString()
{
return $"{baseCar?.ToString()} +++";
}
}
/// <summary>
/// Пример №2 (Динамический декоратор)
/// </summary>
class Pizza
{
public virtual string MakePizza() => "Dough =>";
}
class ChickenPizza : Pizza
{
Pizza pizza;
public ChickenPizza(Pizza pizza)
{
this.pizza = pizza;
}
public override string MakePizza()
=> pizza.MakePizza() + "ChickenPizza =>";
}
class MeatPizza : Pizza
{
Pizza pizza;
public MeatPizza(Pizza pizza)
{
this.pizza = pizza;
}
public override string MakePizza()
=> pizza.MakePizza() + "MeatPizza =>";
}
class CheesePizza : Pizza
{
Pizza pizza;
public CheesePizza(Pizza pizza)
{
this.pizza = pizza;
}
public override string MakePizza()
=> pizza.MakePizza() + "CheesePizza =>";
}
/// <summary>
/// Пример №3 (статический декоратор - используем обобщение)
/// </summary>
public abstract class Pizza_Abstr
{
public virtual string MakePizza() => string.Empty;
}
public class ChickPizza : Pizza_Abstr
{
public ChickPizza() { }
public override string MakePizza() => "ChickPizza => ";
}
public class Pepper<T> : Pizza_Abstr
where T : Pizza_Abstr, new ()
{
T pizza;
public Pepper() => pizza = new T();
public override string MakePizza()
{
return $"{pizza.MakePizza()} Pepper =>";
}
}
public class Olives<T> : Pizza_Abstr
where T : Pizza_Abstr, new()
{
T pizza;
public Olives() => pizza = new T();
public override string MakePizza()
{
return $"{pizza.MakePizza()} Olives =>";
}
}
class Program
{
public static void Main(string[] argv)
{
#region 2
Pizza chickenPizza = new ChickenPizza(new Pizza());
Console.WriteLine(chickenPizza.MakePizza()); // Dough -> ChickenPizza ->
var chickenCheesePizza = new CheesePizza(new ChickenPizza(new Pizza()));
Console.WriteLine(chickenCheesePizza.MakePizza());
#endregion
#region 3
Pizza_Abstr pizza_Abstr = new ChickPizza();
Console.WriteLine(pizza_Abstr.MakePizza());
Pizza_Abstr chickenOlivesPizza = new Olives<ChickPizza>();
Console.WriteLine(chickenOlivesPizza.MakePizza());
#endregion
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_3_Посредник_Mediator_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,123 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_3: Фабричный метод(виртуальный конструктор)
*
* - определяет объект, инкапсулирующий способ взаимодействия множества объектов.
* - это клей, связывающий несколько независимых классов между собой.
* Он избавляет классы от необходимости ссылаться друг на друга,
* позволяя тем самым их независимо изменять и анализировать
*/
/// <summary>
/// Посредники
/// Предоставляет интерфейс для организации
/// процесса по обмену информацией между объектами типа Colleague.
/// </summary>
abstract class Mediator
{
public abstract void Send(string message, Colleague colleague);
}
/// <summary>
/// Конкретный посредник
/// Реализует алгоритм взаимодействия между объектами-коллегами
/// </summary>
class ConcreteMediator : Mediator
{
public Fermer Fermer { get; set; }
public Cannery Cannery { get; set; }
public Shop Shop { get; set; }
public override void Send(string message, Colleague colleague)
{
if(colleague == Fermer)
{
Cannery.MakeKetchup(message);
}
if(colleague == Cannery)
{
Shop.SellKetshup(message);
}
}
}
/// <summary>
/// Коллеги
/// Предоставляет интерфейс для организации процесса
/// взаимодействия объектов-коллег с объектом типа Mediator.
/// </summary>
abstract class Colleague
{
protected Mediator mediator;
public Colleague(Mediator mediator)
{
this.mediator = mediator; //передаем ссылку на абстрактный класс посредника
}
}
/// <summary>
/// Фермер
/// Каждый объект-коллега знает только об объекте-медиаторе.
/// Все объекты-коллеги обмениваются информацией
/// только через посредника (медиатора).
/// </summary>
class Fermer : Colleague
{
public Fermer(Mediator mediator)
: base(mediator) { }
public void GrowTomato()
{
string tomato = "Tomato";
Console.WriteLine($"{this.GetType().Name} raised {tomato}");
mediator.Send(tomato, this);
}
}
/// <summary>
/// Завод
/// </summary>
class Cannery : Colleague
{
public Cannery(Mediator mediator)
: base(mediator) { }
public void MakeKetchup(string message)
{
string ketchup = message + " Ketchup";
Console.WriteLine($"{this.GetType().Name} produced {ketchup}");
mediator.Send(ketchup, this);
}
}
/// <summary>
/// Магазин
/// </summary>
class Shop : Colleague
{
public Shop(Mediator mediator)
: base(mediator) { }
public void SellKetshup(string message)
{
Console.WriteLine($"{this.GetType().Name} sold {message}");
}
}
class Program
{
public static void Main(string[] args)
{
ConcreteMediator mediator = new ConcreteMediator();
var cannery = new Cannery(mediator);
var fermer = new Fermer(mediator);
var shop = new Shop(mediator);
mediator.Cannery = cannery;
mediator.Fermer = fermer;
mediator.Shop = shop;
fermer.GrowTomato();
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_3_Строитель_Builder_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,170 @@
/*
* ПОРОЖДАЮЩИЕ ПАТТЕРНЫ
*
* Глава_11: Строитель (Builder)
*
* - строитель отделяет конструирование сложного объекта
* от его представления, так что в результате одного и того же
* процесса конструирования могут получаться разные представления.
*/
/// <summary>
/// Шаблон адреса
/// </summary>
class Address
{
public string Street { get; set; }
public string House { get; set; }
public Address(string street, string house)
{
Street = street;
House = house;
}
}
/// <summary>
/// Представление с точки зрения паттерна
/// </summary>
class AddressElement
{
public string Title { get; set; }
public string Value { get; set; }
private List<AddressElement> Elements { get; set; }
public void AddElement(string title, string value)
{
Elements.Add(new AddressElement(title, value));
}
public AddressElement(string title, string value)
{
Elements = new List<AddressElement>();
Title = title;
Value = value;
}
private string Print(string indent = "") => "";
public override string ToString() => "";
}
/// <summary>
/// Конструирует корневую главную ячейку
/// </summary>
class AddressBuilder
{
AddressElement address;
public static AddressBuilder Build(string title, string value)
=> new AddressBuilder { address = new AddressElement(title, value) };
private AddressBuilder() { }
public AddressBuilder AddItem(string title, string value)
{
address.AddElement(title, value);
return this;
}
public override string ToString() => address.ToString();
}
/// <summary>
/// Классическое представление паттерна
/// </summary>
class Address_Classic
{
public string? Country { get; set; }
public string? City { get; set; }
public string? Street { get; set; }
public string? House { get; set; }
public string? Number { get; set; }
public override string ToString()
{
return $"Country: {(string.IsNullOrEmpty(Country) ? "unknown" : Country)}\n" +
$"City: {(string.IsNullOrEmpty(City) ? "unknown" : City)}\n" +
$"Street: {(string.IsNullOrEmpty(Street) ? "unknown" : Street)}\n" +
$"House: {(string.IsNullOrEmpty(House) ? "unknown" : House)}\n" +
$"Number: {(string.IsNullOrEmpty(Number) ? "unknown" : Number)}\n";
}
}
interface IAddressBuilder
{
IAddressBuilder SetCountry(string country);
IAddressBuilder SetCity(string city);
IAddressBuilder SetStreet(string street);
IAddressBuilder SetHouse(string house);
IAddressBuilder SetNumber(string number);
Address_Classic Build();
}
class AddressBuilder_Classic : IAddressBuilder
{
Address_Classic address_Classic;
public AddressBuilder_Classic() => address_Classic = new Address_Classic();
public Address_Classic Build() => address_Classic;
public IAddressBuilder SetCity(string city)
{
address_Classic.City = city;
return this;
}
public IAddressBuilder SetCountry(string country)
{
address_Classic.Country = country;
return this;
}
public IAddressBuilder SetHouse(string house)
{
address_Classic.House = house;
return this;
}
public IAddressBuilder SetNumber(string number)
{
address_Classic.Number = number;
return this;
}
public IAddressBuilder SetStreet(string street)
{
address_Classic.Street = street;
return this;
}
}
class Program
{
public static void Main(string[] args)
{
AddressBuilder addressBuilder =
AddressBuilder
.Build("Адрес", "Рабочий адрес")
.AddItem("Индекс", "214000")
.AddItem("страна", "РФ");
Console.WriteLine("");
//Классический конструктор
Address_Classic address_Classic = new AddressBuilder_Classic()
.SetCountry("country")
.SetCity("Moscow")
.SetHouse("Home")
.SetNumber("25")
.Build();
Console.WriteLine(address_Classic);
address_Classic = new AddressBuilder_Classic()
.SetCountry("New York")
.SetStreet("Skobelevskaya")
.Build();
Console.WriteLine(address_Classic);
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_4_Итератор_Iterator_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,333 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_4: Итератор
*
* - представляет доступ ко всем элементам составного объекта, не раскрывая его внутреннего представления
*/
/*
* пример техники "перечисляемый-перечислитель"
*/
interface IEnumerable
{
IEnumerator GetEnumenator();
}
class Bank : IEnumerable
{
List<Banknote> bankVault = new List<Banknote>()
{
new Banknote(), new Banknote(),
new Banknote(), new Banknote()
};
public Banknote this[int index]
{
get
{
return bankVault[index];
}
set
{
bankVault.Insert(index, value);
}
}
public int Count { get { return bankVault.Count; } }
public IEnumerator GetEnumenator()
{
return new Cashier(this);
}
}
class Banknote
{
public string Nominal = "100 $";
}
interface IEnumerator
{
bool MoveNext();
void Reset();
object Current { get; }
}
class Cashier : IEnumerator
{
private Bank bank;
private int current = -1;
public Cashier(Bank bank)
{
this.bank = bank;
}
public bool MoveNext()
{
if(current < bank.Count - 1)
{
current++;
return true;
}
return false;
}
public void Reset()
{
current = -1;
}
public object Current
{
get
{
return bank[current];
}
}
}
class SimpleSet<T>
{
int index;//какой именно элемент нужно возвращать
readonly T[] storage;
public SimpleSet(params T[] args)
{
storage = args;
Reset();
}
//свойство возвращающее элеент нашего хранилища
public T Current => storage[index++];
//можно ли продолжать обход массива
public bool MoveNext => index < storage.Length;
//обнуление значение индекса обхода
public void Reset() => index = 0;
}
class SimleSetYeild<T> : IEnumerable<T>// IEnumerator<T>,
{
//int index;
readonly T[] storage;
public SimleSetYeild(params T[] args)
{
storage = args;
//Reset();
}
//public T Current => storage[index++];
//object System.Collections.IEnumerator.Current => Current;
//public void Dispose(){}
public IEnumerator<T> GetEnumerator()
{
var len = storage.Length;
for (int i = 0; i < len; i++)
yield return storage[i]; //позволяет вернуть значение и перейти на следующую итерацию цикла
}
//public bool MoveNext() => index < storage.Length;
//public void Reset() => index = 0;
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();
}
class Dish : IEnumerable<int>
{
public Dish(string Name, int Weight, int Proteins = 0, int Fats = 0, int Carbohydrates = 0)
{
this.Name = Name;
this.Weight = Weight;
//this.Proteins = Proteins;
//this.Fats = Fats;
nutrients = new Dictionary<string, int>
{
["Proteins"] = Proteins,
["Fats"] = Fats,
["Carbohydrates"] = Carbohydrates
};
}
//допы
readonly Dictionary<string, int> nutrients;
public int Proteins => nutrients[nameof(Proteins)];
public int Fats => nutrients[nameof(Fats)];
public int Carbohydrates => nutrients[nameof(Carbohydrates)];
public double AverageNutrients => nutrients.Values.Average();
//init - только в конструкторе может изменять значения свойства
public string Name { get; init; }
public int Weight { get; init; }
//public int Proteins { get; set; }
//public int Fats { get; set; }
//public int Average => (Proteins + Fats) / 2;
public override string ToString()
{
return $"{nameof(Name)} : {Name} {nameof(Weight)} : {Weight}";
}
public IEnumerator<int> GetEnumerator() => nutrients.Values.GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
}
class Menu : IEnumerable<Dish>
{
public Dish Pizza { get; init; }
public Dish Coffee { get; init; }
public Dish Soup { get; init; }
public IEnumerator<Dish> GetEnumerator()
{
//В каком порядке перечислять
yield return Pizza;
yield return Coffee;
yield return Soup;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => (System.Collections.IEnumerator)this;
}
public class Node<T>
{
public T Value { get; set; }
public Node<T> Left { get; set; }
public Node<T> Right { get; set; }
public Node<T> Parent { get; set; }
public Node (T value) => Value = value;
public Node (T value, Node<T> left = null, Node<T> right = null)
: this(value)
{
Left = left;
Right = right;
if(Left != null) Left.Parent = this;
if(Right != null) Right.Parent = this;
}
public override string ToString() => Value.ToString();
}
//обход самого дерева
public class InOrderIterator<T>
{
public Node<T> Current { get; set; }
private readonly Node<T> root;
private bool detourStarted;
//принимает корневой элемент с которого начнёт обход
public InOrderIterator(Node<T> root)
{
this.root = Current = root;
Reset();
}
public void Reset()
{
Current = root;
while(Current.Left != null) Current = Current.Left;
detourStarted = !true;
}
public bool MoveNext()
{
if (!detourStarted)
{
detourStarted = true;
return true;
}
if (Current.Right != null)
{
Current = Current.Right;
while (Current.Left != null) Current = Current.Left;
return true;
}
else
{
var temp = Current.Parent;
while(temp != null && Current == temp.Right)
{
Current = temp;
temp = temp.Parent;
}
Current = temp;
return Current != null;
}
}
}
class Program
{
public static void Main(string[] args)
{
IEnumerable bank = new Bank();
IEnumerator cashier = bank.GetEnumenator();
while(cashier.MoveNext())
{
if(cashier.Current is Banknote banknote)
Console.WriteLine(banknote.Nominal);
}
//стандартное реализация паттерна Итератор
var array = Enumerable.Range(1, 10).ToArray();
foreach (var item in array)
Console.WriteLine($"array: {item} ");
SimpleSet<int> set = new (array);
set.Reset();
while(set.MoveNext)
Console.WriteLine($"set: {set.Current}");
//Вторая реализация паттерна
SimleSetYeild<int> setyeild = new(array);
foreach (var item in setyeild) Console.WriteLine($"setyeild: {item}");
Menu menu = new()
{
Coffee = new("Latte", 200, 111, 222, 333),
Soup = new("Tom ", 230),
Pizza = new("Margarita", 600),
};
//foreach (var dish in menu) Console.WriteLine(dish);
foreach (var dish in menu)
{
Console.WriteLine($"{dish} - Average: {dish.AverageNutrients} [ ");
foreach (var st in dish)
{
Console.WriteLine($"{nameof(st)} {st}");
}
Console.WriteLine("] ");
}
//пример обхода деревьев (паттерн)
var three = new Node<string>(value: "html",
left: new(value: "head",
left: new(value: "title"),
right: new(value: "meta")),
right: new(value: "body",
left: new(value: "h1",
left: new(value: "a")),
right: new(value: "ul",
left: new(value: "li"),
right: new(value: "li")))
);
var rlr = new InOrderIterator<string>(three);
while (rlr.MoveNext()) Console.WriteLine($"{rlr.Current}");
Console.WriteLine();
rlr.Reset();
while (rlr.MoveNext()) Console.WriteLine($"{rlr.Current}");
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_4_Компоновщик_Composite_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,166 @@
/*
* СТРУКТУРНЫЕ ПАТТЕРНЫ
*
* Глава_15: Компоновщик (Composite)
*
* - компонует объекты в древовидные структуры для представления
* иерархий «часть целое». Позволяет клиентам единообразно
* трактовать индивидуальные и составные объекты
*/
class UIElement
{
public UIElement(string name)
{
Children = new List<UIElement>();
}
public List<UIElement> Children { get; set; }
public string Name { get; set; }
public int Width { get; set; }
public int Height { get; set; }
protected virtual string Draw(string p = "") { return p; }
public override string ToString() => $"{Draw()}";
}
class TextBox : UIElement
{
public TextBox(string name = "textBox") : base(name) { }
}
class Label : UIElement
{
public Label(string name = "label") : base(name) { }
}
class Panel : UIElement
{
public Panel(string name = "panel") : base(name) { }
}
class TextBlock : UIElement
{
public TextBlock(string name = "textBlock") : base(name) { }
}
/// <summary>
/// Пример отправки писем группе адресатов
/// </summary>
interface IEMail
{
void Send();
string Name { get; set; }
}
class Group : IEMail
{
public Group(params IEMail[] es) => Append(es);
public List<IEMail> eMails = new();
public string Name { get; set; }
public void Append(params IEMail[] es) {
foreach (var item in es) eMails.Add(item);
}
public void Send() {
foreach(var item in eMails) item.Send();
}
}
class EMail : IEMail
{
public string Name { get; set; }
public void Send() => Console.WriteLine($"Send {Name}");
}
/// <summary>
/// Генератор файловой системы
/// </summary>
abstract class IFileSystem
{
protected virtual IFileSystem AddItem(IFileSystem element) => this;
public abstract void PrintInfo(string w = "");
public string Title { get; set; }
}
class Document : IFileSystem
{
public override void PrintInfo(string w = "")
{
Console.WriteLine($"{w}{Title}");
}
}
class Folder : IFileSystem
{
private readonly List<IFileSystem> fileSystem;
public Folder() => fileSystem = new();
public IFileSystem AddElement(params IFileSystem[] element)
{
foreach (var item in element) AddItem(item);
return this;
}
public override void PrintInfo(string w = "")
{
Console.WriteLine($"{w}{Title}");
foreach (var item in fileSystem) item.PrintInfo(w);
}
protected override IFileSystem AddItem(IFileSystem element)
{
fileSystem.Add(element);
return this;
}
}
public class Program
{
public static void Main(string[] argv)
{
#region 1
var panel1 = new Panel("panel1");
var tb1 = new TextBox("textBox1");
var tb2 = new TextBox("textBox2");
panel1.Children.Add(tb1);
var panel2 = new Panel("panel2");
var tb3 = new TextBox("textBox3");
var lbl1 = new Label("label1");
lbl1.Children.Add(new TextBlock("textBlock1"));
panel2.Children.Add(tb3);
panel2.Children.Add(lbl1);
panel1.Children.Add(panel2);
panel1.Children.Add(tb2);
Console.WriteLine(panel1);
#endregion
#region 2
EMail c = new EMail() { Name = "nik" };
c.Send();
EMail r = new EMail() { Name = "nikr" };
r.Send();
EMail u = new EMail() { Name = "niku" };
u.Send();
EMail d = new EMail() { Name = "nikd" };
d.Send();
Group cr = new Group(c, r, u);
cr.Send();
//3
new Folder() { Title = "C:/"}
.AddElement(new Folder() { Title = "Windows/"}
.AddElement(new Folder() { Title = "System32/" }
.AddElement(new Document() { Title = "system.xml"}),
new Folder() { Title = "Driver/"}
.AddElement(new Folder() { Title = "etc/"}
.AddElement(new Document() { Title = "jp.json"}),
new Folder() { Title = "etc2"})))
.PrintInfo();
#endregion
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_5_Заместитель_Proxy_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,130 @@
/*
* СТРУКТУРНЫЕ ПАТТЕРНЫ
*
* Глава_16: Заместитель (Proxy)
*
* - является суррогатом другого объекта и контролирует доступ к нему.
*/
/// <summary>
/// Абстрактная сущность о беге
/// </summary>
public abstract class ActionObject
{
public abstract void Run();
}
public class Human : ActionObject
{
public int Age { get; set; }
public Human ()
{
Age = new Random().Next(14, 70);
}
public override void Run() => Console.WriteLine("RUN!");
public Human Clone()
{
Human temp = new Human() { Age = this.Age };
return temp;
}
}
public class AvatarV1 : ActionObject
{
Human human;
public AvatarV1(Human human)
{
this.human = human.Clone();
//или
//this.human = human;
//если есть(нужен) доступ к исходному объекту
}
public int AvatarAge => human.Age;
public override void Run()
{
Console.WriteLine("AvatarV1 Run");
human.Run();
}
}
/// <summary>
/// Proxy сервер
/// </summary>
class Client
{
private string id;
public string Id { get => id; set => id = value; }
public Client(string id = "#2022") => this.id = id;
}
interface IServer
{
void AccessGranted(Client user);
void AccessClosed(Client user);
}
class Server : IServer
{
public Server() => Console.WriteLine("Сервер создан");
public void AccessClosed(Client user)
{
Console.WriteLine("Closed");
}
public void AccessGranted(Client user)
{
Console.WriteLine("Granted");
}
}
class ServerProxy : IServer
{
private Lazy<Server> server;
public ServerProxy() { }
public void AccessClosed(Client client)
{
if (server == null)
{
Console.WriteLine("Unknown user");
}
else
{
server.Value.AccessGranted(user: client);
}
}
public void Autentification(Client client)
{
if (client.Id != "#2022") return;
Console.WriteLine("OK");
server = new();
AccessGranted(client);
}
public void AccessGranted(Client client)
{
if(server == null)
{
Console.WriteLine("Access Close");
return;
}
server.Value.AccessClosed(user: client);
}
}
class Program
{
public static void Main(string[] argv)
{
Human human = new Human();
human.Run();
AvatarV1 avatar = new AvatarV1(human);
avatar.Run();
ServerProxy proxy = new(); //proxy прослойка между сервером
proxy.Autentification(new Client() { });
proxy.AccessGranted(new Client() { });
proxy.AccessClosed(new Client() { });
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_5_Наблюдатель_Observer_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,328 @@
using System.Collections;
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_5: Наблюдатель
*
* - определяет зависимость типа «один ко многим»» (один издатель ко многим подписчикам) между объектами
* таким образом, что при изменении состояния одного объекта все зависящие от него
* оповещаются об этом и автоматически обновляются
*
* -описывает правильные способы организации процесса подписки на определенные события
*/
/*
* Модель вытягивания (Pull model)
*/
/// <summary>
/// Обозреватели газеты
/// </summary>
abstract class Observer
{
public abstract void Update();
}
/// <summary>
/// Издатели газеты
/// </summary>
abstract class Subject
{
ArrayList observers = new ArrayList();
public void Attach(Observer observer)
{
observers.Add(observer);
}
public void Detach(Observer observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (Observer observer in observers)
observer.Update();
}
}
/// <summary>
/// Конкретный издатель(издатель газеты) (наблюдаемый)
/// </summary>
class ConcreteSubject
: Subject
{
public string State { get; set; }
}
/// <summary>
/// Конкретный обозреватель (наблюдатель)
/// </summary>
class ConcreteObserver
: Observer
{
string observerState;
ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject)
{
this.subject = subject;
}
public override void Update()
{
observerState = subject.State;
}
}
/*
* Модель проталкивания (Push model)
*/
/// <summary>
/// Обозреватели газеты
/// </summary>
abstract class Observer_Push
{
public abstract void Update(string state); // получает уведомление о новостях
}
/// <summary>
/// Издатели газеты
/// </summary>
abstract class Subject_Push
{
ArrayList observers = new ArrayList();
public abstract string State { get; set; }
/// <summary>
/// Добавить новость в газету
/// </summary>
/// <param name="observer">обозреватель газеты</param>
public void Attach(Observer_Push observer)
{
observers.Add(observer);
}
/// <summary>
/// Удалить новость из газеты
/// </summary>
/// <param name="observer">обозреватель газеты</param>
public void Detach(Observer_Push observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (Observer_Push observer in observers)
observer.Update(State);
}
}
/// <summary>
/// Конкретный издатель(издатель газеты)
/// </summary>
class ConcreteSubject_Push
: Subject_Push
{
public override string State { get; set; }
}
/// <summary>
/// Конкретный обозреватель
/// </summary>
class ConcreteObserver_Push
: Observer_Push
{
string observerState;
ConcreteSubject_Push subject;
public ConcreteObserver_Push(ConcreteSubject_Push subject)
{
this.subject = subject;
}
public override void Update(string state)
{
observerState = subject.State;
}
}
/// <summary>
/// Пример №2
/// </summary>
class Event { }
class LoggerEvent : Event { }
class AlertEvent : Event { }
/// <summary>
/// Класс, за которым можно наблюдать
/// получая оповещения о происходящих в нем событиях
/// </summary>
class TicTokUser : IObservable<Event>
{
public List<Subscription> Subscriptions { get; init; }
public TicTokUser() => Subscriptions = new List<Subscription>();
public void Alert()
{
Random r = new Random();
foreach (var sub in Subscriptions)
{
Event e = r.Next(2) switch
{
0 => new LoggerEvent(),
_ => new AlertEvent()
};
sub.observer.OnNext(e);
}
}
/*
- IObserver - тот, кто хочет получать
уведомления от наблюдающего класса
- IDisposable - как правило реализуют
с целью возможной отписки
*/
public IDisposable Subscribe(IObserver<Event> observer)
{
var sub = new Subscription(this, observer);
Subscriptions.Add(sub);
return sub;
}
}
class Subscription : IDisposable
{
private TicTokUser user;
public IObserver<Event> observer;
public Subscription(TicTokUser user, IObserver<Event> observer)
{
this.user = user;
this.observer = observer;
}
/// <summary>
/// Удаление наблюдаемого класса из перечня подписавшихся
/// </summary>
public void Dispose() => user.Subscriptions.Remove(this);
}
/// <summary>
/// Конкретный подписчик
/// </summary>
class Observers : IObserver<Event>
{
public Observers()
{
var user = new TicTokUser();
var sub = user.Subscribe(this);
user.Alert();
user.Alert();
sub.Dispose();
user.Alert();
}
/// <summary>
/// Наблюдение окончено - больше ничего
/// происходить не будет
/// </summary>
public void OnCompleted() { }
/// <summary>
/// Обработка ошибки, явное оповещение
/// </summary>
/// <param name="error"></param>
public void OnError(Exception error) { }
/// <summary>
/// Событие при получении данных
/// </summary>
/// <param name="value"></param>
public void OnNext(Event value)
{
if (value is LoggerEvent) Console.WriteLine("Произошло событие OnNext value is LoggerEvent");
if (value is AlertEvent) Console.WriteLine("Произошло событие OnNext value is AlertEvent");
}
}
/// <summary>
/// Логика социальной сети (делегаты)
/// </summary>
class MediaFile
{
public MediaFile (string fileName) => FileName = fileName;
public string FileName { get; set; }
}
class Video : MediaFile
{
public Video(string fileName) : base(fileName) { }
}
class Accaunt
{
public string Nick { get; set; }
}
class TicTokUsers : Accaunt
{
protected event Action<TicTokUsers, string> followers;
public void Subscribe(TicTokUsers user)
{
Console.WriteLine($"{user.Nick} подписался на {Nick}");
followers += user.Alert;
}
public void UnSubscribe(TicTokUsers user)
{
Console.WriteLine($"{user.Nick} отдписался на {Nick}");
followers -= user.Alert;
}
public void Alert(TicTokUsers sender, string info)
{
if (sender != this) Console.WriteLine($"Лента {Nick}: У {sender.Nick} {info}");
else Console.WriteLine($"У меня ({Nick}) {info}");
}
public void VideoPublishing(MediaFile media)
{
var fn = $"вышло видео '{media.FileName}'";
Alert(this, fn);
followers?.Invoke(this, fn);
}
}
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Pull model");
ConcreteSubject subject_pull = new ConcreteSubject(); //инициализируем издателя газеты
subject_pull.Attach(new ConcreteObserver(subject_pull)); //публикуем новость для читателя
subject_pull.Attach(new ConcreteObserver(subject_pull)); //публикуем новость для читателя
subject_pull.State = "Some state ...";
subject_pull.Notify();
Console.WriteLine("Push model");
ConcreteSubject subject_push = new ConcreteSubject();
subject_push.Attach(new ConcreteObserver(subject_push)); //публикуем новость для читателя
subject_push.Attach(new ConcreteObserver(subject_push)); //публикуем новость для читателя
subject_push.State = "Some state ...";
subject_push.Notify();
_ = new Observers(); //Пример 2 на TicTok
TicTokUsers user1 = new() { Nick = "user_1" };
TicTokUsers user2 = new() { Nick = "user_2" };
user1.VideoPublishing(new MediaFile("Misl 1"));
user1.Subscribe(user2);
user1.VideoPublishing(new MediaFile("Misl 2"));
user1.VideoPublishing(new MediaFile("Misl 3"));
Console.WriteLine();
user2.Subscribe(user1);
user2.VideoPublishing(new MediaFile("History 1"));
Console.ReadLine();
}
}

@ -0,0 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console;
namespace Pattern_5_Наблюдатель_Observer_
{
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_6_Посетитель_Visitor_</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,121 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_6: Посетитель
*
* - добавление поведения в иерархию объектов, не изменяя их классы
*/
/*
* При добавлении нового поведения в IAnimal нарушаются SOLID принципы,
* для этого и существует подход Visitor чтобы внедрять поведение в конкретные классы наследники
*/
interface IAnimal
{
void Move();
}
class Cat : IAnimal
{
public void Move() => Console.WriteLine("Kradetsy besshumno");
}
class Dog : IAnimal
{
public void Move() => Console.WriteLine("beshit");
}
class Bird : IAnimal
{
public void Move() => Console.WriteLine("fly");
}
interface IVisitor
{
void Make(Cats cat);
void Make(Dogs cat);
void Make(Birds cat);
}
/// <summary>
/// Реализация Visitor №1
/// </summary>
abstract class Animals
{
public abstract void Accept(IVisitor visitor);
}
class Cats : Animals
{
public override void Accept(IVisitor visitor) => visitor.Make(this);
}
class Dogs : Animals
{
public override void Accept(IVisitor visitor) => visitor.Make(this);
}
class Birds : Animals
{
public override void Accept(IVisitor visitor) => visitor.Make(this);
}
class Kiwi : Birds
{
public override void Accept(IVisitor visitor) => visitor.Make(this);
}
class VoiceVisitor : IVisitor
{
public virtual void Make(Dogs dogs) => Console.WriteLine("Gav");
public virtual void Make(Cats cat) => Console.WriteLine("My");
public virtual void Make(Birds cat) => Console.WriteLine("Chirik");
}
/// <summary>
/// Visitor для птички Киви
/// </summary>
class UpdateVoiceVisitor : VoiceVisitor
{
public override void Make(Birds bird)
{
if (bird is Kiwi) Console.WriteLine("Киви что-то там...");
else base.Make(bird);
}
}
class MoveVisitor : IVisitor
{
public void Make(Cats cat) => Console.WriteLine("Kradet");
public void Make(Dogs cat) => Console.WriteLine("Beg");
public void Make(Birds cat) => Console.WriteLine("Fly");
}
class Program
{
public static void Main(string[] args)
{
Dogs dogs = new Dogs();
Cats cats = new Cats();
Birds birds = new Birds();
var voice = new VoiceVisitor();
var move = new MoveVisitor();
dogs.Accept(voice);
cats.Accept(voice);
birds.Accept(voice);
dogs.Accept(move);
cats.Accept(move);
birds.Accept(move);
var updateVoiceVisitor = new UpdateVoiceVisitor();
var kiwi = new Kiwi();
kiwi.Accept(updateVoiceVisitor);
dogs.Accept(updateVoiceVisitor);
cats.Accept(updateVoiceVisitor);
birds.Accept(updateVoiceVisitor);
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_7_Команда</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,129 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_7_1: Команда
*
* - конкретное действие представить в виде конкретного объекта
*/
using System.Collections.ObjectModel;
class Accaunt
{
public string AccauntOwner { get; set; }
public int Balance { get; set; }
public Accaunt(string accauntOwner, int balance)
{
Balance = balance;
AccauntOwner = accauntOwner;
}
public void Info()
{
Console.WriteLine($"{AccauntOwner}: ${Balance}");
}
}
/// <summary>
/// Проверить факт выполнения операции
/// IOperation - единственный ответственный за действие
/// </summary>
interface IOperation
{
void Execute();
public bool IsComplete { get; }
}
/// <summary>
/// Шаблон команды пополнения кошелька
/// </summary>
class Deposit : IOperation
{
private readonly Accaunt accaunt;
private readonly int money;
private bool isComplete;
public bool IsComplete { get => isComplete; }
public Deposit(Accaunt accaunt, int money)
{
this.accaunt = accaunt;
this.money = money;
isComplete = false;
}
/// <summary>
/// Обработка выполения команды
/// </summary>
public void Execute()
{
accaunt.Balance += money;
isComplete = true;
}
}
/// <summary>
/// Команда снятия с кошелька
/// </summary>
class Withdraw : IOperation
{
private readonly Accaunt accaunt;
private readonly int money;
private bool isComplete;
public bool IsComplete { get => isComplete; }
public Withdraw(Accaunt accaunt, int money)
{
this.accaunt = accaunt;
this.money = money;
isComplete = false;
}
/// <summary>
/// Обработка выполения команды
/// </summary>
public void Execute()
{
if (accaunt.Balance - money < 0) return;
accaunt.Balance -= money;
isComplete = true;
}
}
/// <summary>
/// коллекция команд
/// </summary>
class Operations : Collection<IOperation> { }
class OperationManager
{
static public OperationManager Instance;
static OperationManager() => Instance = new OperationManager();
private Operations transactions;
private OperationManager() => transactions = new Operations();
public void AddOperation(IOperation operation) => transactions.Add(operation);
public void ProcessOperations()
{
transactions.Where(op => !op.IsComplete)
.ToList()
.ForEach(op => op.Execute());
}
}
class Program
{
public static void Main()
{
Accaunt accaunt = new Accaunt("nik", 1000);
accaunt.Info();
new Deposit(accaunt, 1000).Execute();
accaunt.Info();
var manager = OperationManager.Instance;
manager.AddOperation(new Deposit(accaunt, 1000));
manager.AddOperation(new Deposit(accaunt, 1000));
manager.AddOperation(new Withdraw(accaunt, 100));
accaunt.Info();
manager.ProcessOperations();
accaunt.Info();
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_8_Состояние</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,165 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_7_2: Состояние
*
* - позволяет объекту поменять свое поведение в зависимости от состояния
*/
/// <summary>
/// Объектное представление логического состояния
/// </summary>
interface IState
{
void SetStateTrue(Variable v);
void SetStateFalse(Variable v);
}
class Variable
{
IState value;
public Variable()
{
value = new StateFalse();
}
public void SetState(IState state) => value = state;
public void False() => value.SetStateFalse(this);
public void True() => value.SetStateTrue(this);
public override string ToString() => value.ToString();
}
class StateFalse : IState
{
public void SetStateFalse(Variable v) { Console.WriteLine("Итак в лжи [False]"); }
public void SetStateTrue(Variable v) => v.SetState(new StateTrue());
public override string ToString() => "Current state: False";
}
class StateTrue : IState
{
public void SetStateFalse(Variable v) => v.SetState(new StateFalse());
public void SetStateTrue(Variable v) { Console.WriteLine("Итак в истине [True]"); }
public override string ToString() => "Current state: True";
}
/// <summary>
/// пример из реалной жизни
/// </summary>
class Camera : ICameraState
{
ICameraState state;
public Camera() => state = new OffState();
public void SetState(ICameraState state) => this.state = state;
public void RecordVideo(Camera camera) => state.RecordVideo(camera);
public void TakePictures(Camera camera) => state.TakePictures(camera);
public void TurnOff(Camera camera) => state.TurnOff(camera);
public void TurnOn(Camera camera) => state.TurnOn(camera);
}
interface ICameraState
{
void TurnOn(Camera camera);
void TurnOff(Camera camera);
void TakePictures(Camera camera);
void RecordVideo(Camera camera);
}
class FotoState : ICameraState
{
public void RecordVideo(Camera camera)
{
Console.WriteLine("Переходим в режим видео");
camera.RecordVideo(camera);
}
public void TakePictures(Camera camera) => Console.WriteLine("Камера уже в режиме фото");
/// <summary>
/// Выключить камеру
/// </summary>
/// <param name="camera">камера</param>
public void TurnOff(Camera camera)
{
Console.WriteLine("Нажата кнопка выключения");
camera.SetState(new OffState());
}
public void TurnOn(Camera camera) => Console.WriteLine("Камера уже включена");
}
class VideoState : ICameraState
{
public void RecordVideo(Camera camera) => Console.WriteLine("Камера уже в режиме видео");
public void TakePictures(Camera camera)
{
Console.WriteLine("Переходим в режим фото");
camera.TakePictures(camera);
}
/// <summary>
/// Выключить камеру
/// </summary>
/// <param name="camera">камера</param>
public void TurnOff(Camera camera)
{
Console.WriteLine("Нажата кнопка выключения");
camera.SetState(new OffState());
}
public void TurnOn(Camera camera) => Console.WriteLine("Камера уже включена");
}
class OnState : ICameraState
{
public void RecordVideo(Camera camera)
{
Console.WriteLine("Переходим в режим видео");
camera.RecordVideo(camera);
}
public void TakePictures(Camera camera)
{
Console.WriteLine("Переходим в режим фото");
camera.TakePictures(camera);
}
/// <summary>
/// Выключить камеру
/// </summary>
/// <param name="camera">камера</param>
public void TurnOff(Camera camera)
{
Console.WriteLine("Нажата кнопка выключения");
camera.SetState(new OffState());
}
public void TurnOn(Camera camera) => Console.WriteLine("Камера уже включена");
}
class OffState : ICameraState
{
public void RecordVideo(Camera camera) => Console.WriteLine("Камера ещё вылючена");
public void TakePictures(Camera camera) => Console.WriteLine("Камера ещё вылючена");
public void TurnOff(Camera camera) => Console.WriteLine("Камера уже вылючена");
public void TurnOn(Camera camera)
{
Console.WriteLine("Нажата кнопка включения");
camera.SetState(new OnState());
}
}
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("SimpleState.Something");
var sv = new Variable();
sv.True();
Console.WriteLine(sv);
sv.False(); Console.WriteLine(sv);
sv.False(); Console.WriteLine(sv);
sv.False(); Console.WriteLine(sv);
sv.True(); Console.WriteLine(sv);
}
}

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>Pattern_9_Цепочка_обязанностей</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,289 @@
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_7_3: Цепочка обязанностей
*
* - позволяет избежать привязки отправителя запроса к его получателю,
* давая шанс обработать запрос нескольким объектам
*
* - позволяет пробрасывать действия от одной компоненты к другой
*/
class Roshan
{
public Roshan(int hp = 30) => Hp = hp;
public int Hp { get; init; }
}
interface IHero
{
int Hp { get; set; }
Hero Next { get; set; }
void MustWin(Roshan enemy);
}
class Hero : IHero
{
public int Hp { get; set; }
public Hero Next { get; set; }
public string Name => GetType().Name;
public Hero(int hp, Hero hero) { }
public void MustWin(Roshan enemy)
{
if (Hp > enemy.Hp) { Console.WriteLine($"{Name} smog"); }
else
{
if(Next != null)
{
Console.WriteLine($"{Name} ne smog. Poprobyet {Next.GetType().Name}");
Next.MustWin(enemy);
return;
}
Console.WriteLine($"{Name} ne smog. Brag pobedil.");
}
}
}
class Ursa : Hero
{
public Ursa(int hp = 50, Hero hero = null) : base(hp, hero) { }
}
class Timbersaw : Hero
{
public Timbersaw(int hp = 70, Hero hero = null) : base(hp, hero) { }
}
class Axe : Hero
{
public Axe(int hp = 110, Hero hero = null) : base(hp, hero) { }
}
/// <summary>
/// Пример №2
/// </summary>
public class Heros
{
public string Name;
public int Attack { get; set; }
public int Armor { get; set; }
public Heros(string name, int attak, int armor)
{
Name = name;
Attack = attak;
Armor = armor;
}
public override string ToString() => $"{Name}: [{Attack}, {Armor}]\n";
}
public class Effect
{
protected Heros heros;
protected Effect next;
public Effect(Heros heros) => this.heros = heros;
public void Add(Effect effect)
{
if (next != null) next.Add(effect);
else next = effect;
}
/// <summary>
/// Выполнение действия
/// </summary>
public virtual void Handle() => next?.Handle();
}
public class DoubleDamageRune : Effect
{
public DoubleDamageRune(Heros heros)
: base(heros) { }
public override void Handle()
{
Console.WriteLine($"{heros.Name} активировал руну двойного урона");
heros.Attack *= 2;
base.Handle();
}
}
public class Halberd : Effect
{
public Halberd(Heros heros)
: base(heros) { }
public override void Handle()
{
Console.WriteLine("Существо лишено сил, от чего оно не может атаковать");
heros.Attack = 0;
}
}
/// <summary>
/// К какому игровому персонажу какой эффект нужно применить
/// * Самый сложный пример - с брокером событий
/// </summary>
public class Query
{
public string HeroName { get; set; }
public GameEffect TypeEffect { get; set; }
public Characteristic Args { get; set; }
public Query(string heroName, GameEffect typeEffect, Characteristic values)
{
HeroName = heroName;
TypeEffect = typeEffect;
Args = values;
}
}
public enum GameEffect
{
DubleDamageRunes = 1,
ArmorBonus = 2,
HalbertEffects = 3,
ArcaneRune = 4
}
public struct Characteristic
{
public int Attack { get; set; }
public int Armor { get; set; }
}
/// <summary>
/// Брокер который отвечает за эффекты применяемые к персонажу
/// </summary>
public class Game
{
public event EventHandler<Query> Queries;
public void CallQuery(object s, Query q) => Queries?.Invoke(s, q);
}
/// <summary>
/// В какой игре к какому персонажу применить какую характеристику
/// </summary>
public class Effects : IDisposable
{
protected Heross heross;
protected Game game;
public Effects(Heross heross, Game game)
{
this.heross = heross;
this.game = game;
game.Queries += Handlle;
}
public virtual void Handlle(object sender, Query e) => Console.WriteLine("Basic Effect");
public void Dispose() => game.Queries -= Handlle;
}
public class DoubleDamageRunes : Effects
{
public DoubleDamageRunes(Heross heross, Game game) : base(heross, game) { }
public override void Handlle(object sender, Query e)
{
if(e.HeroName == heross.Name
&& e.TypeEffect == (GameEffect.DubleDamageRunes | GameEffect.HalbertEffects))
{
e.Args = new Characteristic
{
Armor = e.Args.Armor,
Attack = 2 * e.Args.Attack
};
}
}
}
public class Halberds : Effects
{
public Halberds(Heross heross, Game game) : base(heross, game) { }
public override void Handlle(object sender, Query e)
{
if (e.HeroName == heross.Name
&& e.TypeEffect == GameEffect.HalbertEffects)
{
e.Args = new Characteristic
{
Armor = 1000,
Attack = 0
};
}
}
}
public class Heross
{
private readonly Game game;
public string Name;
Characteristic characteristic;
public int Attack
{
get
{
Query query = new (Name, GameEffect.DubleDamageRunes | GameEffect.ArmorBonus, characteristic);
game.CallQuery(this, query);
return query.Args.Attack;
}
}
public int Armor
{
get
{
Query query = new (Name, GameEffect.DubleDamageRunes | GameEffect.ArmorBonus, characteristic);
game.CallQuery(this, query);
return query.Args.Armor;
}
}
public Heross(string name, int attack, int armor, Game game)
{
Console.WriteLine($"Создан герой {name}");
Name = name;
characteristic.Attack = attack;
characteristic.Armor = armor;
this.game = game;
}
public override string ToString() => $"{Name} : [{Attack}, {Armor}]\n";
}
class Program
{
public static void Main(string[] args)
{
var enemy = new Roshan(109);
var ursa = new Ursa();
var timber = new Timbersaw();
var axe = new Axe();
ursa.Next = timber;
timber.Next = axe;
ursa.MustWin(enemy);
var heros = new Heros("Queen Of Pain", armor: 4, attak: 80);
Console.WriteLine(heros);
var game = new Effect(heros);
game.Add(new DoubleDamageRune(heros)); game.Handle();
Console.WriteLine(heros);
game.Add(new Halberd(heros)); game.Handle(); Console.WriteLine(heros);
var dota = new Game();
var heross = new Heross("Queen Of Pain", attack: 80, armor: 4, dota);
Console.WriteLine(heross);
var dd = new DoubleDamageRunes(heross, dota);
Console.WriteLine(heross);
dd.Dispose(); Console.WriteLine(heross);
var hb = new Halberds(heross, dota);
Console.WriteLine(heross);
hb.Dispose(); Console.WriteLine(heross);
}
}

146
Patterns/PatternsExtra.sln Normal file

@ -0,0 +1,146 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32210.238
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_1-Стратегия(Strategy)", "Pattern_1-Стратегия\Pattern_1-Стратегия(Strategy).csproj", "{9976C22F-4293-40CE-8E2E-F6C56D096164}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_3-Фабричный метод", "Pattern_2-Шаблонный метод\Pattern_3-Фабричный метод.csproj", "{BC45C9FC-E037-4066-B3EB-A5EA98D4E7BF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_3-Посредник(Mediator)", "Pattern_3-Посредник(Mediator)\Pattern_3-Посредник(Mediator).csproj", "{F2E4BD9E-E31E-4C5B-A7BA-6D14B4332388}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_4-Итератор(Iterator)", "Pattern_4-Итератор(Iterator)\Pattern_4-Итератор(Iterator).csproj", "{2A2134F4-9496-49A3-9F94-79EBC25F8E03}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_5-Наблюдатель(Observer)", "Pattern_5-Наблюдатель(Observer)\Pattern_5-Наблюдатель(Observer).csproj", "{71D4783A-71C3-4E88-9F18-D75A8D347824}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_6-Посетитель(Visitor)", "Pattern_6-Посетитель(Visitor)\Pattern_6-Посетитель(Visitor).csproj", "{6CF1383D-B4F4-485E-B294-827F919F28FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_7-Команда(Command)", "Pattern_7-Команда\Pattern_7-Команда(Command).csproj", "{988AD18B-096A-4F25-947F-07B4A68497D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_8-Состояние(State)", "Pattern_8-Состояние\Pattern_8-Состояние(State).csproj", "{BB702708-54E5-4831-8B3A-30B92B226DAE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_9-Цепочка обязанностей(ChainOfResponsobility)", "Pattern_9-Цепочка обязанностей\Pattern_9-Цепочка обязанностей(ChainOfResponsobility).csproj", "{F8109BBB-C1B9-44CC-982B-AE13ADF27E13}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Паттерны поведения", "Паттерны поведения", "{81D10339-197A-4101-B195-6866DE85ED80}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Порождающие паттерны", "Порождающие паттерны", "{772B724B-1643-417A-BC3B-F732C739F628}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_1-Синглтон(Singleton)", "Pattern_1-Синглтон(Singleton)\Pattern_1-Синглтон(Singleton).csproj", "{55927094-11C3-4F21-94AF-58A831A9A550}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_2-Абстрактная фабрика(Abstract Factory)", "Pattern_2-Абстрактная фабрика(Abstract Factory)\Pattern_2-Абстрактная фабрика(Abstract Factory).csproj", "{9BB70525-29BD-43BB-9F32-D2E3387CFE92}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_4-Строитель(Builder)", "Pattern_3-Строитель(Builder)\Pattern_4-Строитель(Builder).csproj", "{A2498812-2B35-4EAA-B8DD-1E2860BEA995}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Структурные паттерны", "Структурные паттерны", "{CFD4A239-FAAB-4C2B-A55C-1051E994069A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_1-Адаптер(Adapter)", "Pattern_1-Адаптер(Adapter)\Pattern_1-Адаптер(Adapter).csproj", "{5DEAE4CF-D089-42C5-9FCF-2D3C4B7AB385}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_2-Фасад(Facade)", "Pattern_2-Фасад(Facade)\Pattern_2-Фасад(Facade).csproj", "{B00B3EA6-B1E0-48E0-A42A-FE52C73BDAB3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_3-Декоратор(Decorator)", "Pattern_3-Декоратор(Decorator)\Pattern_3-Декоратор(Decorator).csproj", "{0234C795-F6EB-4CF0-BCC0-B4B97C789B12}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_4-Компоновщик(Composite)", "Pattern_4-Компоновщик(Composite)\Pattern_4-Компоновщик(Composite).csproj", "{0B5DCEE7-F54E-49AB-A63F-DFE0CBFF6AC9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pattern_5-Заместитель(Proxy)", "Pattern_5-Заместитель(Proxy)\Pattern_5-Заместитель(Proxy).csproj", "{8288DD61-F2B0-4B95-B8CE-04E920B8CAD0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9976C22F-4293-40CE-8E2E-F6C56D096164}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9976C22F-4293-40CE-8E2E-F6C56D096164}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9976C22F-4293-40CE-8E2E-F6C56D096164}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9976C22F-4293-40CE-8E2E-F6C56D096164}.Release|Any CPU.Build.0 = Release|Any CPU
{BC45C9FC-E037-4066-B3EB-A5EA98D4E7BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC45C9FC-E037-4066-B3EB-A5EA98D4E7BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC45C9FC-E037-4066-B3EB-A5EA98D4E7BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC45C9FC-E037-4066-B3EB-A5EA98D4E7BF}.Release|Any CPU.Build.0 = Release|Any CPU
{F2E4BD9E-E31E-4C5B-A7BA-6D14B4332388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2E4BD9E-E31E-4C5B-A7BA-6D14B4332388}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2E4BD9E-E31E-4C5B-A7BA-6D14B4332388}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2E4BD9E-E31E-4C5B-A7BA-6D14B4332388}.Release|Any CPU.Build.0 = Release|Any CPU
{2A2134F4-9496-49A3-9F94-79EBC25F8E03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A2134F4-9496-49A3-9F94-79EBC25F8E03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A2134F4-9496-49A3-9F94-79EBC25F8E03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A2134F4-9496-49A3-9F94-79EBC25F8E03}.Release|Any CPU.Build.0 = Release|Any CPU
{71D4783A-71C3-4E88-9F18-D75A8D347824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71D4783A-71C3-4E88-9F18-D75A8D347824}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71D4783A-71C3-4E88-9F18-D75A8D347824}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71D4783A-71C3-4E88-9F18-D75A8D347824}.Release|Any CPU.Build.0 = Release|Any CPU
{6CF1383D-B4F4-485E-B294-827F919F28FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6CF1383D-B4F4-485E-B294-827F919F28FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6CF1383D-B4F4-485E-B294-827F919F28FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6CF1383D-B4F4-485E-B294-827F919F28FA}.Release|Any CPU.Build.0 = Release|Any CPU
{988AD18B-096A-4F25-947F-07B4A68497D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{988AD18B-096A-4F25-947F-07B4A68497D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{988AD18B-096A-4F25-947F-07B4A68497D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{988AD18B-096A-4F25-947F-07B4A68497D0}.Release|Any CPU.Build.0 = Release|Any CPU
{BB702708-54E5-4831-8B3A-30B92B226DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB702708-54E5-4831-8B3A-30B92B226DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB702708-54E5-4831-8B3A-30B92B226DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB702708-54E5-4831-8B3A-30B92B226DAE}.Release|Any CPU.Build.0 = Release|Any CPU
{F8109BBB-C1B9-44CC-982B-AE13ADF27E13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8109BBB-C1B9-44CC-982B-AE13ADF27E13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8109BBB-C1B9-44CC-982B-AE13ADF27E13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8109BBB-C1B9-44CC-982B-AE13ADF27E13}.Release|Any CPU.Build.0 = Release|Any CPU
{55927094-11C3-4F21-94AF-58A831A9A550}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55927094-11C3-4F21-94AF-58A831A9A550}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55927094-11C3-4F21-94AF-58A831A9A550}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55927094-11C3-4F21-94AF-58A831A9A550}.Release|Any CPU.Build.0 = Release|Any CPU
{9BB70525-29BD-43BB-9F32-D2E3387CFE92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9BB70525-29BD-43BB-9F32-D2E3387CFE92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BB70525-29BD-43BB-9F32-D2E3387CFE92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BB70525-29BD-43BB-9F32-D2E3387CFE92}.Release|Any CPU.Build.0 = Release|Any CPU
{A2498812-2B35-4EAA-B8DD-1E2860BEA995}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2498812-2B35-4EAA-B8DD-1E2860BEA995}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2498812-2B35-4EAA-B8DD-1E2860BEA995}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2498812-2B35-4EAA-B8DD-1E2860BEA995}.Release|Any CPU.Build.0 = Release|Any CPU
{5DEAE4CF-D089-42C5-9FCF-2D3C4B7AB385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DEAE4CF-D089-42C5-9FCF-2D3C4B7AB385}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DEAE4CF-D089-42C5-9FCF-2D3C4B7AB385}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DEAE4CF-D089-42C5-9FCF-2D3C4B7AB385}.Release|Any CPU.Build.0 = Release|Any CPU
{B00B3EA6-B1E0-48E0-A42A-FE52C73BDAB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B00B3EA6-B1E0-48E0-A42A-FE52C73BDAB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B00B3EA6-B1E0-48E0-A42A-FE52C73BDAB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B00B3EA6-B1E0-48E0-A42A-FE52C73BDAB3}.Release|Any CPU.Build.0 = Release|Any CPU
{0234C795-F6EB-4CF0-BCC0-B4B97C789B12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0234C795-F6EB-4CF0-BCC0-B4B97C789B12}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0234C795-F6EB-4CF0-BCC0-B4B97C789B12}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0234C795-F6EB-4CF0-BCC0-B4B97C789B12}.Release|Any CPU.Build.0 = Release|Any CPU
{0B5DCEE7-F54E-49AB-A63F-DFE0CBFF6AC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B5DCEE7-F54E-49AB-A63F-DFE0CBFF6AC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B5DCEE7-F54E-49AB-A63F-DFE0CBFF6AC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B5DCEE7-F54E-49AB-A63F-DFE0CBFF6AC9}.Release|Any CPU.Build.0 = Release|Any CPU
{8288DD61-F2B0-4B95-B8CE-04E920B8CAD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8288DD61-F2B0-4B95-B8CE-04E920B8CAD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8288DD61-F2B0-4B95-B8CE-04E920B8CAD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8288DD61-F2B0-4B95-B8CE-04E920B8CAD0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9976C22F-4293-40CE-8E2E-F6C56D096164} = {81D10339-197A-4101-B195-6866DE85ED80}
{BC45C9FC-E037-4066-B3EB-A5EA98D4E7BF} = {772B724B-1643-417A-BC3B-F732C739F628}
{F2E4BD9E-E31E-4C5B-A7BA-6D14B4332388} = {81D10339-197A-4101-B195-6866DE85ED80}
{2A2134F4-9496-49A3-9F94-79EBC25F8E03} = {81D10339-197A-4101-B195-6866DE85ED80}
{71D4783A-71C3-4E88-9F18-D75A8D347824} = {81D10339-197A-4101-B195-6866DE85ED80}
{6CF1383D-B4F4-485E-B294-827F919F28FA} = {81D10339-197A-4101-B195-6866DE85ED80}
{988AD18B-096A-4F25-947F-07B4A68497D0} = {81D10339-197A-4101-B195-6866DE85ED80}
{BB702708-54E5-4831-8B3A-30B92B226DAE} = {81D10339-197A-4101-B195-6866DE85ED80}
{F8109BBB-C1B9-44CC-982B-AE13ADF27E13} = {81D10339-197A-4101-B195-6866DE85ED80}
{55927094-11C3-4F21-94AF-58A831A9A550} = {772B724B-1643-417A-BC3B-F732C739F628}
{9BB70525-29BD-43BB-9F32-D2E3387CFE92} = {772B724B-1643-417A-BC3B-F732C739F628}
{A2498812-2B35-4EAA-B8DD-1E2860BEA995} = {772B724B-1643-417A-BC3B-F732C739F628}
{5DEAE4CF-D089-42C5-9FCF-2D3C4B7AB385} = {CFD4A239-FAAB-4C2B-A55C-1051E994069A}
{B00B3EA6-B1E0-48E0-A42A-FE52C73BDAB3} = {CFD4A239-FAAB-4C2B-A55C-1051E994069A}
{0234C795-F6EB-4CF0-BCC0-B4B97C789B12} = {CFD4A239-FAAB-4C2B-A55C-1051E994069A}
{0B5DCEE7-F54E-49AB-A63F-DFE0CBFF6AC9} = {CFD4A239-FAAB-4C2B-A55C-1051E994069A}
{8288DD61-F2B0-4B95-B8CE-04E920B8CAD0} = {CFD4A239-FAAB-4C2B-A55C-1051E994069A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7EAC518E-F875-4F24-AB38-B1F72CB23C93}
EndGlobalSection
EndGlobal

17
README.md Normal file

@ -0,0 +1,17 @@
<p align="center">
<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>
# C# паттерны - дополнение 📚
**Создано в качестве дополнения к 🌟 [моему существующему репозиторию](https://github.com/Dvurechensky/Patterns-Programming)** 🌟
Содержит: **паттерны** и [примеры создания сниппетов](Patterns/Pattern_1-Синглтон(Singleton)/MySnippet.snippet)
Данная информация по C# проработанна мной с плейлиста грамотного человека 👊 [Сергея Камянецкого](https://www.youtube.com/playlist?list=PLsV7KW4r_oBAxqpJ0IyfJw16GBZXJvLKg) 👊