├── .gitignore ├── README.md ├── Src ├── TheDesignPatterns.sln └── TheDesignPatterns │ ├── Adapter │ ├── Adapter.cs │ ├── Adapter.png │ ├── AdapterTest.cs │ └── ReadMe.txt │ ├── Bridge │ ├── Bridge.cs │ ├── Bridge.png │ ├── BridgeTest.cs │ └── ReadMe.txt │ ├── Builder │ ├── Builder.cs │ ├── Builder.png │ ├── BuilderTest.cs │ └── ReadMe.txt │ ├── ChainOfResponsibility │ ├── ChainOfResponsibility.cs │ ├── ChainOfResponsibilityTest.cs │ ├── ChainofResponsibility.png │ └── ReadMe.txt │ ├── Composite │ ├── Composit.cs │ ├── Composit.png │ ├── CompositTest.cs │ └── ReadMe.txt │ ├── Decorator │ ├── Decorator.cs │ ├── Decorator.png │ ├── DecoratorTest.cs │ └── ReadMe.txt │ ├── Facade │ ├── Facade.cs │ ├── Facade.png │ ├── FacadeTest.cs │ └── ReadMe.txt │ ├── Factory │ ├── AbstractFactory │ │ ├── AbstractFact.png │ │ ├── AbstractFactory.cs │ │ ├── AbstractFactoryTest.cs │ │ └── ReadMe.txt │ └── FactoryMethod │ │ ├── FactMethod.png │ │ ├── FactoryMethod.cs │ │ ├── FactoryMethodTest.cs │ │ └── ReadMe.txt │ ├── Mediator │ ├── Mediator.cs │ ├── Mediator.jpg │ ├── MediatorTest.cs │ ├── Mediator_Usecase_Family.png │ └── ReadMe.txt │ ├── NullObject │ ├── NullObject.cs │ ├── NullObject.png │ ├── NullObjectTest.cs │ └── ReadMe.txt │ ├── Observer │ ├── Observer.cs │ ├── Observer.png │ ├── ObserverTest.cs │ └── ReadMe.txt │ ├── Proxy │ ├── Proxy.cs │ ├── Proxy.png │ ├── ProxyTest.cs │ └── ReadMe.txt │ ├── PublisherSubScriber │ ├── PublisherSubscriber.cs │ ├── PublisherSubscriber.png │ ├── PublisherSubscriberTest.cs │ └── ReadMe.txt │ ├── Repository │ ├── ReadMe.txt │ ├── Repository.cs │ ├── Repository.jpg │ └── RepositoryTest.cs │ ├── Singleton │ ├── ReadMe.txt │ ├── Singleton.cs │ ├── Singleton.jpg │ └── SingletonTest.cs │ ├── Specification │ ├── ReadMe.txt │ ├── Specification.cs │ ├── Specification.png │ └── SpecificationTest.cs │ ├── State │ ├── ReadMe.txt │ ├── State.cs │ ├── State.png │ └── StateTest.cs │ ├── Strategy │ ├── CouponCodes.cs │ ├── DiscountStartegyTests.cs │ ├── DiscountStrategyProvider.cs │ ├── FlatRateDiscountStratigy.cs │ ├── IDiscountStrategy.cs │ ├── IDiscountStrategyProvider.cs │ ├── PercentageDiscountStrategy.cs │ ├── PercentageLimitDiscountStrategy.cs │ ├── ReadMe.txt │ ├── Strategy.jpg │ └── Usecase_Football.png │ ├── TemplateMethod │ ├── ReadMe.txt │ ├── TemplateMethod.cs │ ├── TemplateMethod.png │ └── TemplateMethodTest.cs │ └── TheDesignPatterns.csproj └── docs ├── dpc.jpg └── dpt.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | *.cache 25 | # Visual Studio 2015 cache/options directory 26 | src/.vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | *.cache 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # NCrunch 115 | _NCrunch_* 116 | .*crunch*.local.xml 117 | nCrunchTemp_* 118 | 119 | # MightyMoose 120 | *.mm.* 121 | AutoTest.Net/ 122 | 123 | # Web workbench (sass) 124 | .sass-cache/ 125 | 126 | # Installshield output folder 127 | [Ee]xpress/ 128 | 129 | # DocProject is a documentation generator add-in 130 | DocProject/buildhelp/ 131 | DocProject/Help/*.HxT 132 | DocProject/Help/*.HxC 133 | DocProject/Help/*.hhc 134 | DocProject/Help/*.hhk 135 | DocProject/Help/*.hhp 136 | DocProject/Help/Html2 137 | DocProject/Help/html 138 | 139 | # Click-Once directory 140 | publish/ 141 | 142 | # Publish Web Output 143 | *.[Pp]ublish.xml 144 | *.azurePubxml 145 | # TODO: Comment the next line if you want to checkin your web deploy settings 146 | # but database connection strings (with potential passwords) will be unencrypted 147 | #*.pubxml 148 | *.publishproj 149 | 150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 151 | # checkin your Azure Web App publish settings, but sensitive information contained 152 | # in these scripts will be unencrypted 153 | PublishScripts/ 154 | 155 | # NuGet Packages 156 | *.nupkg 157 | # The packages folder can be ignored because of Package Restore 158 | **/packages/* 159 | # except build/, which is used as an MSBuild target. 160 | !**/packages/build/ 161 | # Uncomment if necessary however generally it will be regenerated when needed 162 | #!**/packages/repositories.config 163 | # NuGet v3's project.json files produces more ignoreable files 164 | *.nuget.props 165 | *.nuget.targets 166 | 167 | # Microsoft Azure Build Output 168 | csx/ 169 | *.build.csdef 170 | 171 | # Microsoft Azure Emulator 172 | ecf/ 173 | rcf/ 174 | 175 | # Windows Store app package directories and files 176 | AppPackages/ 177 | BundleArtifacts/ 178 | Package.StoreAssociation.xml 179 | _pkginfo.txt 180 | 181 | # Visual Studio cache files 182 | # files ending in .cache can be ignored 183 | *.[Cc]ache 184 | # but keep track of directories ending in .cache 185 | !*.[Cc]ache/ 186 | 187 | # Others 188 | ClientBin/ 189 | ~$* 190 | *~ 191 | *.dbmdl 192 | *.dbproj.schemaview 193 | *.jfm 194 | *.pfx 195 | *.publishsettings 196 | node_modules/ 197 | orleans.codegen.cs 198 | 199 | # Since there are multiple workflows, uncomment next line to ignore bower_components 200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 201 | #bower_components/ 202 | 203 | # RIA/Silverlight projects 204 | Generated_Code/ 205 | 206 | # Backup & report files from converting an old project file 207 | # to a newer Visual Studio version. Backup files are not needed, 208 | # because we have git ;-) 209 | _UpgradeReport_Files/ 210 | Backup*/ 211 | UpgradeLog*.XML 212 | UpgradeLog*.htm 213 | 214 | # SQL Server files 215 | *.mdf 216 | *.ldf 217 | 218 | # Business Intelligence projects 219 | *.rdl.data 220 | *.bim.layout 221 | *.bim_*.settings 222 | 223 | # Microsoft Fakes 224 | FakesAssemblies/ 225 | 226 | # GhostDoc plugin setting file 227 | *.GhostDoc.xml 228 | 229 | # Node.js Tools for Visual Studio 230 | .ntvs_analysis.dat 231 | 232 | # Visual Studio 6 build log 233 | *.plg 234 | 235 | # Visual Studio 6 workspace options file 236 | *.opt 237 | 238 | # Visual Studio LightSwitch build output 239 | **/*.HTMLClient/GeneratedArtifacts 240 | **/*.DesktopClient/GeneratedArtifacts 241 | **/*.DesktopClient/ModelManifest.xml 242 | **/*.Server/GeneratedArtifacts 243 | **/*.Server/ModelManifest.xml 244 | _Pvt_Extensions 245 | 246 | # Paket dependency manager 247 | .paket/paket.exe 248 | paket-files/ 249 | 250 | # FAKE - F# Make 251 | .fake/ 252 | 253 | # JetBrains Rider 254 | .idea/ 255 | *.sln.iml 256 | 257 | # CodeRush 258 | .cr/ 259 | 260 | # Python Tools for Visual Studio (PTVS) 261 | __pycache__/ 262 | *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TheDesignPatterns 2 | 3 | Design pattern is a documented best practice of a solution that has been applied 4 | successfully to solve a problem that recurs a specific set of situations. 5 | In a short we can say recuring solution to a common problem in a given context. 6 | 7 | #### GOF devide design patterns in 3 types: 8 | 9 | ![Types](https://github.com/habibsql/TheDesignPatterns/blob/master/docs/dpt.jpg?raw=true) 10 | 11 | * **Creational Design Pattern**: The patterns which are responsible for creating objects. Ex: Factory, Builder, Singleton etc. 12 | * **Structural Design Pattern**: The patterns which are responsible for assembles objects. 13 | and classes to create better strucutre for efficiency and flexibilities. Ex: Adapter, Bridge, Facade etc. 14 | * **Behaviour Design Pattern**: The patters which are assign responsiblities between objects. Ex: State, 15 | ChainOfResponsibility, TemplateMethod etc. 16 | 17 | 18 | ![Category](https://github.com/habibsql/TheDesignPatterns/blob/master/docs/dpc.jpg?raw=true) 19 | 20 | **I demonastrate few important design patterns that can be use in real life application/api development**... 21 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29613.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheDesignPatterns", "TheDesignPatterns\TheDesignPatterns.csproj", "{576A56B1-3F24-4911-BEC4-27A0D128B704}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {576A56B1-3F24-4911-BEC4-27A0D128B704}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {576A56B1-3F24-4911-BEC4-27A0D128B704}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {576A56B1-3F24-4911-BEC4-27A0D128B704}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {576A56B1-3F24-4911-BEC4-27A0D128B704}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C147F55A-3408-40FC-AE51-9F972EA73BF7} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Adapter/Adapter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TheDesignPatterns.Adapter 4 | { 5 | public interface ITarget 6 | { 7 | IEnumerable GetAsianCountryCodeList(); 8 | } 9 | 10 | /// 11 | /// Adapter 12 | /// 13 | public class CountryCodeAdapter : ITarget 14 | { 15 | private readonly IThirdParty country; 16 | 17 | public CountryCodeAdapter(IThirdParty country) 18 | { 19 | this.country = country; 20 | } 21 | 22 | public IEnumerable GetAsianCountryCodeList() 23 | { 24 | var countryCodeList = new List(); 25 | 26 | Dictionary countries = country.GetAsianCountryList(); 27 | 28 | foreach(string countryCode in countries.Keys) 29 | { 30 | countryCodeList.Add(countryCode); 31 | } 32 | 33 | return countryCodeList; 34 | } 35 | } 36 | 37 | public interface IThirdParty 38 | { 39 | public Dictionary GetAsianCountryList(); 40 | } 41 | 42 | /// 43 | /// Adaptee 44 | /// 45 | public class CountryAdaptee : IThirdParty 46 | { 47 | public Dictionary GetAsianCountryList() 48 | { 49 | var dictionary = new Dictionary(); 50 | 51 | dictionary.Add("bd", "Bangladesh"); 52 | dictionary.Add("in", "India"); 53 | dictionary.Add("pk", "Pakistan"); 54 | 55 | return dictionary; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Adapter/Adapter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Adapter/Adapter.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Adapter/AdapterTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System.Collections.Generic; 3 | using Xunit; 4 | 5 | namespace TheDesignPatterns.Adapter 6 | { 7 | public class AdapterTest 8 | { 9 | [Fact] 10 | public void ShouldWork() 11 | { 12 | IThirdParty thirdParty = new CountryAdaptee(); 13 | ITarget adapter = new CountryCodeAdapter(thirdParty); 14 | IEnumerable countryCodeList = adapter.GetAsianCountryCodeList(); 15 | 16 | countryCodeList.Should().HaveCount(3); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Adapter/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Structural design pattern 6 | 7 | - Another name is wrapper. 8 | 9 | - Matches between incompatable interfaces. Very similar to electrical plug/adapters 10 | 11 | - Client make a request to the adapter and adapter translates that request on the adaptee using the adaptee interface. 12 | 13 | - Actually convert one interface of a class into another interface that clients expect. 14 | 15 | - Adapter can be classified in 2 ways i) Class adapter: Implement based on inheritence. 16 | and ii) Object adapter: Implement based on composition. 17 | 18 | Benifits: 19 | 20 | - Without adapter, 2 different classes can not work together(because of incompatible interface). 21 | 22 | - Provide features that clients actual need. May be same feature or less. 23 | 24 | - Instead of providing entire new interface it provides 2 exising imcompatable class can work together. 25 | 26 | ----------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Bridge/Bridge.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace TheDesignPatterns.Bridge 4 | { 5 | 6 | public interface IBridge 7 | { 8 | void SendNotication(string message); 9 | } 10 | 11 | public class EmailBridge : IBridge 12 | { 13 | private readonly ISendNotification emailNotication; 14 | 15 | public EmailBridge() 16 | { 17 | emailNotication = new EmailNotificaiton(); // IOC container need to use here 18 | } 19 | 20 | public void SendNotication(string message) 21 | { 22 | emailNotication.Send(message); 23 | } 24 | } 25 | 26 | public class SmsBridge : IBridge 27 | { 28 | private readonly ISendNotification smsNotication; 29 | 30 | public SmsBridge() 31 | { 32 | smsNotication = new SmsNotification(); // IOC container need to use here 33 | } 34 | 35 | public void SendNotication(string message) 36 | { 37 | smsNotication.Send(message); 38 | } 39 | } 40 | 41 | public interface ISendNotification 42 | { 43 | void Send(string message); 44 | } 45 | 46 | public class EmailNotificaiton : ISendNotification 47 | { 48 | public object Dubug { get; private set; } 49 | 50 | public void Send(string message) 51 | { 52 | Debug.WriteLine($"Sending Email:{message}"); 53 | } 54 | } 55 | 56 | public class SmsNotification : ISendNotification 57 | { 58 | public void Send(string message) 59 | { 60 | Debug.WriteLine($"Sending Sms:{message}"); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Bridge/Bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Bridge/Bridge.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Bridge/BridgeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | namespace TheDesignPatterns.Bridge 7 | { 8 | public class BridgeTest 9 | { 10 | [Fact] 11 | public void ShouldWork() 12 | { 13 | IBridge bridge = new EmailBridge(); 14 | bridge.SendNotication("Hello! Everyone!"); 15 | 16 | bridge = new SmsBridge(); 17 | bridge.SendNotication("Good Morning!"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Bridge/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Structural design pattern 6 | 7 | - Main goal is to seperate the abstraction from implementation so that they can vary independently. 8 | 9 | - 2 parts 1) Abstraction 2) Implementation. 10 | 11 | - Client code can use only abstraction. 12 | 13 | - State, stratigy, Bridge are similar pattern. 14 | 15 | Befinits: 16 | 17 | - Without clientcode change, possible to change implementation details. 18 | 19 | - Increase loose coupling. 20 | 21 | - Separating low level logic implementation from high level defination. 22 | 23 | ----------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Builder/Builder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TheDesignPatterns.Builder 4 | { 5 | public interface ICarBuilder 6 | { 7 | void BuildWheel(); 8 | 9 | void BuildEngine(); 10 | 11 | void BuildBody(); 12 | 13 | void SetBlackColor(); 14 | 15 | Car GetCar(); 16 | 17 | } 18 | 19 | /// 20 | /// Concreate builder 21 | /// 22 | public class CardBuilder : ICarBuilder 23 | { 24 | private readonly Car car = new Car(); 25 | 26 | public void BuildBody() 27 | { 28 | car.AddPart("Body"); 29 | } 30 | 31 | public void BuildEngine() 32 | { 33 | car.AddPart("Engine"); 34 | } 35 | 36 | public void BuildWheel() 37 | { 38 | car.AddPart("Wheel"); 39 | } 40 | 41 | public void SetBlackColor() 42 | { 43 | car.SetBlackColor(); 44 | } 45 | 46 | public Car GetCar() 47 | { 48 | return car; 49 | } 50 | } 51 | 52 | /// 53 | /// Product that need to build step by step 54 | /// 55 | public class Car 56 | { 57 | private readonly List parts = new List(); 58 | private string color = null; 59 | 60 | public void AddPart(object part) 61 | { 62 | parts.Add(part); 63 | } 64 | 65 | public IEnumerable GetAllParts() 66 | { 67 | return parts; 68 | } 69 | 70 | public void SetBlackColor() 71 | { 72 | color = "Black"; 73 | } 74 | 75 | public string GetColor() 76 | { 77 | return color; 78 | } 79 | 80 | } 81 | 82 | /// 83 | /// Director 84 | /// 85 | public class CardBuildingProcess 86 | { 87 | private readonly ICarBuilder carBuilder; 88 | 89 | public CardBuildingProcess(ICarBuilder carBBuilder) 90 | { 91 | this.carBuilder = carBBuilder; 92 | } 93 | 94 | public Car BuildCar() 95 | { 96 | carBuilder.BuildEngine(); 97 | carBuilder.BuildWheel(); 98 | carBuilder.BuildBody(); 99 | 100 | return carBuilder.GetCar(); 101 | } 102 | 103 | public Car BuildCarWithBlackColor() 104 | { 105 | carBuilder.BuildEngine(); 106 | carBuilder.BuildWheel(); 107 | carBuilder.BuildBody(); 108 | carBuilder.SetBlackColor(); 109 | 110 | return carBuilder.GetCar(); 111 | } 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Builder/Builder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Builder/Builder.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Builder/BuilderTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Builder 5 | { 6 | public class BuilderTest 7 | { 8 | [Fact] 9 | public void ShouldBuildCar() 10 | { 11 | ICarBuilder carBuilder = new CardBuilder(); 12 | var carBuildingProcess = new CardBuildingProcess(carBuilder); 13 | Car car = carBuildingProcess.BuildCar(); 14 | 15 | car.GetAllParts().Should().HaveCount(3); 16 | car.GetColor().Should().BeNull(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Builder/ReadMe.txt: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Creational design pattern. 6 | 7 | - Construct a complex object step by step. 8 | 9 | - Components are Builder, Product, Director 10 | 11 | - Director responsible for only building product sequentially. Control building flows. 12 | 13 | - Product is the altemate object that needs to build step by step. 14 | 15 | - Builder is responsible for building concreate product. 16 | 17 | Benifits: 18 | 19 | - Produce different types/representation of object with same construction code. 20 | 21 | = Increate Readibility 22 | 23 | ----------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/ChainOfResponsibility/ChainOfResponsibility.cs: -------------------------------------------------------------------------------- 1 | namespace TheDesignPatterns.ChainOfResponsibility 2 | { 3 | public class LoanRequest 4 | { 5 | public string NationalId { get; set; } 6 | public bool PreviousRecord { get; set; } 7 | public int LoanAmount { get; set; } 8 | 9 | public bool Approved { get; set; } 10 | 11 | public ILoanAppover ApprovedBy { get; set; } 12 | } 13 | 14 | public class LoanExecutive 15 | { 16 | public LoanRequest RequestForLoanApprove(string nationaId, bool previousRecordGood, int loanAmount) 17 | { 18 | var loanRequest = new LoanRequest 19 | { 20 | NationalId = nationaId, 21 | PreviousRecord = previousRecordGood, 22 | LoanAmount = loanAmount 23 | }; 24 | 25 | ILoanAppover loanAppover = new BranchManagerApprover("Mr. X"); 26 | 27 | loanAppover.Approve(loanRequest); 28 | 29 | return loanRequest; 30 | 31 | } 32 | } 33 | 34 | /// 35 | /// Loan approve responsibility is segrigated by various Managers 36 | /// 37 | public interface ILoanAppover 38 | { 39 | public string GetApproverId(); 40 | void Approve(LoanRequest loanRequest); 41 | } 42 | 43 | /// 44 | /// Limited amount Loan approver 45 | /// 46 | public class BranchManagerApprover : ILoanAppover 47 | { 48 | private const int MaxLoanApproveAmount = 1000; 49 | private readonly ILoanAppover nextLoanApprover = new RegionallManagerApprover("Mr. Y"); 50 | private readonly string managerId = null; 51 | 52 | public BranchManagerApprover(string managerId) 53 | { 54 | this.managerId = managerId; 55 | } 56 | 57 | public void Approve(LoanRequest loanRequest) 58 | { 59 | if (loanRequest.LoanAmount <= MaxLoanApproveAmount) 60 | { 61 | loanRequest.Approved = true; 62 | loanRequest.ApprovedBy = this; 63 | } 64 | 65 | nextLoanApprover.Approve(loanRequest); 66 | } 67 | 68 | public string GetApproverId() 69 | { 70 | return managerId; 71 | } 72 | } 73 | 74 | /// 75 | /// Limited amount Loan approver but higher then Branch Manager 76 | /// 77 | public class RegionallManagerApprover : ILoanAppover 78 | { 79 | private const int MaxLoanApproveAmount = 10000; 80 | private readonly ILoanAppover nextLoanApprover = new DevisionalManagerApprover("Mr. Z"); 81 | private readonly string managerId = null; 82 | 83 | public RegionallManagerApprover(string managerId) 84 | { 85 | this.managerId = managerId; 86 | } 87 | 88 | public void Approve(LoanRequest loanRequest) 89 | { 90 | if (loanRequest.LoanAmount <= MaxLoanApproveAmount) 91 | { 92 | loanRequest.Approved = true; 93 | loanRequest.ApprovedBy = this; 94 | 95 | } 96 | 97 | nextLoanApprover.Approve(loanRequest); 98 | } 99 | public string GetApproverId() 100 | { 101 | return managerId; 102 | } 103 | } 104 | 105 | /// 106 | /// Maximum level loan approver who checks the previous load record of requeter. 107 | /// 108 | public class DevisionalManagerApprover : ILoanAppover 109 | { 110 | private const int MaxLoanApproveAmount = 1000000; 111 | private readonly string managerId = null; 112 | 113 | public DevisionalManagerApprover(string managerId) 114 | { 115 | this.managerId = managerId; 116 | } 117 | public void Approve(LoanRequest loanRequest) 118 | { 119 | if (loanRequest.LoanAmount <= MaxLoanApproveAmount && loanRequest.PreviousRecord) 120 | { 121 | loanRequest.Approved = true; 122 | loanRequest.ApprovedBy = this; 123 | } 124 | } 125 | 126 | public string GetApproverId() 127 | { 128 | return managerId; 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/ChainOfResponsibility/ChainOfResponsibilityTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.ChainOfResponsibility 5 | { 6 | public class ChainOfResponsibilityTest 7 | { 8 | [Fact] 9 | public void ShouldApproveLoadAmount() 10 | { 11 | var loanExecutive = new LoanExecutive(); 12 | 13 | LoanRequest loanRequest1 = loanExecutive.RequestForLoanApprove("123", false, 100); 14 | 15 | LoanRequest loanRequest2 = loanExecutive.RequestForLoanApprove("123", true, 100000); 16 | 17 | loanRequest1.Approved.Should().BeTrue(); 18 | loanRequest1.ApprovedBy.GetApproverId().Should().NotBeNullOrEmpty(); 19 | 20 | loanRequest2.Approved.Should().BeTrue(); 21 | loanRequest2.ApprovedBy.GetApproverId().Should().NotBeNullOrEmpty(); 22 | } 23 | 24 | [Fact] 25 | public void ShouldNotApproveLoadAmount() 26 | { 27 | var loanExecutive = new LoanExecutive(); 28 | 29 | LoanRequest loanRequest1 = loanExecutive.RequestForLoanApprove("123", false, 100000); 30 | 31 | loanRequest1.Approved.Should().BeFalse(); 32 | loanRequest1.ApprovedBy.Should().BeNull(); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/ChainOfResponsibility/ChainofResponsibility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/ChainOfResponsibility/ChainofResponsibility.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/ChainOfResponsibility/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------ 2 | 3 | - Overview: 4 | 5 | - Behavioral Design Pattern 6 | 7 | - Pass a request to a chain of handlers 8 | 9 | - Each handler decide either process it and send it to the next handler or not. 10 | 11 | - Benifits: 12 | 13 | - Follow single responsibility principle. 14 | 15 | - Flexibile code structure 16 | 17 | - Reduce coupling between objects. 18 | 19 | - Increase Request processing with new class convenently 20 | 21 | ------------------------------------------------------------------------------------ -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Composite/Composit.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Text; 4 | 5 | namespace TheDesignPatterns.Composite 6 | { 7 | /// 8 | /// Common interface for File and Folder. It is the component interface of the pattern. 9 | /// 10 | public interface IFileManagement 11 | { 12 | string Name { get; set; } 13 | void Display(); 14 | } 15 | 16 | /// 17 | /// Similar to Directory/Folder object. It is the composit object of the pattern 18 | /// 19 | public class FileDirectory : IFileManagement 20 | { 21 | private IList fileManagementList = new List(); 22 | 23 | public string Name { get; set; } 24 | 25 | public void Add(IFileManagement fileManagement) 26 | { 27 | fileManagementList.Add(fileManagement); 28 | 29 | if (fileManagement is FileContent) 30 | { 31 | var customFile = fileManagement as FileContent; 32 | 33 | customFile.ParentDirectory = this; 34 | } 35 | } 36 | 37 | /// 38 | /// Interface memeber 39 | /// 40 | public void Display() 41 | { 42 | Debug.WriteLine($"+Directory Name={Name}"); 43 | 44 | foreach(IFileManagement fileManagement in fileManagementList) 45 | { 46 | fileManagement.Display(); 47 | } 48 | } 49 | } 50 | 51 | /// 52 | /// Similar to File object. It is the Leaf object of the pattern. 53 | /// 54 | public class FileContent : IFileManagement 55 | { 56 | public FileDirectory ParentDirectory { get; set; } 57 | private StringBuilder contentBuilder = new StringBuilder(); 58 | public string Name { get; set; } 59 | 60 | public void AddContent(string content) 61 | { 62 | contentBuilder.Append(content); 63 | } 64 | 65 | public string GetContent() 66 | { 67 | return contentBuilder.ToString(); 68 | } 69 | 70 | /// 71 | /// Interface memeber 72 | /// 73 | public void Display() 74 | { 75 | Debug.WriteLine($"+File Name={Name}"); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Composite/Composit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Composite/Composit.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Composite/CompositTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace TheDesignPatterns.Composite 4 | { 5 | public class CompositTest 6 | { 7 | [Fact] 8 | public void ShouldDemonastrateCompositDesignPattern() 9 | { 10 | var countryDirectory = new FileDirectory() { Name = "Contries" }; 11 | 12 | var bangladeshFile = new FileContent { Name = "BangladeshFile.txt" }; 13 | bangladeshFile.AddContent("Bangladesh is a best country"); 14 | 15 | var IndiaFile = new FileContent { Name = "India.txt" }; 16 | IndiaFile.AddContent("India is a country"); 17 | 18 | countryDirectory.Add(bangladeshFile); 19 | countryDirectory.Add(IndiaFile); 20 | 21 | countryDirectory.Display(); 22 | 23 | // Please check debug window 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Composite/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------------------- 2 | 3 | - Overview: 4 | 5 | - Structural Design Pattern. 6 | 7 | - Deals with hierarchy of objects and maintain Parent-Child relationship (Part/Whole hierarchy). 8 | 9 | - Goal is compose objects as Tree like data structure. 10 | 11 | - 3 Components are exists here. i) Component: A interface ii) Composit: A children who can 12 | store other children(Node/Leaf) iii) Leaf: A children implement Component 13 | 14 | ---------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Decorator/Decorator.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace TheDesignPatterns.Decorator 4 | { 5 | /// 6 | /// Source class interface 7 | /// 8 | public interface IWriter 9 | { 10 | void Write(string data); 11 | } 12 | 13 | /// 14 | /// Source class which functionality need to extend using Decorators. 15 | /// 16 | public class TextWriter : IWriter 17 | { 18 | private FileInfo fileInfo = new FileInfo("ReportFile.txt"); 19 | 20 | public void Write(string data) 21 | { 22 | byte[] dataBytes = System.Text.UTF8Encoding.UTF8.GetBytes(data); 23 | 24 | using (FileStream fileStream = fileInfo.OpenWrite()) 25 | { 26 | fileStream.Write(dataBytes); 27 | } 28 | } 29 | } 30 | 31 | /// 32 | /// Abstract Decorator class 33 | /// 34 | public abstract class WriterDecorator : IWriter 35 | { 36 | protected readonly IWriter Writer; 37 | protected readonly Transformer Transformer = new Transformer(); 38 | 39 | public WriterDecorator(IWriter writer) 40 | { 41 | this.Writer = writer; 42 | } 43 | 44 | public void Write(string data) 45 | { 46 | Writer.Write(data); 47 | } 48 | } 49 | 50 | /// 51 | /// Concreate Decorator class which extend functionality of original/source class 52 | /// 53 | public class JsonWriterDecorator : WriterDecorator 54 | { 55 | public JsonWriterDecorator(IWriter writer) : base(writer) 56 | { 57 | } 58 | 59 | /// 60 | /// Extended feature 61 | /// 62 | /// 63 | /// 64 | public bool WriteToJson(string data) 65 | { 66 | string json = Transformer.TrasnformJson(data); 67 | 68 | Writer.Write(json); 69 | 70 | return true; 71 | } 72 | } 73 | 74 | 75 | /// 76 | /// Concreat Decorator class which extend functionality of original/source class 77 | /// 78 | public class XmlWriterDecorator : WriterDecorator 79 | { 80 | public XmlWriterDecorator(IWriter writer) : base(writer) 81 | { 82 | } 83 | 84 | /// 85 | /// Extended feature 86 | /// 87 | /// 88 | /// 89 | public bool WriteToXml(string data) 90 | { 91 | string xml = Transformer.TrasnformXml(data); 92 | Writer.Write(xml); 93 | 94 | return true; 95 | } 96 | } 97 | 98 | /// 99 | /// Helper class 100 | /// 101 | public class Transformer 102 | { 103 | public static string TrasnformXml(string data) 104 | { 105 | return $"{data}"; 106 | } 107 | 108 | public static string TrasnformJson(string data) 109 | { 110 | return $@"{"message"}: ""{data}"""; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Decorator/Decorator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Decorator/Decorator.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Decorator/DecoratorTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Decorator 5 | { 6 | public class DecoratorTest 7 | { 8 | [Fact] 9 | public void ShouldWriteToJsonUsingDecorator() 10 | { 11 | string data = "Good Morning"; 12 | IWriter writer = new TextWriter(); 13 | var jsonWriter = new JsonWriterDecorator(writer); 14 | 15 | bool succeed = jsonWriter.WriteToJson(data); 16 | 17 | succeed.Should().BeTrue(); 18 | } 19 | 20 | [Fact] 21 | public void ShouldWriteToXmlUsingDecorator() 22 | { 23 | string data = "Good Morning"; 24 | IWriter writer = new TextWriter(); 25 | var jsonWriter = new XmlWriterDecorator(writer); 26 | 27 | bool succeed = jsonWriter.WriteToXml(data); 28 | 29 | succeed.Should().BeTrue(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Decorator/ReadMe.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - It is a structural design pattern. 6 | 7 | - Wrapping to any class and extend or open to extend its functionality dynamically without change the 8 | original object. 9 | 10 | - Use composition to work with. 11 | 12 | - Very similar to adapter and Proxy design pattern. Adapter provide new interface, 13 | Proxy provide same interface for exising object. Decorator provide 14 | enhanced interface. 15 | 16 | 17 | Benifits: 18 | 19 | - Allow additional functionallities dynamically to an existing object without altering main object. 20 | 21 | - Wihout subclassing we can extend behaviour. 22 | 23 | - Follow SRP (Single Responsibility Principle) 24 | 25 | - Combining several behaviours with wrapping an object into multiple operators. 26 | 27 | - Possible to bind one object with the decorator and wrap their result with another decorator. 28 | 29 | - Allow to follow SRP (Single Responsibility Principle). 30 | 31 | -------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Facade/Facade.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TheDesignPatterns.Facade 4 | { 5 | public interface IHRFacade 6 | { 7 | IEnumerable GetAllEmployees(); 8 | Manager GetManagerById(string id); 9 | IEnumerable GetAllDepartments(); 10 | } 11 | 12 | public class HRFacade : IHRFacade 13 | { 14 | private readonly IEmployeeService employeeService; 15 | private readonly IManagerService managerService; 16 | private readonly IDepartmentService departmentService; 17 | 18 | public HRFacade() 19 | { 20 | employeeService = new EmployeeService(); 21 | managerService = new ManagerService(); 22 | departmentService = new DepartmentService(); 23 | } 24 | 25 | public IEnumerable GetAllDepartments() 26 | { 27 | return departmentService.GetAllDepartments(); 28 | } 29 | 30 | public IEnumerable GetAllEmployees() 31 | { 32 | return employeeService.GetAllEmployees(); 33 | } 34 | 35 | public Manager GetManagerById(string id) 36 | { 37 | return managerService.GetManagerById(id); 38 | } 39 | } 40 | 41 | public interface IEmployeeService 42 | { 43 | public IEnumerable GetAllEmployees(); 44 | } 45 | 46 | public class EmployeeService : IEmployeeService 47 | { 48 | public IEnumerable GetAllEmployees() 49 | { 50 | return new[] 51 | { 52 | new Employee{Id = "E01", Name = "Employee-E01"}, 53 | new Employee{Id = "E02", Name = "Employee-E02"}, 54 | new Employee{Id = "E03", Name = "Employee-E03"}, 55 | }; 56 | } 57 | } 58 | 59 | public interface IManagerService 60 | { 61 | public Manager GetManagerById(string id); 62 | } 63 | 64 | public class ManagerService : IManagerService 65 | { 66 | public Manager GetManagerById(string id) 67 | { 68 | return new Manager 69 | { 70 | Id = id, 71 | Name = $"Manager-{id}", 72 | Age = 45 73 | }; 74 | } 75 | } 76 | 77 | 78 | public interface IDepartmentService 79 | { 80 | public IEnumerable GetAllDepartments(); 81 | } 82 | 83 | public class DepartmentService : IDepartmentService 84 | { 85 | public IEnumerable GetAllDepartments() 86 | { 87 | var managerIT = new Manager 88 | { 89 | Id = "M01", 90 | Name = $"Manager-M01", 91 | Age = 45 92 | }; 93 | var managerFi = new Manager 94 | { 95 | Id = "M02", 96 | Name = $"Manager-M02", 97 | Age = 50 98 | }; 99 | 100 | return new[] 101 | { 102 | new Department{Id = "D01", Name = "IT", Manager = managerIT}, 103 | new Department{Id = "D02", Name = "Finance", Manager = managerFi}, 104 | }; 105 | } 106 | } 107 | 108 | public class Employee 109 | { 110 | public string Id { get; set; } 111 | public string Name { get; set; } 112 | } 113 | 114 | public class Department 115 | { 116 | public string Id { get; set; } 117 | public string Name { get; set; } 118 | 119 | public Manager Manager { get; set; } 120 | } 121 | 122 | public class Manager : Employee 123 | { 124 | public int Age { get; set; } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Facade/Facade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Facade/Facade.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Facade/FacadeTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System.Collections.Generic; 3 | using Xunit; 4 | 5 | namespace TheDesignPatterns.Facade 6 | { 7 | public class FacadeTest 8 | { 9 | private readonly IHRFacade hrFacade = new HRFacade(); 10 | 11 | [Fact] 12 | public void SholdWork() 13 | { 14 | IEnumerable departments = hrFacade.GetAllDepartments(); 15 | IEnumerable employees = hrFacade.GetAllEmployees(); 16 | Manager manager = hrFacade.GetManagerById("M01"); 17 | 18 | departments.Should().HaveCount(2); 19 | employees.Should().HaveCount(3); 20 | manager.Should().NotBeNull(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Facade/ReadMe.txt: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Structural desgin pattern. 6 | 7 | - Frontface interface. 8 | 9 | - Simpler interface for complex module/subsystem. 10 | 11 | - Basically use complex system/subsystem/module. 12 | 13 | - Basically use a single wrapper class contains set of members consist of different classes. 14 | 15 | - Implement a single interface that delegate request to subsystems. 16 | 17 | Benifits: 18 | 19 | - Improve readability 20 | 21 | - Hide complixity 22 | 23 | - Loosely couple code 24 | 25 | - Easier to use. 26 | 27 | - Minimized dependencies from subsystems/modules. 28 | 29 | - May add additional functionality before/after forwading request. 30 | 31 | -------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/AbstractFactory/AbstractFact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Factory/AbstractFactory/AbstractFact.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/AbstractFactory/AbstractFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace TheDesignPatterns.Factory.AbstractFactory 4 | { 5 | public interface IChair 6 | { 7 | void SitOn(); 8 | } 9 | 10 | public class ComputerChair : IChair 11 | { 12 | public void SitOn() 13 | { 14 | Debug.WriteLine("Dyning Chair"); 15 | } 16 | } 17 | 18 | public class SofaChair : IChair 19 | { 20 | public void SitOn() 21 | { 22 | Debug.WriteLine("Sofa Chair"); 23 | } 24 | } 25 | 26 | public interface ITable 27 | { 28 | bool HasDrawar(); 29 | } 30 | 31 | public class ComputerTable : ITable 32 | { 33 | public bool HasDrawar() 34 | { 35 | return true; 36 | } 37 | } 38 | 39 | public class DyningTable : ITable 40 | { 41 | public bool HasDrawar() 42 | { 43 | return false; 44 | } 45 | } 46 | 47 | public interface IFurnitureFactory 48 | { 49 | IChair CreateChair(); 50 | ITable CreateTable(); 51 | } 52 | 53 | public class HomeFurnitureFactory : IFurnitureFactory 54 | { 55 | public IChair CreateChair() 56 | { 57 | IChair sofaChair = new SofaChair(); 58 | 59 | return sofaChair; 60 | } 61 | 62 | public ITable CreateTable() 63 | { 64 | ITable dyningTable = new DyningTable(); 65 | 66 | return dyningTable; 67 | } 68 | } 69 | 70 | public class OfficeFurnitureFactory : IFurnitureFactory 71 | { 72 | public IChair CreateChair() 73 | { 74 | IChair computerChair = new ComputerChair(); 75 | 76 | return computerChair; 77 | } 78 | 79 | public ITable CreateTable() 80 | { 81 | ITable computerTable = new ComputerTable(); 82 | 83 | return computerTable; 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/AbstractFactory/AbstractFactoryTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Factory.AbstractFactory 5 | { 6 | public class AbstractFactoryTest 7 | { 8 | [Fact] 9 | public void ShoudWorkForOfficeFurnitureCreation() 10 | { 11 | IFurnitureFactory officeFurnitureFactory = new OfficeFurnitureFactory(); 12 | IChair chair = officeFurnitureFactory.CreateChair(); 13 | ITable table = officeFurnitureFactory.CreateTable(); 14 | 15 | chair.GetType().Name.Should().Be("ComputerChair"); 16 | table.GetType().Name.Should().Be("ComputerTable"); 17 | } 18 | 19 | [Fact] 20 | public void ShoudWorkForHomeFurnitureCreation() 21 | { 22 | IFurnitureFactory officeFurnitureFactory = new HomeFurnitureFactory(); 23 | IChair chair = officeFurnitureFactory.CreateChair(); 24 | ITable table = officeFurnitureFactory.CreateTable(); 25 | 26 | chair.GetType().Name.Should().Be("SofaChair"); 27 | table.GetType().Name.Should().Be("DyningTable"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/AbstractFactory/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Creational design pattern 6 | 7 | - Create families of products without specifying their concreate class. 8 | 9 | - Separate object construct logic from its client. 10 | 11 | Benifit: 12 | 13 | - More decouple. 14 | 15 | ---------------------------------------------------------------------- 16 | 17 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/FactoryMethod/FactMethod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Factory/FactoryMethod/FactMethod.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/FactoryMethod/FactoryMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace TheDesignPatterns.Factory.FactoryMethod 5 | { 6 | public interface IVehicle 7 | { 8 | void Run(); 9 | } 10 | 11 | public class Car : IVehicle 12 | { 13 | public void Run() 14 | { 15 | Debug.WriteLine("Car is running"); 16 | } 17 | } 18 | 19 | public class MotorBike : IVehicle 20 | { 21 | public void Run() 22 | { 23 | Debug.WriteLine("MotorBike is running"); 24 | } 25 | } 26 | 27 | public interface IVehicleFactory 28 | { 29 | public IVehicle CreateVehicle(); 30 | } 31 | 32 | public class VehicleFactory : IVehicleFactory 33 | { 34 | private VehicleType vehicleType; 35 | 36 | public VehicleFactory(VehicleType vehicleType) 37 | { 38 | this.vehicleType = vehicleType; 39 | } 40 | public IVehicle CreateVehicle() 41 | { 42 | IVehicle vehicle = null; 43 | 44 | switch(vehicleType) 45 | { 46 | case VehicleType.Car: 47 | vehicle = new Car(); 48 | break; 49 | case VehicleType.MotorBike: 50 | vehicle = new MotorBike(); 51 | break; 52 | default: 53 | throw new NotImplementedException($"Sorry! {vehicleType} not yet launched!"); 54 | } 55 | 56 | return vehicle; 57 | } 58 | } 59 | 60 | public enum VehicleType 61 | { 62 | Car, 63 | MotorBike, 64 | Truck 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/FactoryMethod/FactoryMethodTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Factory.FactoryMethod 5 | { 6 | public class FactoryMethodTest 7 | { 8 | [Fact] 9 | public void ShouldWork() 10 | { 11 | IVehicleFactory vehicleFactory = new VehicleFactory(VehicleType.Car); 12 | IVehicle vehicle = vehicleFactory.CreateVehicle(); 13 | 14 | vehicle.Should().NotBeNull(); 15 | vehicle.GetType().Name.Should().Equals("Car"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Factory/FactoryMethod/ReadMe.txt: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------------------- 2 | Overview: 3 | 4 | - Creational design pattern 5 | 6 | - Define an interface for creating an object, but let subclasses decide which class to instantiate. 7 | 8 | - Factory Method lets a class defer instantiation to subclasses. 9 | 10 | - Factory Method depends on inheritance to decide which product to be created. 11 | 12 | Benifits: 13 | 14 | - More decouple. 15 | 16 | --------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Mediator/Mediator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TheDesignPatterns.Mediator 4 | { 5 | /// 6 | /// Colleague 7 | /// 8 | public interface IFamilyExpenseProvider 9 | { 10 | int ProvideExpenseAmount(); 11 | } 12 | 13 | public class Father : IFamilyExpenseProvider 14 | { 15 | public int ProvideExpenseAmount() 16 | { 17 | return 1000; 18 | } 19 | } 20 | public class GrandFather : IFamilyExpenseProvider 21 | { 22 | public int ProvideExpenseAmount() 23 | { 24 | return 2000; 25 | } 26 | } 27 | 28 | /// 29 | /// Mediator 30 | /// 31 | public interface IExpenseMoneyCollector 32 | { 33 | int CollectExpenseAmount(); 34 | } 35 | 36 | public class Mother : IExpenseMoneyCollector 37 | { 38 | private readonly IList familyExpenseProviderList = new List(); 39 | 40 | public Mother() 41 | { 42 | familyExpenseProviderList.Add(new Father()); 43 | familyExpenseProviderList.Add(new GrandFather()); 44 | } 45 | 46 | public int CollectExpenseAmount() 47 | { 48 | int totalAmount = 0; 49 | foreach(IFamilyExpenseProvider expenseProvider in familyExpenseProviderList) 50 | { 51 | totalAmount += expenseProvider.ProvideExpenseAmount(); 52 | } 53 | 54 | return totalAmount; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Mediator/Mediator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Mediator/Mediator.jpg -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Mediator/MediatorTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Mediator 5 | { 6 | public class MediatorTest 7 | { 8 | [Fact] 9 | public void ShouldWork() 10 | { 11 | IExpenseMoneyCollector mother = new Mother(); 12 | int totalExpenseAmount = mother.CollectExpenseAmount(); 13 | 14 | totalExpenseAmount.Should().Be(3000); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Mediator/Mediator_Usecase_Family.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Mediator/Mediator_Usecase_Family.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Mediator/ReadMe.txt: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------------------------- 2 | Overview: 3 | 4 | - A behavioral design pattern. 5 | 6 | - Encaptulate how object set of objects interact. 7 | 8 | - Restricts direct communication between objects and force them to collaborate only via mediator object. 9 | (Indirect communication between objects (Decouple objects from each other) 10 | 11 | Benifits: 12 | 13 | - More decouple. 14 | 15 | --------------------------------------------------------------------------------------------------------- 16 | 17 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/NullObject/NullObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TheDesignPatterns.NullObject 4 | { 5 | public interface IMathService 6 | { 7 | public int Addition(int x, int y); 8 | } 9 | 10 | public class MathService : IMathService 11 | { 12 | private readonly ILogger logger; 13 | 14 | public MathService(ILogger logger) 15 | { 16 | this.logger = logger; 17 | } 18 | 19 | public int Addition(int x, int y) 20 | { 21 | logger.Log($"For addition the value of x={x} and y={y}"); 22 | 23 | return x + y; 24 | } 25 | } 26 | 27 | public interface ILogger 28 | { 29 | public void Log(string logData); 30 | } 31 | 32 | public class ConsoleLogger : ILogger 33 | { 34 | public void Log(string logData) 35 | { 36 | Console.WriteLine(logData); 37 | } 38 | } 39 | 40 | public class NullLogger : ILogger 41 | { 42 | public void Log(string logData) 43 | { 44 | // Do nothing 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/NullObject/NullObject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/NullObject/NullObject.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/NullObject/NullObjectTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.NullObject 5 | { 6 | public class NullObjectTest 7 | { 8 | private readonly IMathService mathService; 9 | 10 | public NullObjectTest() 11 | { 12 | ILogger logger = new NullLogger(); 13 | this.mathService = new MathService(logger); 14 | } 15 | 16 | [Fact] 17 | public void ShouldWork() 18 | { 19 | int result = mathService.Addition(20, 10); 20 | 21 | result.Should().Be(30); 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/NullObject/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Simplify used dependencies that are still undefined. 6 | 7 | - It uses instead of null reference. 8 | 9 | - Null object is used and it does not contain any functionality. 10 | 11 | Benifit: 12 | 13 | - Safe from Runtime Null Reference exception. It is very dangeous type of exception and 14 | very difficult to trace when raised. 15 | 16 | - No need to check null 17 | 18 | - Null object can be used when need real object do nothing. 19 | 20 | - More readable code. 21 | 22 | Concern: 23 | 24 | - This pattern should be used carefully as it can make erros as normal program execution. 25 | 26 | ---------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Observer/Observer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace TheDesignPatterns.Observer 6 | { 7 | /// 8 | /// Subject Class 9 | /// 10 | public class KeyboardItemInStock 11 | { 12 | private readonly Queue keyboards = new Queue(); 13 | private readonly IList noKeyboardInStockListeners = new List(); 14 | 15 | public KeyboardItemInStock() 16 | { 17 | keyboards.Enqueue(new Keyboard { Id = 1, UnitPrice = 100 }); 18 | keyboards.Enqueue(new Keyboard { Id = 2, UnitPrice = 150 }); 19 | keyboards.Enqueue(new Keyboard { Id = 3, UnitPrice = 200 }); 20 | } 21 | 22 | /// 23 | /// Register Listers who are interested to listen when keybaord will be empty in stock. 24 | /// 25 | /// 26 | public void RegisterListener(INoKeyboardInStockListener newListner) 27 | { 28 | noKeyboardInStockListeners.Add(newListner); 29 | } 30 | 31 | public void UnRegisterListener(INoKeyboardInStockListener existingListner) 32 | { 33 | noKeyboardInStockListeners.Remove(existingListner); 34 | } 35 | 36 | public Keyboard FetchSingleKeyboard() 37 | { 38 | Keyboard singleKeyboard = keyboards.Dequeue(); 39 | 40 | if (keyboards.Count ==0 ) 41 | { 42 | NotifyNOKeyboardInStockListenres(); 43 | } 44 | 45 | return singleKeyboard; 46 | } 47 | 48 | /// 49 | /// Retrull all observers who wants to listen when empty keyboard in stock 50 | /// 51 | /// 52 | public IEnumerable GetAllObservers() 53 | { 54 | return noKeyboardInStockListeners; 55 | } 56 | 57 | /// 58 | /// Notify all listeners when keyboard is empty in stock. 59 | /// 60 | private void NotifyNOKeyboardInStockListenres() 61 | { 62 | foreach(INoKeyboardInStockListener listner in noKeyboardInStockListeners ) 63 | { 64 | listner.OnEmptyKeyboardInStock(DateTime.UtcNow); 65 | } 66 | } 67 | } 68 | 69 | public class Keyboard 70 | { 71 | public int Id { get; set; } 72 | 73 | public string Model { get; set; } 74 | 75 | public int UnitPrice { get; set; } 76 | } 77 | 78 | /// 79 | /// Observer interface 80 | /// 81 | public interface INoKeyboardInStockListener 82 | { 83 | void OnEmptyKeyboardInStock(DateTime date); 84 | } 85 | 86 | /// 87 | /// One kind of observer 88 | /// 89 | public class Supplier : INoKeyboardInStockListener 90 | { 91 | public int SupplierId { get; set; } 92 | public string SupplierName { get; set; } 93 | public DateTime? DateOfKeyboardEmptyInStock { get; private set; } 94 | 95 | public void OnEmptyKeyboardInStock(DateTime date) 96 | { 97 | DateOfKeyboardEmptyInStock = date; 98 | 99 | Debug.WriteLine($"Need to supply new products dated={date}"); 100 | } 101 | } 102 | 103 | /// 104 | /// Another kind of observer 105 | /// 106 | public class Accounts : INoKeyboardInStockListener 107 | { 108 | public int AccountId { get; set; } 109 | public string AccountName { get; set; } 110 | public DateTime? DateOfKeyboardEmptyInStock { get; private set; } 111 | 112 | public void OnEmptyKeyboardInStock(DateTime date) 113 | { 114 | DateOfKeyboardEmptyInStock = date; 115 | 116 | Debug.WriteLine($"Keyboard stock has finished at {date}. Need to prepare money for purchse new items"); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Observer/Observer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Observer/Observer.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Observer/ObserverTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System; 3 | using Xunit; 4 | 5 | namespace TheDesignPatterns.Observer 6 | { 7 | public class ObserverTest 8 | { 9 | private readonly KeyboardItemInStock keyboardItemInStock = new KeyboardItemInStock(); 10 | 11 | [Fact] 12 | public void ShouldRegisterListener() 13 | { 14 | INoKeyboardInStockListener supplierListener = new Supplier(); 15 | INoKeyboardInStockListener accountListener = new Supplier(); 16 | 17 | keyboardItemInStock.RegisterListener(supplierListener); 18 | keyboardItemInStock.RegisterListener(accountListener); 19 | 20 | keyboardItemInStock.GetAllObservers().Should().HaveCount(2); 21 | } 22 | 23 | 24 | [Fact] 25 | public void ShouldNotifyListeners() 26 | { 27 | //Arrange 28 | var supplierListener = new Supplier(); 29 | var accountListener = new Accounts(); 30 | 31 | keyboardItemInStock.RegisterListener(supplierListener); 32 | keyboardItemInStock.RegisterListener(accountListener); 33 | 34 | //Act 35 | Keyboard item1 = keyboardItemInStock.FetchSingleKeyboard(); // after getting, still stock has two items 36 | Keyboard item2 = keyboardItemInStock.FetchSingleKeyboard(); // after getting, still stock has one item 37 | Keyboard item3 = keyboardItemInStock.FetchSingleKeyboard(); // after getting, stock is empty and now it should notify subsribers/listeners 38 | 39 | //Assert 40 | supplierListener.DateOfKeyboardEmptyInStock.Should().BeSameDateAs(DateTime.UtcNow); 41 | accountListener.DateOfKeyboardEmptyInStock.Should().BeSameDateAs(DateTime.UtcNow); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Observer/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------------------------------- 2 | 3 | - Overview: 4 | 5 | - Main intent is a machanism to notify one objects change to other objects who are depends on it (One to Many). 6 | 7 | - After nofited dependent objects work accordingly. 8 | 9 | - Implementation would be dependent objects subscripe main objects events. 10 | 11 | - Synchonous by nature. 12 | 13 | - 2 main components i) Subject (Publisher who maintain observers collection and notify them) 14 | ii) Observer (subscribers who are listening) 15 | 16 | - Publisher-Subscripber pattern and Observer pattern has little difference. 17 | Pub/Sub is asynchonous and use Message Broker for communicating. 18 | 19 | - Benenits: 20 | 21 | - Notifier objects and notifie object will be decoupled. 22 | 23 | - Easily manage one to many dependencies. 24 | 25 | - Responsibility can be separated between many objects. 26 | 27 | - Disadvantages: 28 | 29 | - Subject & observer know each other (One kind of coupling is there). 30 | 31 | ------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Proxy/Proxy.cs: -------------------------------------------------------------------------------- 1 | namespace TheDesignPatterns.Proxy 2 | { 3 | public interface IAccountService 4 | { 5 | int GetTodaysIncome(); 6 | 7 | int GetTodaysExpense(); 8 | } 9 | 10 | public class AccountService : IAccountService 11 | { 12 | public int GetTodaysExpense() 13 | { 14 | int expense = 500; 15 | 16 | return expense; 17 | } 18 | 19 | public int GetTodaysIncome() 20 | { 21 | int income = 1000000; 22 | 23 | return income; 24 | } 25 | } 26 | 27 | public class ProxyAccountService : IAccountService 28 | { 29 | private readonly IAccountService accountService = new AccountService(); 30 | 31 | public int GetTodaysExpense() 32 | { 33 | int expense = accountService.GetTodaysExpense(); 34 | 35 | if (expense >= 10000) 36 | { 37 | return expense; 38 | } 39 | 40 | return expense * 2; 41 | } 42 | 43 | public int GetTodaysIncome() 44 | { 45 | int income = accountService.GetTodaysIncome(); 46 | 47 | if (income > 10000) 48 | { 49 | return income / 2; 50 | } 51 | 52 | return income; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Proxy/Proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Proxy/Proxy.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Proxy/ProxyTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Proxy 5 | { 6 | public class ProxyTest 7 | { 8 | [Fact] 9 | public void ShouldWorkProperlyUsingProxyDesingPattern() 10 | { 11 | IAccountService accountService = new ProxyAccountService(); 12 | int todaysIncome = accountService.GetTodaysIncome(); 13 | int todaysExpense = accountService.GetTodaysExpense(); 14 | 15 | todaysIncome.Should().BeLessOrEqualTo(1000000 / 2); 16 | todaysExpense.Should().BeGreaterOrEqualTo(500 * 2); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Proxy/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - Its a structural design pattern. 6 | 7 | - Placeholder of another object. 8 | 9 | - Control access to another object. 10 | 11 | - A wrapper for real object for safe undue complexity. 12 | 13 | Benefits: 14 | 15 | - Better security. 16 | 17 | - Allow something before or after or both the request gets through the original object. 18 | 19 | - Support lazy initailization (object create on demand). 20 | 21 | ------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/PublisherSubScriber/PublisherSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | 4 | namespace TheDesignPatterns.PublisherSubScriber 5 | { 6 | /// 7 | /// Custom message broker. Here It should be any popular message brokers 8 | /// like Apachi Kakfa/RabbitMq/ActiveMq etc. 9 | /// 10 | public interface IMessageBroker 11 | { 12 | void Subscribe(string topic, IMessageSubscriber subscriber); 13 | 14 | void Publish(string topic, string message); 15 | } 16 | 17 | 18 | public class CustomMessageBroker : IMessageBroker 19 | { 20 | private IList topicSubscribers = new List(); 21 | 22 | public void Subscribe(string topic, IMessageSubscriber messageSubscriber) 23 | { 24 | topicSubscribers.Add(new TopicSubscriber(topic, messageSubscriber)); 25 | } 26 | 27 | public void Publish(string topic, string message) 28 | { 29 | foreach(TopicSubscriber topicSubscriber in topicSubscribers) 30 | { 31 | if (!topicSubscriber.Topic.Equals( topic)) 32 | { 33 | break; 34 | } 35 | 36 | topicSubscriber.MessageSubscriber.OnMessage(message); 37 | } 38 | } 39 | } 40 | 41 | /// 42 | /// Publisher component who publish the messages 43 | /// 44 | public class Management 45 | { 46 | private readonly IMessageBroker messageBroker; 47 | public Management(IMessageBroker messageBroker) 48 | { 49 | this.messageBroker = messageBroker; 50 | } 51 | 52 | public void PublishKeyboardNeedMessage() 53 | { 54 | this.messageBroker.Publish("KEYBOARDNEEDED", "Please organize more keyboards"); 55 | } 56 | } 57 | 58 | /// 59 | /// Message Subscription interface. Who are interested to listen should implement this. 60 | /// 61 | public interface IMessageSubscriber 62 | { 63 | /// 64 | /// Publisher will execute this method with message 65 | /// 66 | /// 67 | void OnMessage(string message); 68 | } 69 | 70 | /// 71 | /// A subscriber 72 | /// 73 | public class AccountsManager : IMessageSubscriber 74 | { 75 | public void OnMessage(string message) 76 | { 77 | ArrangeMoney(message); 78 | } 79 | 80 | private void ArrangeMoney(string message) 81 | { 82 | Debug.WriteLine($"Arranging money. Message={message}"); 83 | } 84 | } 85 | 86 | /// 87 | /// Another subscriber 88 | /// 89 | public class PurchaseManager : IMessageSubscriber 90 | { 91 | public void OnMessage(string message) 92 | { 93 | PurchaseKeyboards(message); 94 | } 95 | 96 | private void PurchaseKeyboards(string message) 97 | { 98 | Debug.WriteLine($"Arranging keyboards. Message={message}"); 99 | } 100 | } 101 | 102 | public class TopicSubscriber 103 | { 104 | public string Topic { get; private set; } 105 | public IMessageSubscriber MessageSubscriber { get; private set; } 106 | 107 | public TopicSubscriber(string topic, IMessageSubscriber messageSubscriber ) 108 | { 109 | this.Topic = topic; 110 | this.MessageSubscriber = messageSubscriber; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/PublisherSubScriber/PublisherSubscriber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/PublisherSubScriber/PublisherSubscriber.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/PublisherSubScriber/PublisherSubscriberTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace TheDesignPatterns.PublisherSubScriber 4 | { 5 | public class PublisherSubscriberTest 6 | { 7 | [Fact] 8 | public void ShouldPublishAndSubscibeMessageUsingPubSubDesignPattern() 9 | { 10 | IMessageBroker messageBroker = new CustomMessageBroker(); 11 | IMessageSubscriber accountManager = new AccountsManager(); 12 | IMessageSubscriber purchaseManager = new PurchaseManager(); 13 | 14 | messageBroker.Subscribe("KEYBOARDNEEDED", accountManager); 15 | messageBroker.Subscribe("KEYBOARDNEEDED", purchaseManager); 16 | 17 | var manaement = new Management(messageBroker); 18 | 19 | manaement.PublishKeyboardNeedMessage(); 20 | 21 | // Please check the debug window for message information. 22 | } 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/PublisherSubScriber/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------------------------- 2 | 3 | - Overview 4 | 5 | - Short name is pub/sub 6 | 7 | - Asynchonously notify subscriber about any changes/events so that they (dependent object) can interact. 8 | 9 | - Similar to Observer pattern but has few difference and it is not GOF design pattern. 10 | 11 | - Publisher has no knowldge about its subscriber. It just brodecast the message. 12 | 13 | - Subscriber has no knowledge about message publisher. 14 | 15 | - Heavily use Event driven architecture. 16 | 17 | - 2 ways to implement i) Peer to Peer ii) With message broker 18 | 19 | - Advantages: 20 | 21 | - Decouple objects 22 | 23 | - Responsibilites are separated. 24 | 25 | ----------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Repository/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - A data access pattern 6 | 7 | - Introduced as a part of DDD (Domain Driven Design) 8 | 9 | - Separate persistence responsibility from UI/Business classes. 10 | 11 | Advantages: 12 | 13 | - Enable single responsibility principle. 14 | 15 | - Promote separation of concern. 16 | 17 | - Reducing coupling to persistence details. 18 | 19 | - Improve testibility. 20 | 21 | Implementation Approaches: 22 | 23 | - Organized by CQRS (Read/Write) 24 | - IReadRepository 25 | - IWriteRepository 26 | 27 | - Per Bounded Context 28 | 29 | - Per Aggregate 30 | - Prevent ability to persist any entity outside of its aggregate 31 | 32 | - Per Entity 33 | - Customer Repository, Order Repository, Product Repository 34 | 35 | - Always should return Domain Entity 36 | 37 | - Generic Repository IRepository 38 | 39 | ---------------------------------------------------------------------- 40 | 41 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Repository/Repository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace TheDesignPatterns.Repository 5 | { 6 | public abstract class EntityBase 7 | { 8 | public string Id { get; set; } 9 | 10 | public DateTime CreatedDate => DateTime.UtcNow; 11 | } 12 | 13 | public class Employee : EntityBase 14 | { 15 | public string Name { get; set; } 16 | } 17 | 18 | public class User : EntityBase 19 | { 20 | public string Email { get; set; } 21 | } 22 | 23 | /// 24 | /// Generic Repository for all Data source 25 | /// 26 | /// 27 | public interface IRepository where T : EntityBase 28 | { 29 | T FindById(string id); 30 | 31 | void Save(T entity); 32 | } 33 | 34 | 35 | /// 36 | /// Nosql database specific Employee Repository 37 | /// 38 | public interface INoSqlEmployeeRepository : IRepository 39 | { 40 | IEnumerable FindEmployees(string departmentId); 41 | } 42 | 43 | /// 44 | /// Sql database specific employee repository 45 | /// 46 | public interface ISqlEmployeeRepository : IRepository 47 | { 48 | IEnumerable FindEmployees(string departmentId); 49 | } 50 | 51 | /// 52 | /// Concreate Employee repository for NosqlDatabase 53 | /// 54 | public class NoSqlEmployeeRepository : INoSqlEmployeeRepository 55 | { 56 | public Employee FindById(string id) 57 | { 58 | return new Employee { Id = id, Name = $"Name-{id}" }; 59 | } 60 | 61 | public IEnumerable FindEmployees(string departmentId) 62 | { 63 | return new[] { new Employee { Id = "E01", Name = "Name-01" }, new Employee { Id = "E02", Name = "Name-02" } }; 64 | } 65 | 66 | public void Save(Employee entity) 67 | { 68 | // Save the employee... 69 | } 70 | } 71 | 72 | /// 73 | /// Concreate Employee repository for sqlDatabase 74 | /// 75 | public class SqlEmployeeRepository : ISqlEmployeeRepository 76 | { 77 | public Employee FindById(string id) 78 | { 79 | return new Employee { Id = id, Name = $"Name-{id}" }; 80 | } 81 | 82 | public IEnumerable FindEmployees(string departmentId) 83 | { 84 | return new[] { new Employee { Id = "E01", Name = "Name-01" }, new Employee { Id = "E02", Name = "Name-02" } }; 85 | } 86 | 87 | public void Save(Employee entity) 88 | { 89 | // Save the employee... 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Repository/Repository.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Repository/Repository.jpg -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Repository/RepositoryTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System.Collections.Generic; 3 | using Xunit; 4 | 5 | namespace TheDesignPatterns.Repository 6 | { 7 | public class NoSqlRepositoryTest 8 | { 9 | private readonly NoSqlEmployeeRepository noSqlEmployeeRepository = new NoSqlEmployeeRepository(); 10 | 11 | [Fact] 12 | public void ShouldReturnEmployeeWhenValidEmployeeIdProvided() 13 | { 14 | Employee emp = noSqlEmployeeRepository.FindById("001"); 15 | 16 | emp.Should().NotBeNull(); 17 | emp.Id.Should().Be("001"); 18 | } 19 | 20 | [Fact] 21 | public void ShouldReturnEmployeesWhenValidDepartmentIdProvided() 22 | { 23 | string departmentId = "D001"; 24 | 25 | IEnumerable employees = noSqlEmployeeRepository.FindEmployees(departmentId); 26 | 27 | employees.Should().HaveCount(2); 28 | } 29 | 30 | [Fact] 31 | public void ShouldSaveEmployee() 32 | { 33 | var employee = new Employee { Id = "E001", Name = "Employee-001" }; 34 | 35 | noSqlEmployeeRepository.Save(employee); 36 | } 37 | 38 | } 39 | 40 | public class SqlRepositoryTest 41 | { 42 | private readonly SqlEmployeeRepository sqlEmployeeRepository = new SqlEmployeeRepository(); 43 | 44 | [Fact] 45 | public void ShouldReturnEmployeeWhenValidEmployeeIdProvided() 46 | { 47 | Employee emp = sqlEmployeeRepository.FindById("001"); 48 | 49 | emp.Should().NotBeNull(); 50 | emp.Id.Should().Be("001"); 51 | } 52 | 53 | [Fact] 54 | public void ShouldReturnEmployeesWhenValidDepartmentIdProvided() 55 | { 56 | string departmentId = "D001"; 57 | 58 | IEnumerable employees = sqlEmployeeRepository.FindEmployees(departmentId); 59 | 60 | employees.Should().HaveCount(2); 61 | } 62 | 63 | [Fact] 64 | public void ShouldSaveEmployee() 65 | { 66 | var employee = new Employee { Id = "E001", Name = "Employee-001" }; 67 | 68 | sqlEmployeeRepository.Save(employee); 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Singleton/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Overview: 2 | - Ensure a class has only one instance. 3 | - Make the class itself responsible for keeping track of its sole instance. 4 | - There can be only one. 5 | 6 | Disadvantages: 7 | - Global state. 8 | - Difficult to test. 9 | - Violate single responsibility principle. 10 | - Some experts called it is an anti pattern. 11 | 12 | Solution: 13 | - Instead of manualy create it is possible to create with the help of IOC container to avoid 14 | maintaining lifetime and also coupoing and testibility issue. -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Singleton/Singleton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TheDesignPatterns.Singleton 4 | { 5 | /// 6 | /// Singleton object (Application lifetime only onetime instance will be created) 7 | /// 8 | public class ApplicationObject 9 | { 10 | public Guid ApplicationId { get; private set; } 11 | private static ApplicationObject singleInstance = null; 12 | private static readonly object v = new object(); 13 | private static readonly object lockObject = v; 14 | 15 | 16 | private ApplicationObject() 17 | { 18 | } 19 | 20 | public static ApplicationObject GetInstance() 21 | { 22 | if (null == singleInstance) 23 | { 24 | lock (lockObject) 25 | { 26 | if (null == singleInstance) 27 | { 28 | singleInstance = new ApplicationObject 29 | { 30 | ApplicationId = Guid.NewGuid() 31 | }; 32 | } 33 | } 34 | } 35 | 36 | return singleInstance; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Singleton/Singleton.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Singleton/Singleton.jpg -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Singleton/SingletonTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.Singleton 5 | { 6 | public class SingletonTest 7 | { 8 | [Fact] 9 | public void ShouldWork() 10 | { 11 | ApplicationObject applicationObject = ApplicationObject.GetInstance(); 12 | 13 | applicationObject.Should().NotBeNull(); 14 | applicationObject.ApplicationId.Should().NotBeEmpty(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Specification/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------ 2 | 3 | - Overview: 4 | 5 | - A way of encaptualte domain rules in objects. 6 | 7 | - Frequently used in DDD (Domain Driven Design) 8 | 9 | - All one type of logic (Filtering logic) keept in one place. 10 | 11 | - Advantages: 12 | 13 | - Reusablity 14 | 15 | - Maintanability. 16 | 17 | - Decouple 18 | 19 | - Disadvantages: 20 | 21 | - Few experts consider it as anti pattern. 22 | 23 | ------------------------------------------------------------------------ -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Specification/Specification.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | 4 | namespace TheDesignPatterns.Specification 5 | { 6 | 7 | public class Employee 8 | { 9 | public int Id { get; set; } 10 | 11 | public string Name { get; set; } 12 | 13 | public string Department { get; set; } 14 | 15 | public bool Active { get; set; } 16 | } 17 | 18 | /// 19 | /// Composit specification can also possible by adding AND OR specification. 20 | /// 21 | /// 22 | public interface ISpecification where T : class 23 | { 24 | bool IsSatisfiedBy(T employee); 25 | } 26 | 27 | 28 | public class ActiveEmployeSpecification : ISpecification 29 | { 30 | public bool IsSatisfiedBy(Employee employee) 31 | { 32 | return employee.Active; 33 | } 34 | } 35 | 36 | public class JavaEmployeSpecification : ISpecification 37 | { 38 | public bool IsSatisfiedBy(Employee employee) 39 | { 40 | return employee.Department.Equals("Java"); 41 | } 42 | } 43 | 44 | public class SendEmailSpecification : ISpecification 45 | { 46 | public bool IsSatisfiedBy(Employee employee) 47 | { 48 | return employee.Active && (employee.Department == "C#" || employee.Department == "Python"); 49 | } 50 | } 51 | 52 | public class EmployeeService 53 | { 54 | private readonly IList employees = new List(); 55 | 56 | public EmployeeService() 57 | { 58 | employees.Add(new Employee { Id = 1, Name = "Employee-1", Department = "C#", Active = true }); 59 | employees.Add(new Employee { Id = 2, Name = "Employee-2", Department = "C#", Active = true }); 60 | employees.Add(new Employee { Id = 3, Name = "Employee-3", Department = "Java", Active = true }); 61 | employees.Add(new Employee { Id = 4, Name = "Employee-4", Department = "Java", Active = true }); 62 | employees.Add(new Employee { Id = 5, Name = "Employee-5", Department = "Python", Active = true }); 63 | employees.Add(new Employee { Id = 6, Name = "Employee-6", Department = "Python", Active = false }); 64 | } 65 | 66 | /// 67 | /// Find the employees who meet the specification 68 | /// 69 | /// 70 | public IEnumerable FindEmployees(ISpecification specification) 71 | { 72 | var localEmployees = new List(); 73 | 74 | foreach (Employee employee in employees) 75 | { 76 | if (specification.IsSatisfiedBy(employee)) 77 | { 78 | localEmployees.Add(employee); 79 | } 80 | } 81 | 82 | return localEmployees; 83 | } 84 | 85 | /// 86 | /// Find the employees who meet the specifications 87 | /// 88 | /// 89 | public IEnumerable FindEmployees(IEnumerable> specifications) 90 | { 91 | var localEmployees = new List(); 92 | 93 | foreach (Employee employee in employees) 94 | { 95 | var satisfied = true; 96 | 97 | foreach (ISpecification specification in specifications) 98 | { 99 | satisfied = specification.IsSatisfiedBy(employee); 100 | if (!satisfied) 101 | { 102 | satisfied = false; 103 | break; 104 | } 105 | } 106 | 107 | if (satisfied) 108 | { 109 | localEmployees.Add(employee); 110 | } 111 | } 112 | 113 | return localEmployees; 114 | } 115 | 116 | /// 117 | /// Send email to those employees who has satisfied condition 118 | /// 119 | public void SendEmailToAllEmployees(ISpecification emailSendingSpeicication) 120 | { 121 | foreach (Employee employee in employees) 122 | { 123 | bool satisfied = emailSendingSpeicication.IsSatisfiedBy(employee); 124 | if (satisfied) 125 | { 126 | SendEmail(employee); 127 | } 128 | } 129 | } 130 | 131 | /// 132 | /// Provide EmployeeSpecifications for ActiveJava employees 133 | /// 134 | /// 135 | public IEnumerable> GetActiveJavaEmployeeSpecifications() 136 | { 137 | var list = new List>(); 138 | list.Add(new ActiveEmployeSpecification()); 139 | list.Add(new JavaEmployeSpecification()); 140 | 141 | return list; 142 | } 143 | 144 | /// 145 | /// Email Sending Helper 146 | /// 147 | /// 148 | private void SendEmail(Employee employee) 149 | { 150 | Debug.WriteLine($"Email Sending to Employee Id={employee.Id}"); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Specification/Specification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Specification/Specification.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Specification/SpecificationTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System.Collections.Generic; 3 | using Xunit; 4 | 5 | namespace TheDesignPatterns.Specification 6 | { 7 | public class SpecificationTest 8 | { 9 | private readonly EmployeeService employeeService = new EmployeeService(); 10 | 11 | [Fact] 12 | public void ShouldReturnActiveEmployees() 13 | { 14 | ISpecification activeEmployeeSpecification = new ActiveEmployeSpecification(); 15 | 16 | IEnumerable activeEmployees = employeeService.FindEmployees(activeEmployeeSpecification); 17 | 18 | activeEmployees.Should().HaveCount(5); 19 | } 20 | 21 | [Fact] 22 | public void ShouldReturnActiveJavaEmployees() 23 | { 24 | IEnumerable> specifications = employeeService.GetActiveJavaEmployeeSpecifications(); 25 | 26 | IEnumerable activeJavaEmployees = employeeService.FindEmployees(specifications); 27 | 28 | activeJavaEmployees.Should().HaveCount(2); 29 | } 30 | 31 | [Fact] 32 | public void ShoudSendEmailToPerfectEmployees() 33 | { 34 | ISpecification specification = new SendEmailSpecification(); 35 | 36 | employeeService.SendEmailToAllEmployees(specification); 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/State/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | 3 | - Overview: 4 | 5 | - It is a behavioural pattern. 6 | 7 | - Object behavior is changed based on object state change. 8 | 9 | - 2 Components 1) Context 2) State. Context hold State reference. 10 | 11 | - 2 challenges: 12 | i) How can an object change its behavior when its internal state changes 13 | ii) How can state-specific behaviors be defined in a way that states can 14 | be added without altering the behaviors of existing states? 15 | 16 | - The pattern does not specify where the state transition will be defined. 17 | 2 places are there i) Context object and ii) Each State object 18 | 19 | - Advantages: 20 | 21 | - Easily changable & flexible. 22 | 23 | - Easily Extendable. 24 | 25 | - Allow pollymorphic behaviour. 26 | 27 | 28 | ------------------------------------------------------------------------------- 29 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/State/State.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace TheDesignPatterns.State 4 | { 5 | public interface IState 6 | { 7 | void Handle(VideoPlayer videoPalyer); 8 | } 9 | 10 | 11 | public class StartedState : IState 12 | { 13 | public void Handle(VideoPlayer videoPalyer) 14 | { 15 | if (!(videoPalyer.CurrentState is StartedState)) 16 | { 17 | Debug.WriteLine($"Video is started"); 18 | } 19 | } 20 | } 21 | 22 | public class PausedState : IState 23 | { 24 | public void Handle(VideoPlayer videoPalyer) 25 | { 26 | if (!(videoPalyer.CurrentState is PausedState)) 27 | { 28 | Debug.WriteLine($"Video is Paused"); 29 | } 30 | } 31 | } 32 | 33 | /// 34 | /// State 35 | /// 36 | public class StoppedState : IState 37 | { 38 | public void Handle(VideoPlayer videoPalyer) 39 | { 40 | if (!(videoPalyer.CurrentState is PausedState)) 41 | { 42 | Debug.WriteLine($"Video is Stopped"); 43 | } 44 | } 45 | } 46 | 47 | /// 48 | /// Context class 49 | /// 50 | public class VideoPlayer 51 | { 52 | public IState CurrentState { get; private set; } 53 | 54 | public void ChangeState(IState state) 55 | { 56 | this.CurrentState = state; 57 | } 58 | 59 | public void Operate() 60 | { 61 | CurrentState.Handle(this); 62 | } 63 | } 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/State/State.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/State/State.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/State/StateTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace TheDesignPatterns.State 5 | { 6 | public class StateTest 7 | { 8 | [Fact] 9 | public void ShouldStartVideoPalyer() 10 | { 11 | var startedState = new StartedState(); 12 | var videoPlayer = new VideoPlayer(); 13 | videoPlayer.ChangeState(startedState); 14 | 15 | videoPlayer.Operate(); 16 | 17 | videoPlayer.CurrentState.Should().BeEquivalentTo(startedState); 18 | } 19 | 20 | [Fact] 21 | public void ShouldPauseVideoPalyer() 22 | { 23 | var pausedState = new PausedState(); 24 | var videoPlayer = new VideoPlayer(); 25 | videoPlayer.ChangeState(pausedState); 26 | 27 | videoPlayer.Operate(); 28 | 29 | videoPlayer.CurrentState.Should().BeEquivalentTo(pausedState); 30 | } 31 | 32 | [Fact] 33 | public void ShouldStoppedVideoPalyer() 34 | { 35 | var stoppedState = new StoppedState(); 36 | var videoPlayer = new VideoPlayer(); 37 | videoPlayer.ChangeState(stoppedState); 38 | 39 | videoPlayer.Operate(); 40 | 41 | videoPlayer.CurrentState.Should().BeEquivalentTo(stoppedState); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/CouponCodes.cs: -------------------------------------------------------------------------------- 1 | namespace ThePattern.Stratigy 2 | { 3 | public enum CouponCodes 4 | { 5 | FlatRateCode, 6 | PercentageCode, 7 | PercentageLimitCode 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/DiscountStartegyTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace ThePattern.Stratigy 4 | { 5 | public class DiscountStartegyTests 6 | { 7 | private FlatRateDiscountStratigy flatRateDiscountStratigy; 8 | private PercentageDiscountStrategy percentageDiscountStratigy; 9 | private PercentageLimitDiscountStrategy percentageLimitDiscountStratigy; 10 | 11 | public DiscountStartegyTests() 12 | { 13 | } 14 | 15 | [Fact] 16 | public void ShouldDiscountFixedAmount() 17 | { 18 | long price = 1000; 19 | 20 | flatRateDiscountStratigy = new FlatRateDiscountStratigy(price); 21 | 22 | long discount = flatRateDiscountStratigy.Discount(); 23 | 24 | Assert.Equal(700, discount); 25 | } 26 | 27 | [Fact] 28 | public void ShouldDiscountPercentage() 29 | { 30 | long price = 1000; 31 | 32 | percentageDiscountStratigy = new PercentageDiscountStrategy(price); 33 | 34 | long discount = percentageDiscountStratigy.Discount(); 35 | 36 | Assert.Equal(150, discount); 37 | } 38 | 39 | [Fact] 40 | public void ShouldDiscountPercentageLimitPolicy() 41 | { 42 | long price = 1800; 43 | 44 | percentageLimitDiscountStratigy = new PercentageLimitDiscountStrategy(price); 45 | 46 | long discount = percentageLimitDiscountStratigy.Discount(); 47 | 48 | Assert.Equal(270, discount); 49 | } 50 | 51 | [Fact] 52 | public void ShouldDiscountMaxRateWithIgnoringActualCalculatedDiscount() 53 | { 54 | long price = 3000; 55 | 56 | percentageLimitDiscountStratigy = new PercentageLimitDiscountStrategy(price); 57 | 58 | long discount = percentageLimitDiscountStratigy.Discount(); 59 | 60 | Assert.Equal(300, discount); 61 | } 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/DiscountStrategyProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ThePattern.Stratigy 4 | { 5 | public class DiscountStrategyProvider : IDiscountStrategyProvider 6 | { 7 | public IDiscountStrategy CreateDiscountStratigy(int couponCode, long productPrice) 8 | { 9 | IDiscountStrategy stratigy; 10 | 11 | switch (couponCode) 12 | { 13 | case (int)CouponCodes.FlatRateCode: 14 | stratigy = new FlatRateDiscountStratigy(productPrice); 15 | break; 16 | case (int)CouponCodes.PercentageCode: 17 | stratigy = new PercentageDiscountStrategy(productPrice); 18 | break; 19 | case (int)CouponCodes.PercentageLimitCode: 20 | stratigy = new PercentageLimitDiscountStrategy(productPrice); 21 | break; 22 | default: 23 | throw new ApplicationException($"Sorry! {couponCode} is not a valid Coupon code."); 24 | } 25 | 26 | return stratigy; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/FlatRateDiscountStratigy.cs: -------------------------------------------------------------------------------- 1 | namespace ThePattern.Stratigy 2 | { 3 | public class FlatRateDiscountStratigy : IDiscountStrategy 4 | { 5 | private const long FIXED_AMOUNT = 300; 6 | private readonly long _price; 7 | 8 | public FlatRateDiscountStratigy(long price) 9 | { 10 | _price = price; 11 | } 12 | 13 | public long Discount() 14 | { 15 | return _price - FIXED_AMOUNT; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/IDiscountStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace ThePattern.Stratigy 2 | { 3 | public interface IDiscountStrategy 4 | { 5 | long Discount(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/IDiscountStrategyProvider.cs: -------------------------------------------------------------------------------- 1 | namespace ThePattern.Stratigy 2 | { 3 | public interface IDiscountStrategyProvider 4 | { 5 | IDiscountStrategy CreateDiscountStratigy(int couponCode, long productPrice); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/PercentageDiscountStrategy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ThePattern.Stratigy 4 | { 5 | public class PercentageDiscountStrategy : IDiscountStrategy 6 | { 7 | private readonly long _price; 8 | private const decimal PercentDiscountRate = 15; // 15% 9 | 10 | public PercentageDiscountStrategy(long price) 11 | { 12 | _price = price; 13 | } 14 | 15 | public long Discount() 16 | { 17 | decimal percent = PercentDiscountRate / 100; 18 | 19 | return Convert.ToInt64(_price * percent); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/PercentageLimitDiscountStrategy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ThePattern.Stratigy 4 | { 5 | public class PercentageLimitDiscountStrategy : IDiscountStrategy 6 | { 7 | private readonly long _price; 8 | private const long DiscountAmountLimit = 300; 9 | private const decimal DiscountRateInPercent = 15; //15% 10 | 11 | public PercentageLimitDiscountStrategy(long price) 12 | { 13 | _price = price; 14 | } 15 | 16 | public long Discount() 17 | { 18 | decimal discountPercent = DiscountRateInPercent / 100; 19 | 20 | long discountValue = Convert.ToInt64(_price * discountPercent); 21 | 22 | if (discountValue > DiscountAmountLimit) 23 | { 24 | return DiscountAmountLimit; 25 | } 26 | 27 | return discountValue; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------------- 2 | 3 | Overview: 4 | 5 | - It is a behavioral Design pattern. Invented by GOF. 6 | 7 | - A set of policy/stratigy/algorithm defined into objects and those policis 8 | are interchanged during runtime inside context object based on context values. 9 | 10 | - This pattern is compatable with Open close principle (OCP) purpose is class is open for extension but close for modification 11 | 12 | - This pattern uses composition instead of inheritence. Behaviours are defined in separate interfaces and classes. Behaviour can be 13 | changed without breaking the classes that use it. Behaviour can be changed at runtime as wel as design time. 14 | 15 | ------------------------------------------------------------------------------------------- 16 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/Strategy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Strategy/Strategy.jpg -------------------------------------------------------------------------------- /Src/TheDesignPatterns/Strategy/Usecase_Football.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/Strategy/Usecase_Football.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/TemplateMethod/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | 3 | - Overview: 4 | 5 | - Behaviral Design Pattern. 6 | 7 | - Define structure, sequece of a algorithm/prcess/steps. 8 | 9 | - Child classes will be implement the steps without changing the structure. 10 | 11 | - Point to be noted that steps are fixed but implementation may vary. 12 | 13 | - Mostly use Framework development. 14 | 15 | - Very similar to factory method. The differce is factory method create object, 16 | template method define behaviour. 17 | 18 | - Implementation Procedure: 19 | 20 | - Define Steps in Base/Super class. 21 | 22 | - Implements steps in Sub/Child classes. 23 | 24 | - Advantages: 25 | 26 | - More flexible to change logic without structural change. 27 | 28 | ---------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Src/TheDesignPatterns/TemplateMethod/TemplateMethod.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace TheDesignPatterns.TemplateMethod 4 | { 5 | public abstract class Document 6 | { 7 | protected StringBuilder Docuemnt; 8 | 9 | public Document(StringBuilder docuemnt) 10 | { 11 | this.Docuemnt = docuemnt; 12 | } 13 | 14 | public string GenerateDocument() 15 | { 16 | CreateHeaderSection(); 17 | CreateBodySection(); 18 | CreateFooterSection(); 19 | 20 | return Docuemnt.ToString(); 21 | } 22 | 23 | protected abstract void CreateHeaderSection(); 24 | 25 | protected abstract void CreateBodySection(); 26 | 27 | 28 | protected abstract void CreateFooterSection(); 29 | 30 | } 31 | 32 | public class XmlDocument : Document 33 | { 34 | public XmlDocument(StringBuilder docuemnt) : base(docuemnt) 35 | { 36 | } 37 | 38 | protected override void CreateBodySection() 39 | { 40 | Docuemnt.Append($"This is Document Body."); 41 | } 42 | 43 | protected override void CreateFooterSection() 44 | { 45 | Docuemnt.Append($"
This is Document Footer.
"); 46 | } 47 | 48 | protected override void CreateHeaderSection() 49 | { 50 | Docuemnt.Append($"
This is Document Header.
"); 51 | } 52 | } 53 | 54 | public class JsonDocument : Document 55 | { 56 | public JsonDocument(StringBuilder docuemnt) : base(docuemnt) 57 | { 58 | } 59 | 60 | protected override void CreateBodySection() 61 | { 62 | Docuemnt.Append(@"""body"":""This is Document Body."","); 63 | } 64 | 65 | protected override void CreateFooterSection() 66 | { 67 | Docuemnt.Append(@"""footer"": ""This is Document Footer.""}"); 68 | } 69 | 70 | protected override void CreateHeaderSection() 71 | { 72 | Docuemnt.Append(@"{""header"": ""This is Document Header."","); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/TemplateMethod/TemplateMethod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/Src/TheDesignPatterns/TemplateMethod/TemplateMethod.png -------------------------------------------------------------------------------- /Src/TheDesignPatterns/TemplateMethod/TemplateMethodTest.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using System.Text; 3 | using System.Xml.Linq; 4 | using Xunit; 5 | 6 | namespace TheDesignPatterns.TemplateMethod 7 | { 8 | public class TemplateMethodTest 9 | { 10 | [Fact] 11 | public void ShouldCreateXmlDocument() 12 | { 13 | var documentBuilder = new StringBuilder(); 14 | Document document = new XmlDocument(documentBuilder); 15 | 16 | var xmlData = document.GenerateDocument(); 17 | 18 | xmlData.Should().NotBeNullOrEmpty(); 19 | var xDoc = XDocument.Parse(xmlData); 20 | xDoc.Should().NotBeNull(); 21 | } 22 | 23 | 24 | [Fact] 25 | public void ShouldCreateJsonDocument() 26 | { 27 | var documentBuilder = new StringBuilder(); 28 | Document document = new JsonDocument(documentBuilder); 29 | 30 | var jsonData = document.GenerateDocument(); 31 | 32 | jsonData.Should().NotBeNullOrEmpty(); 33 | var jsonDoc= System.Text.Json.JsonDocument.Parse(jsonData); 34 | jsonDoc.Should().NotBeNull(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Src/TheDesignPatterns/TheDesignPatterns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/dpc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/docs/dpc.jpg -------------------------------------------------------------------------------- /docs/dpt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibsql/TheDesignPatterns/863129d04640655f03ecbf4e881efe6e0dc7d3cf/docs/dpt.jpg --------------------------------------------------------------------------------