commit a4cd4b4cedbbe5c758c2f67ded542c806b834187 Author: Dvurechensky <46356631+Dvurechensky@users.noreply.github.com> Date: Sat Oct 5 09:30:14 2024 +0300 1.0 Main diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71ec0d1 --- /dev/null +++ b/.gitignore @@ -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) +##### \ No newline at end of file diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENCE @@ -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. diff --git a/Patterns/Pattern_1-Адаптер(Adapter)/Pattern_1-Адаптер(Adapter).csproj b/Patterns/Pattern_1-Адаптер(Adapter)/Pattern_1-Адаптер(Adapter).csproj new file mode 100644 index 0000000..6c47a30 --- /dev/null +++ b/Patterns/Pattern_1-Адаптер(Adapter)/Pattern_1-Адаптер(Adapter).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_1_Адаптер_Adapter_ + enable + enable + + + diff --git a/Patterns/Pattern_1-Адаптер(Adapter)/Program.cs b/Patterns/Pattern_1-Адаптер(Adapter)/Program.cs new file mode 100644 index 0000000..f06cabf --- /dev/null +++ b/Patterns/Pattern_1-Адаптер(Adapter)/Program.cs @@ -0,0 +1,59 @@ +/* + * СТРУКТУРНЫЕ ПАТТЕРНЫ + * + * Глава_12: Адаптер (Adapter) + * + * - преобразует интерфейс одного класса в интерфейс другого, который + * ожидают клиенты. Адаптер делает возможной совместную работу + * классов с несовместимыми интерфейсами + */ + +class Motorcycle { } + +/// +/// Что адаптируем +/// +class Voskhod : Motorcycle +{ + public void Sound() => Console.WriteLine("DRDRDR"); +} + +/// +/// Цель на которую нужно ориентироваться при адаптации +/// +interface Isport +{ + void MakeNoise(); +} + +/// +/// Пример готового объекта aдаптированного под цель +/// +class Honda : Motorcycle, Isport +{ + public void MakeNoise() => Console.WriteLine("hooondaaa"); +} + +/// +/// Адаптер +/// Адаптирует простой класс под цель +/// +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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_1-Синглтон(Singleton)/MySnippet.snippet b/Patterns/Pattern_1-Синглтон(Singleton)/MySnippet.snippet new file mode 100644 index 0000000..4cd0310 --- /dev/null +++ b/Patterns/Pattern_1-Синглтон(Singleton)/MySnippet.snippet @@ -0,0 +1,28 @@ + + +
+ Мой сниппет + Николай + CR + генерация void метода + + Expansion + +
+ + + + имя + sb + + + + + + + + System + + + +
diff --git a/Patterns/Pattern_1-Синглтон(Singleton)/Pattern_1-Синглтон(Singleton).csproj b/Patterns/Pattern_1-Синглтон(Singleton)/Pattern_1-Синглтон(Singleton).csproj new file mode 100644 index 0000000..6bcc1c5 --- /dev/null +++ b/Patterns/Pattern_1-Синглтон(Singleton)/Pattern_1-Синглтон(Singleton).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_1_Синглтон_Singleton_ + enable + enable + + + diff --git a/Patterns/Pattern_1-Синглтон(Singleton)/Program.cs b/Patterns/Pattern_1-Синглтон(Singleton)/Program.cs new file mode 100644 index 0000000..37ee5f0 --- /dev/null +++ b/Patterns/Pattern_1-Синглтон(Singleton)/Program.cs @@ -0,0 +1,33 @@ +/* + * ПОРОЖДАЮЩИЕ ПАТТЕРНЫ + * + * Глава_8: Сиглтон, Одиночка (Singleton) + * + * - гантирует, что у класса есть только один экземпляр, + * и предоставляет глобальную точку доступа к нему + */ +class Singleton +{ + private Singleton() + { + Data = 28; + MoreData = 90; + } + + public int Data { get; set; } + public int MoreData { get; set; } + + /// + /// Отложенный синглтон (ленивый одиночка) + /// + static Lazy uniqueInstance = new Lazy(() => new Singleton()); + public static Singleton Instance => uniqueInstance.Value; +} + +class Program +{ + public static void Main() + { + Console.WriteLine(Singleton.Instance.Data); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_1-Синглтон(Singleton)/voidSnippet.snippet b/Patterns/Pattern_1-Синглтон(Singleton)/voidSnippet.snippet new file mode 100644 index 0000000..6c09d88 --- /dev/null +++ b/Patterns/Pattern_1-Синглтон(Singleton)/voidSnippet.snippet @@ -0,0 +1,43 @@ + + +
+ Мой сниппет + Николай + void + генерация void метода + + Expansion + +
+ + + + public + Модификатор доступности + public + + + void + Тип возвращаемого значения + void + + + name + Имя метода + name + + + value + Возвращаемое значение + value + + + + + + +
diff --git a/Patterns/Pattern_1-Стратегия/ILogReader.cs b/Patterns/Pattern_1-Стратегия/ILogReader.cs new file mode 100644 index 0000000..8939f65 --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/ILogReader.cs @@ -0,0 +1,7 @@ + +namespace Behavioral; + +public interface ILogReader +{ + List Read(); +} \ No newline at end of file diff --git a/Patterns/Pattern_1-Стратегия/LogEntry.cs b/Patterns/Pattern_1-Стратегия/LogEntry.cs new file mode 100644 index 0000000..86d287a --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/LogEntry.cs @@ -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; } +} diff --git a/Patterns/Pattern_1-Стратегия/LogFileReader.cs b/Patterns/Pattern_1-Стратегия/LogFileReader.cs new file mode 100644 index 0000000..ba5626a --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/LogFileReader.cs @@ -0,0 +1,17 @@ +namespace Behavioral; + +public class LogFileReader : ILogReader +{ + public List Read() + { + return new List() + { + new LogEntry() + { + DateTime = DateTime.Now, + Message = GetType().Name, + Severity = LogType.Debug + } + }; + } +} diff --git a/Patterns/Pattern_1-Стратегия/LogProcessor.cs b/Patterns/Pattern_1-Стратегия/LogProcessor.cs new file mode 100644 index 0000000..a86c8d3 --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/LogProcessor.cs @@ -0,0 +1,21 @@ +namespace Behavioral; + +public class LogProcessor +{ + private readonly Func> _logimporter; + + public LogProcessor(Func> logImporter) + { + _logimporter = logImporter; + } + + public void ProcessLogs() + { + foreach(var logEntry in _logimporter.Invoke()) + { + Console.WriteLine(logEntry.DateTime); + Console.WriteLine(logEntry.Severity); + Console.WriteLine(logEntry.Message); + } + } +} diff --git a/Patterns/Pattern_1-Стратегия/Pattern_1-Стратегия(Strategy).csproj b/Patterns/Pattern_1-Стратегия/Pattern_1-Стратегия(Strategy).csproj new file mode 100644 index 0000000..d85a215 --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/Pattern_1-Стратегия(Strategy).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_1-Стратегия + enable + enable + + + diff --git a/Patterns/Pattern_1-Стратегия/Program.cs b/Patterns/Pattern_1-Стратегия/Program.cs new file mode 100644 index 0000000..ad9ded8 --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/Program.cs @@ -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}"); + } +} + +/// +/// Реализует интерфейс сортировки +/// Добавлет возможность сортировки по ID по возрастающей +/// +class EmployeeByIdComparer : IComparer +{ + int IComparer.Compare(Employee? x, Employee? y) + { + if(x is Employee xx && y is Employee yy) + return xx.Id.CompareTo(yy.Id); + else + return 0; + } +} + +/// +/// Фабричный класс для создания экземпляров IComparer +/// +class ComparerFactory +{ + public static IComparer Create(Comparison comparer) + { + return new DelegateComparer(comparer); + } + + private class DelegateComparer : IComparer + { + private readonly Comparison _comparer; + + public DelegateComparer(Comparison 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 list) + { + list.Sort(new EmployeeByIdComparer()); //используем функтор + } + + public static void SortListName(List list) + { + list.Sort((x, y) => x.Name.CompareTo(y.Name)); //используем делегат + } + + static void Main(string[] args) + { + var logFileReader = new LogFileReader(); + + /* + создали делегат который принимает в себя метод, + в результате выполнения которого возвращается List + */ + Func> _import = () => logFileReader.Read(); + + new LogProcessor(_import).ProcessLogs(); + + var employees = new List + { + 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(comparer); + + /* + конструктор принимает IComparable + нет конструктора, принимающего делегат Comparison + можно создать небольшой адаптерный фабричный класс + */ + var comparer_factory = ComparerFactory.Create((x, y) => x.Id.CompareTo(y.Id)); + var set_factory = new SortedSet(comparer_factory); //он помещает сюда фабрику - ту что умеет создавать + } +} diff --git a/Patterns/Pattern_1-Стратегия/WindowsEventLogReader.cs b/Patterns/Pattern_1-Стратегия/WindowsEventLogReader.cs new file mode 100644 index 0000000..825ee7e --- /dev/null +++ b/Patterns/Pattern_1-Стратегия/WindowsEventLogReader.cs @@ -0,0 +1,17 @@ +namespace Behavioral; + +public class WindowsEventLogReader : ILogReader +{ + public List Read() + { + return new List() + { + new LogEntry() + { + DateTime = DateTime.Now, + Message = GetType().Name, + Severity = LogType.Debug + } + }; + } +} diff --git a/Patterns/Pattern_2-Абстрактная фабрика(Abstract Factory)/Pattern_2-Абстрактная фабрика(Abstract Factory).csproj b/Patterns/Pattern_2-Абстрактная фабрика(Abstract Factory)/Pattern_2-Абстрактная фабрика(Abstract Factory).csproj new file mode 100644 index 0000000..7610c3b --- /dev/null +++ b/Patterns/Pattern_2-Абстрактная фабрика(Abstract Factory)/Pattern_2-Абстрактная фабрика(Abstract Factory).csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + Pattern_2_Абстрактная_фабрика_Abstract_Factory_ + enable + enable + + + + + + + diff --git a/Patterns/Pattern_2-Абстрактная фабрика(Abstract Factory)/Program.cs b/Patterns/Pattern_2-Абстрактная фабрика(Abstract Factory)/Program.cs new file mode 100644 index 0000000..fdd26f3 --- /dev/null +++ b/Patterns/Pattern_2-Абстрактная фабрика(Abstract Factory)/Program.cs @@ -0,0 +1,129 @@ +/* + * ПОРОЖДАЮЩИЕ ПАТТЕРНЫ + * + * Глава_9: Абстрактная фабрика (Abstract Factory) + * + * - скрыть сложную логику инициализации + * - упростить поддержку функционала и его дополнение + * (крайне рекдо используется) + */ + +using BenchmarkDotNet.Attributes; + +/// +/// Фабрика +/// +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(); + } +} + +/// +/// Абстрактная фабрика +/// +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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_2-Фасад(Facade)/Pattern_2-Фасад(Facade).csproj b/Patterns/Pattern_2-Фасад(Facade)/Pattern_2-Фасад(Facade).csproj new file mode 100644 index 0000000..9485da3 --- /dev/null +++ b/Patterns/Pattern_2-Фасад(Facade)/Pattern_2-Фасад(Facade).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_2_Фасад_Facade_ + enable + enable + + + diff --git a/Patterns/Pattern_2-Фасад(Facade)/Program.cs b/Patterns/Pattern_2-Фасад(Facade)/Program.cs new file mode 100644 index 0000000..eaac645 --- /dev/null +++ b/Patterns/Pattern_2-Фасад(Facade)/Program.cs @@ -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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_2-Шаблонный метод/ExceptionLogEntry.cs b/Patterns/Pattern_2-Шаблонный метод/ExceptionLogEntry.cs new file mode 100644 index 0000000..53ec1f3 --- /dev/null +++ b/Patterns/Pattern_2-Шаблонный метод/ExceptionLogEntry.cs @@ -0,0 +1,6 @@ +namespace Creational; + +public struct ExceptionLogEntry +{ + public string Message { get; set; } +} diff --git a/Patterns/Pattern_2-Шаблонный метод/Pattern_3-Фабричный метод.csproj b/Patterns/Pattern_2-Шаблонный метод/Pattern_3-Фабричный метод.csproj new file mode 100644 index 0000000..af22a2e --- /dev/null +++ b/Patterns/Pattern_2-Шаблонный метод/Pattern_3-Фабричный метод.csproj @@ -0,0 +1,19 @@ + + + + Exe + net6.0 + Pattern_2_Шаблонный_метод + enable + enable + + + + + + + + + + + diff --git a/Patterns/Pattern_2-Шаблонный метод/Program.cs b/Patterns/Pattern_2-Шаблонный метод/Program.cs new file mode 100644 index 0000000..7de8524 --- /dev/null +++ b/Patterns/Pattern_2-Шаблонный метод/Program.cs @@ -0,0 +1,227 @@ +/* + * ПАТТЕРНЫ ПОВЕДЕНИЯ + * + * Глава_2 и 10: Фабричный метод(виртуальный конструктор) и Шаблонный метод (Паттерн поведения) + * + * — это каркас, в который наследники могут + * подставить реализации недостающих элементов. + * + * - позволяет более четко определить «контракт» между базовым классом и потомками + */ + +using Behavioral; +using Creational; +using System.ServiceModel; +using System.Text; + +/* + * Теперь все реализации читателей логов будут вынуждены следовать согласованному протоколу + */ +public abstract class LogReader +{ + private int _currentPosition; + + /// + /// Определяет алгоритм импорта + /// + /// + public IEnumerable ReadLogEntry() + { + return ReadEntries(ref _currentPosition).Select(ParseLogEntry); + } + + protected abstract IEnumerable ReadEntries(ref int position); + + protected abstract LogEntry ParseLogEntry(string stringEntry); +} + +/* + * 2.1: Локальный шаблонный метод на основе делегатов + * + * ! является более контекстно зависимой операцией + * + * Использование наследования является слишком тяжеловесным решением, + * поэтому в таких случаях применяется подход, при котором переменный шаг алгоритма задается делегатом + */ + +/// +/// Поведение сервиса сохранения записей +/// +interface ILogSaver +{ + void UploadLogEntries(IEnumerablelogEntries); + void UploadExceptions(IEnumerable exceptions); +} + +/// +/// Прокси - класс инкапсулирует особенности работы +/// с WCF - инфраструктурой +/// +class LogSaverProxy : ILogSaver +{ + /// + /// Подключение к службе + /// + class LogSaverClient : ClientBase + { + public ILogSaver LogSaver + { + get { return Channel; } + } + } + + public void UploadExceptions(IEnumerable exceptions) + { + UseProxyClient(c => c.UploadExceptions(exceptions)); + } + + public void UploadLogEntries(IEnumerable logEntries) + { + UseProxyClient(c => c.UploadLogEntries(logEntries)); + } + + private void UseProxyClient(Action 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; } + + /// + /// ExceptionLogEntry - будет возвращать информацию об исключении + /// + 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(); + } +} + +/// +/// Абстракция для взаимодействия с фабриками +/// +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); + } +} + +/// +/// Конкретная фабрика +/// +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); + } +} + +/// +/// Абстракция для взаимодействия с продуктами +/// +public abstract class Product +{ + public abstract void GetText(); +} + +/// +/// Конкретный продукт +/// +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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_3-Декоратор(Decorator)/Pattern_3-Декоратор(Decorator).csproj b/Patterns/Pattern_3-Декоратор(Decorator)/Pattern_3-Декоратор(Decorator).csproj new file mode 100644 index 0000000..64bff80 --- /dev/null +++ b/Patterns/Pattern_3-Декоратор(Decorator)/Pattern_3-Декоратор(Decorator).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_3_Декоратор_Decorator_ + enable + enable + + + diff --git a/Patterns/Pattern_3-Декоратор(Decorator)/Program.cs b/Patterns/Pattern_3-Декоратор(Decorator)/Program.cs new file mode 100644 index 0000000..9b5c94d --- /dev/null +++ b/Patterns/Pattern_3-Декоратор(Decorator)/Program.cs @@ -0,0 +1,144 @@ +/* + * СТРУКТУРНЫЕ ПАТТЕРНЫ + * + * Глава_14: Декоратор (Decorator) + * + * - динамически добавляет объекту новые обязанности. Является гибкой + * альтернативой порождению подклассов с целью расширения функциональности + */ + +/// +/// Пример №1 +/// +public sealed class Car +{ + public string Model { get; set; } + public Car(string model, IEnumerable options) + { + + } + public List 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 options) + { + baseCar = new Car(model, options); + } + public List 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()} +++"; + } +} + +/// +/// Пример №2 (Динамический декоратор) +/// +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 =>"; +} + +/// +/// Пример №3 (статический декоратор - используем обобщение) +/// +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 : 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 : 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(); + Console.WriteLine(chickenOlivesPizza.MakePizza()); + #endregion + } +} \ No newline at end of file diff --git a/Patterns/Pattern_3-Посредник(Mediator)/Pattern_3-Посредник(Mediator).csproj b/Patterns/Pattern_3-Посредник(Mediator)/Pattern_3-Посредник(Mediator).csproj new file mode 100644 index 0000000..e7d62a6 --- /dev/null +++ b/Patterns/Pattern_3-Посредник(Mediator)/Pattern_3-Посредник(Mediator).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_3_Посредник_Mediator_ + enable + enable + + + diff --git a/Patterns/Pattern_3-Посредник(Mediator)/Program.cs b/Patterns/Pattern_3-Посредник(Mediator)/Program.cs new file mode 100644 index 0000000..c40907b --- /dev/null +++ b/Patterns/Pattern_3-Посредник(Mediator)/Program.cs @@ -0,0 +1,123 @@ +/* + * ПАТТЕРНЫ ПОВЕДЕНИЯ + * + * Глава_3: Фабричный метод(виртуальный конструктор) + * + * - определяет объект, инкапсулирующий способ взаимодействия множества объектов. + * - это клей, связывающий несколько независимых классов между собой. + * Он избавляет классы от необходимости ссылаться друг на друга, + * позволяя тем самым их независимо изменять и анализировать + */ + +/// +/// Посредники +/// Предоставляет интерфейс для организации +/// процесса по обмену информацией между объектами типа Colleague. +/// +abstract class Mediator +{ + public abstract void Send(string message, Colleague colleague); +} + +/// +/// Конкретный посредник +/// Реализует алгоритм взаимодействия между объектами-коллегами +/// +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); + } + } +} + +/// +/// Коллеги +/// Предоставляет интерфейс для организации процесса +/// взаимодействия объектов-коллег с объектом типа Mediator. +/// +abstract class Colleague +{ + protected Mediator mediator; + + public Colleague(Mediator mediator) + { + this.mediator = mediator; //передаем ссылку на абстрактный класс посредника + } +} + +/// +/// Фермер +/// Каждый объект-коллега знает только об объекте-медиаторе. +/// Все объекты-коллеги обмениваются информацией +/// только через посредника (медиатора). +/// +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); + } +} + +/// +/// Завод +/// +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); + } +} + +/// +/// Магазин +/// +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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_3-Строитель(Builder)/Pattern_4-Строитель(Builder).csproj b/Patterns/Pattern_3-Строитель(Builder)/Pattern_4-Строитель(Builder).csproj new file mode 100644 index 0000000..ad7f9d7 --- /dev/null +++ b/Patterns/Pattern_3-Строитель(Builder)/Pattern_4-Строитель(Builder).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_3_Строитель_Builder_ + enable + enable + + + diff --git a/Patterns/Pattern_3-Строитель(Builder)/Program.cs b/Patterns/Pattern_3-Строитель(Builder)/Program.cs new file mode 100644 index 0000000..9c33aa8 --- /dev/null +++ b/Patterns/Pattern_3-Строитель(Builder)/Program.cs @@ -0,0 +1,170 @@ +/* + * ПОРОЖДАЮЩИЕ ПАТТЕРНЫ + * + * Глава_11: Строитель (Builder) + * + * - строитель отделяет конструирование сложного объекта + * от его представления, так что в результате одного и того же + * процесса конструирования могут получаться разные представления. + */ + +/// +/// Шаблон адреса +/// +class Address +{ + public string Street { get; set; } + public string House { get; set; } + + public Address(string street, string house) + { + Street = street; + House = house; + } +} + +/// +/// Представление с точки зрения паттерна +/// +class AddressElement +{ + public string Title { get; set; } + public string Value { get; set; } + private List 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(); + Title = title; + Value = value; + } + + private string Print(string indent = "") => ""; + public override string ToString() => ""; +} + +/// +/// Конструирует корневую главную ячейку +/// +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(); +} + +/// +/// Классическое представление паттерна +/// +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); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_4-Итератор(Iterator)/Pattern_4-Итератор(Iterator).csproj b/Patterns/Pattern_4-Итератор(Iterator)/Pattern_4-Итератор(Iterator).csproj new file mode 100644 index 0000000..f70d666 --- /dev/null +++ b/Patterns/Pattern_4-Итератор(Iterator)/Pattern_4-Итератор(Iterator).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_4_Итератор_Iterator_ + enable + enable + + + diff --git a/Patterns/Pattern_4-Итератор(Iterator)/Program.cs b/Patterns/Pattern_4-Итератор(Iterator)/Program.cs new file mode 100644 index 0000000..b4dbfed --- /dev/null +++ b/Patterns/Pattern_4-Итератор(Iterator)/Program.cs @@ -0,0 +1,333 @@ +/* + * ПАТТЕРНЫ ПОВЕДЕНИЯ + * + * Глава_4: Итератор + * + * - представляет доступ ко всем элементам составного объекта, не раскрывая его внутреннего представления + */ + +/* + * пример техники "перечисляемый-перечислитель" + */ + +interface IEnumerable +{ + IEnumerator GetEnumenator(); +} + +class Bank : IEnumerable +{ + List bankVault = new List() + { + 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 +{ + 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 : IEnumerable// IEnumerator, +{ + //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 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 +{ + 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 + { + ["Proteins"] = Proteins, + ["Fats"] = Fats, + ["Carbohydrates"] = Carbohydrates + }; + } + + //допы + readonly Dictionary 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 GetEnumerator() => nutrients.Values.GetEnumerator(); + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); +} + +class Menu : IEnumerable +{ + public Dish Pizza { get; init; } + public Dish Coffee { get; init; } + public Dish Soup { get; init; } + + public IEnumerator GetEnumerator() + { + //В каком порядке перечислять + yield return Pizza; + yield return Coffee; + yield return Soup; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => (System.Collections.IEnumerator)this; +} + +public class Node +{ + public T Value { get; set; } + public Node Left { get; set; } + public Node Right { get; set; } + public Node Parent { get; set; } + public Node (T value) => Value = value; + public Node (T value, Node left = null, Node 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 +{ + public Node Current { get; set; } + private readonly Node root; + private bool detourStarted; + //принимает корневой элемент с которого начнёт обход + public InOrderIterator(Node 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 set = new (array); + set.Reset(); + while(set.MoveNext) + Console.WriteLine($"set: {set.Current}"); + + //Вторая реализация паттерна + SimleSetYeild 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(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(three); + while (rlr.MoveNext()) Console.WriteLine($"{rlr.Current}"); + Console.WriteLine(); + rlr.Reset(); + while (rlr.MoveNext()) Console.WriteLine($"{rlr.Current}"); + } +} + diff --git a/Patterns/Pattern_4-Компоновщик(Composite)/Pattern_4-Компоновщик(Composite).csproj b/Patterns/Pattern_4-Компоновщик(Composite)/Pattern_4-Компоновщик(Composite).csproj new file mode 100644 index 0000000..1a7e933 --- /dev/null +++ b/Patterns/Pattern_4-Компоновщик(Composite)/Pattern_4-Компоновщик(Composite).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_4_Компоновщик_Composite_ + enable + enable + + + diff --git a/Patterns/Pattern_4-Компоновщик(Composite)/Program.cs b/Patterns/Pattern_4-Компоновщик(Composite)/Program.cs new file mode 100644 index 0000000..41c3e2f --- /dev/null +++ b/Patterns/Pattern_4-Компоновщик(Composite)/Program.cs @@ -0,0 +1,166 @@ +/* + * СТРУКТУРНЫЕ ПАТТЕРНЫ + * + * Глава_15: Компоновщик (Composite) + * + * - компонует объекты в древовидные структуры для представления + * иерархий «часть — целое». Позволяет клиентам единообразно + * трактовать индивидуальные и составные объекты + */ + +class UIElement +{ + public UIElement(string name) + { + Children = new List(); + } + public List 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) { } +} + +/// +/// Пример отправки писем группе адресатов +/// +interface IEMail +{ + void Send(); + string Name { get; set; } +} + +class Group : IEMail +{ + public Group(params IEMail[] es) => Append(es); + + public List 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}"); +} + +/// +/// Генератор файловой системы +/// +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 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 + } +} \ No newline at end of file diff --git a/Patterns/Pattern_5-Заместитель(Proxy)/Pattern_5-Заместитель(Proxy).csproj b/Patterns/Pattern_5-Заместитель(Proxy)/Pattern_5-Заместитель(Proxy).csproj new file mode 100644 index 0000000..b18ae9c --- /dev/null +++ b/Patterns/Pattern_5-Заместитель(Proxy)/Pattern_5-Заместитель(Proxy).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_5_Заместитель_Proxy_ + enable + enable + + + diff --git a/Patterns/Pattern_5-Заместитель(Proxy)/Program.cs b/Patterns/Pattern_5-Заместитель(Proxy)/Program.cs new file mode 100644 index 0000000..9d32744 --- /dev/null +++ b/Patterns/Pattern_5-Заместитель(Proxy)/Program.cs @@ -0,0 +1,130 @@ +/* + * СТРУКТУРНЫЕ ПАТТЕРНЫ + * + * Глава_16: Заместитель (Proxy) + * + * - является суррогатом другого объекта и контролирует доступ к нему. + */ + +/// +/// Абстрактная сущность о беге +/// +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(); + } +} + +/// +/// Proxy сервер +/// +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; + 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() { }); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_5-Наблюдатель(Observer)/Pattern_5-Наблюдатель(Observer).csproj b/Patterns/Pattern_5-Наблюдатель(Observer)/Pattern_5-Наблюдатель(Observer).csproj new file mode 100644 index 0000000..a33ee58 --- /dev/null +++ b/Patterns/Pattern_5-Наблюдатель(Observer)/Pattern_5-Наблюдатель(Observer).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_5_Наблюдатель_Observer_ + enable + enable + + + diff --git a/Patterns/Pattern_5-Наблюдатель(Observer)/Program.cs b/Patterns/Pattern_5-Наблюдатель(Observer)/Program.cs new file mode 100644 index 0000000..18f348b --- /dev/null +++ b/Patterns/Pattern_5-Наблюдатель(Observer)/Program.cs @@ -0,0 +1,328 @@ +using System.Collections; +/* + * ПАТТЕРНЫ ПОВЕДЕНИЯ + * + * Глава_5: Наблюдатель + * + * - определяет зависимость типа «один ко многим»» (один издатель ко многим подписчикам) между объектами + * таким образом, что при изменении состояния одного объекта все зависящие от него + * оповещаются об этом и автоматически обновляются + * + * -описывает правильные способы организации процесса подписки на определенные события + */ + +/* + * Модель вытягивания (Pull model) + */ +/// +/// Обозреватели газеты +/// +abstract class Observer +{ + public abstract void Update(); +} + +/// +/// Издатели газеты +/// +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(); + } +} + +/// +/// Конкретный издатель(издатель газеты) (наблюдаемый) +/// +class ConcreteSubject + : Subject +{ + public string State { get; set; } +} + +/// +/// Конкретный обозреватель (наблюдатель) +/// +class ConcreteObserver + : Observer +{ + string observerState; + ConcreteSubject subject; + + public ConcreteObserver(ConcreteSubject subject) + { + this.subject = subject; + } + + public override void Update() + { + observerState = subject.State; + } +} + +/* + * Модель проталкивания (Push model) + */ +/// +/// Обозреватели газеты +/// +abstract class Observer_Push +{ + public abstract void Update(string state); // получает уведомление о новостях +} + +/// +/// Издатели газеты +/// +abstract class Subject_Push +{ + ArrayList observers = new ArrayList(); + + public abstract string State { get; set; } + + /// + /// Добавить новость в газету + /// + /// обозреватель газеты + public void Attach(Observer_Push observer) + { + observers.Add(observer); + } + + /// + /// Удалить новость из газеты + /// + /// обозреватель газеты + public void Detach(Observer_Push observer) + { + observers.Remove(observer); + } + + public void Notify() + { + foreach (Observer_Push observer in observers) + observer.Update(State); + } +} + +/// +/// Конкретный издатель(издатель газеты) +/// +class ConcreteSubject_Push + : Subject_Push +{ + public override string State { get; set; } +} + +/// +/// Конкретный обозреватель +/// +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; + } +} + +/// +/// Пример №2 +/// +class Event { } +class LoggerEvent : Event { } +class AlertEvent : Event { } + +/// +/// Класс, за которым можно наблюдать +/// получая оповещения о происходящих в нем событиях +/// +class TicTokUser : IObservable +{ + public List Subscriptions { get; init; } + + public TicTokUser() => Subscriptions = new List(); + + 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 observer) + { + var sub = new Subscription(this, observer); + Subscriptions.Add(sub); + return sub; + } +} + +class Subscription : IDisposable +{ + private TicTokUser user; + public IObserver observer; + public Subscription(TicTokUser user, IObserver observer) + { + this.user = user; + this.observer = observer; + } + + /// + /// Удаление наблюдаемого класса из перечня подписавшихся + /// + public void Dispose() => user.Subscriptions.Remove(this); +} + +/// +/// Конкретный подписчик +/// +class Observers : IObserver +{ + public Observers() + { + var user = new TicTokUser(); + var sub = user.Subscribe(this); + user.Alert(); + user.Alert(); + sub.Dispose(); + user.Alert(); + } + + /// + /// Наблюдение окончено - больше ничего + /// происходить не будет + /// + public void OnCompleted() { } + + /// + /// Обработка ошибки, явное оповещение + /// + /// + public void OnError(Exception error) { } + + /// + /// Событие при получении данных + /// + /// + 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"); + } +} + +/// +/// Логика социальной сети (делегаты) +/// +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 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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_5-Наблюдатель(Observer)/SimpleObserver.cs b/Patterns/Pattern_5-Наблюдатель(Observer)/SimpleObserver.cs new file mode 100644 index 0000000..2b77e73 --- /dev/null +++ b/Patterns/Pattern_5-Наблюдатель(Observer)/SimpleObserver.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using static System.Console; + +namespace Pattern_5_Наблюдатель_Observer_ +{ + +} diff --git a/Patterns/Pattern_6-Посетитель(Visitor)/Pattern_6-Посетитель(Visitor).csproj b/Patterns/Pattern_6-Посетитель(Visitor)/Pattern_6-Посетитель(Visitor).csproj new file mode 100644 index 0000000..2c5a5e3 --- /dev/null +++ b/Patterns/Pattern_6-Посетитель(Visitor)/Pattern_6-Посетитель(Visitor).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_6_Посетитель_Visitor_ + enable + enable + + + diff --git a/Patterns/Pattern_6-Посетитель(Visitor)/Program.cs b/Patterns/Pattern_6-Посетитель(Visitor)/Program.cs new file mode 100644 index 0000000..124d622 --- /dev/null +++ b/Patterns/Pattern_6-Посетитель(Visitor)/Program.cs @@ -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); +} + +/// +/// Реализация Visitor №1 +/// +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"); +} + +/// +/// Visitor для птички Киви +/// +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); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_7-Команда/Pattern_7-Команда(Command).csproj b/Patterns/Pattern_7-Команда/Pattern_7-Команда(Command).csproj new file mode 100644 index 0000000..9b43bfd --- /dev/null +++ b/Patterns/Pattern_7-Команда/Pattern_7-Команда(Command).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_7_Команда + enable + enable + + + diff --git a/Patterns/Pattern_7-Команда/Program.cs b/Patterns/Pattern_7-Команда/Program.cs new file mode 100644 index 0000000..99ed85a --- /dev/null +++ b/Patterns/Pattern_7-Команда/Program.cs @@ -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}"); + } +} + +/// +/// Проверить факт выполнения операции +/// IOperation - единственный ответственный за действие +/// +interface IOperation +{ + void Execute(); + public bool IsComplete { get; } +} + +/// +/// Шаблон команды пополнения кошелька +/// +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; + } + + /// + /// Обработка выполения команды + /// + public void Execute() + { + accaunt.Balance += money; + isComplete = true; + } +} + +/// +/// Команда снятия с кошелька +/// +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; + } + + /// + /// Обработка выполения команды + /// + public void Execute() + { + if (accaunt.Balance - money < 0) return; + accaunt.Balance -= money; + isComplete = true; + } +} + +/// +/// коллекция команд +/// +class Operations : Collection { } + +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(); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_8-Состояние/Pattern_8-Состояние(State).csproj b/Patterns/Pattern_8-Состояние/Pattern_8-Состояние(State).csproj new file mode 100644 index 0000000..11c709b --- /dev/null +++ b/Patterns/Pattern_8-Состояние/Pattern_8-Состояние(State).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_8_Состояние + enable + enable + + + diff --git a/Patterns/Pattern_8-Состояние/Program.cs b/Patterns/Pattern_8-Состояние/Program.cs new file mode 100644 index 0000000..042ef2b --- /dev/null +++ b/Patterns/Pattern_8-Состояние/Program.cs @@ -0,0 +1,165 @@ +/* + * ПАТТЕРНЫ ПОВЕДЕНИЯ + * + * Глава_7_2: Состояние + * + * - позволяет объекту поменять свое поведение в зависимости от состояния + */ + +/// +/// Объектное представление логического состояния +/// +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"; +} + +/// +/// пример из реалной жизни +/// +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("Камера уже в режиме фото"); + + /// + /// Выключить камеру + /// + /// камера + 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); + } + + /// + /// Выключить камеру + /// + /// камера + 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); + } + + /// + /// Выключить камеру + /// + /// камера + 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); + } +} \ No newline at end of file diff --git a/Patterns/Pattern_9-Цепочка обязанностей/Pattern_9-Цепочка обязанностей(ChainOfResponsobility).csproj b/Patterns/Pattern_9-Цепочка обязанностей/Pattern_9-Цепочка обязанностей(ChainOfResponsobility).csproj new file mode 100644 index 0000000..4dd3c98 --- /dev/null +++ b/Patterns/Pattern_9-Цепочка обязанностей/Pattern_9-Цепочка обязанностей(ChainOfResponsobility).csproj @@ -0,0 +1,11 @@ + + + + Exe + net6.0 + Pattern_9_Цепочка_обязанностей + enable + enable + + + diff --git a/Patterns/Pattern_9-Цепочка обязанностей/Program.cs b/Patterns/Pattern_9-Цепочка обязанностей/Program.cs new file mode 100644 index 0000000..efdac8c --- /dev/null +++ b/Patterns/Pattern_9-Цепочка обязанностей/Program.cs @@ -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) { } +} + + +/// +/// Пример №2 +/// +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; + } + + /// + /// Выполнение действия + /// + 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; + } +} + +/// +/// К какому игровому персонажу какой эффект нужно применить +/// * Самый сложный пример - с брокером событий +/// +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; } +} + +/// +/// Брокер который отвечает за эффекты применяемые к персонажу +/// +public class Game +{ + public event EventHandler Queries; + public void CallQuery(object s, Query q) => Queries?.Invoke(s, q); +} + +/// +/// В какой игре к какому персонажу применить какую характеристику +/// +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); + } +} \ No newline at end of file diff --git a/Patterns/PatternsExtra.sln b/Patterns/PatternsExtra.sln new file mode 100644 index 0000000..2c9025c --- /dev/null +++ b/Patterns/PatternsExtra.sln @@ -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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea92c36 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +

+

+ Typing SVG +

+

+ Static Badge + +

+

+ +# C# паттерны - дополнение 📚 + +**Создано в качестве дополнения к 🌟 [моему существующему репозиторию](https://github.com/Dvurechensky/Patterns-Programming)** 🌟 + +Содержит: **паттерны** и [примеры создания сниппетов](Patterns/Pattern_1-Синглтон(Singleton)/MySnippet.snippet) + +Данная информация по C# проработанна мной с плейлиста грамотного человека 👊 [Сергея Камянецкого](https://www.youtube.com/playlist?list=PLsV7KW4r_oBAxqpJ0IyfJw16GBZXJvLKg) 👊 \ No newline at end of file