├── .gitignore ├── CSharpDesignPatterns.sln ├── Engine ├── ActiveRecordPattern │ ├── Customer.cs │ └── READ_ME.txt ├── BuilderPattern │ ├── NonPatternVersion │ │ └── Report.cs │ ├── PatternVersion │ │ ├── Report.cs │ │ └── ReportBuilder.cs │ └── READ_ME.txt ├── CommandPattern │ ├── BaseTransaction.cs │ ├── NonPatternVersion │ │ └── Account.cs │ ├── PatternVersion │ │ ├── Account.cs │ │ ├── Deposit.cs │ │ ├── ITransaction.cs │ │ ├── TransactionManager.cs │ │ ├── Transfer.cs │ │ └── Withdraw.cs │ ├── PatternVersion_WithUndo │ │ ├── Account.cs │ │ ├── Deposit.cs │ │ ├── Enums.cs │ │ ├── ITransaction.cs │ │ ├── TransactionManager.cs │ │ ├── Transfer.cs │ │ └── Withdraw.cs │ └── READ_ME.txt ├── CompositionOverInheritance │ ├── Composition_AFTER │ │ ├── Monster.cs │ │ └── MonsterFactory.cs │ ├── Composition_BEFORE │ │ ├── Monster.cs │ │ └── MonsterFactory.cs │ ├── Inheritance_AFTER │ │ ├── BitingKickingMonster.cs │ │ ├── BitingKickingPunchingMonster.cs │ │ ├── BitingMonster.cs │ │ ├── BitingPunchingMonster.cs │ │ ├── KickingMonster.cs │ │ ├── KickingPunchingMonster.cs │ │ ├── Monster.cs │ │ ├── MonsterFactory.cs │ │ └── PunchingMonster.cs │ ├── Inheritance_BEFORE │ │ └── Monster.cs │ └── READ_ME.txt ├── DataMapperPattern │ ├── Customer.cs │ ├── CustomerDataMapper.cs │ └── READ_ME.txt ├── DependencyInversionPattern │ ├── NonPatternVersion │ │ ├── Player.cs │ │ └── PlayerDataMapper.cs │ ├── PatternVersion │ │ ├── IPlayerDataMapper.cs │ │ ├── Player.cs │ │ └── PlayerDataMapper.cs │ └── READ_ME.txt ├── Engine.csproj ├── FactoryPattern │ ├── NonPatternVersion │ │ └── Player.cs │ ├── PatternVersion_ExternalFactory │ │ ├── Player.cs │ │ └── PlayerFactory.cs │ ├── PatternVersion_InternalFactory │ │ └── Player.cs │ ├── PatternVersion_MultipleDatatypes │ │ ├── FlyingMonster.cs │ │ ├── LandMonster.cs │ │ ├── Monster.cs │ │ ├── MonsterFactory.cs │ │ └── SeaMonster.cs │ └── READ_ME.txt ├── LICENSE.txt ├── MVVMPattern │ ├── PatternVersion │ │ ├── Models │ │ │ └── AccountModel.cs │ │ └── ViewModels │ │ │ └── AccountCreationViewModel.cs │ └── READ_ME.txt ├── MementoPattern │ ├── BetterMemento │ │ └── Customer.cs │ ├── MultipleMemento │ │ └── Customer.cs │ ├── READ_ME.txt │ └── SimpleMemento │ │ └── Customer.cs ├── Properties │ └── AssemblyInfo.cs ├── PrototypePattern │ ├── NonPatternVersion │ │ └── Monster.cs │ ├── PatternVersion_Complex │ │ ├── LootTableEntry.cs │ │ └── Monster.cs │ ├── PatternVersion_Simple │ │ └── Monster.cs │ └── READ_ME.txt ├── PublishSubscribePattern │ ├── NonPatternVersion │ │ ├── Models │ │ │ ├── Location.cs │ │ │ └── Player.cs │ │ └── ViewModels │ │ │ └── GameSession.cs │ ├── PatternVersion │ │ ├── Models │ │ │ ├── Location.cs │ │ │ └── Player.cs │ │ └── ViewModels │ │ │ └── GameSession.cs │ ├── PatternVersion_CustomEventArgs │ │ ├── Common │ │ │ └── PlayerKilledEventArgs.cs │ │ ├── Models │ │ │ ├── Location.cs │ │ │ └── Player.cs │ │ └── ViewModels │ │ │ └── GameSession.cs │ ├── PatternVersion_WithEvent │ │ ├── Models │ │ │ ├── Location.cs │ │ │ └── Player.cs │ │ └── ViewModels │ │ │ └── GameSession.cs │ └── READ_ME.txt ├── READ_ME.txt ├── SingletonPattern │ ├── NonPatternVersion │ │ ├── Customer.cs │ │ └── Logger.cs │ ├── PatternVersion_DoubleLock │ │ └── Logger.cs │ ├── PatternVersion_StaticInitialization │ │ └── Logger.cs │ └── READ_ME.txt ├── StrategyPattern │ ├── NonPatternVersion_MultipleMethods │ │ └── Calculator.cs │ ├── NonPatternVersion_SingleMethod │ │ └── Calculator.cs │ ├── PatternVersion │ │ ├── AverageByMean.cs │ │ ├── AverageByMedian.cs │ │ ├── Calculator.cs │ │ └── IAveragingMethod.cs │ └── READ_ME.txt └── WrapperFacadePattern │ ├── NonPatternVersion_Complex │ └── MyClassForFacade.cs │ ├── NonPatternVersion_Medium │ └── MyClassForFacade.cs │ ├── NonPatternVersion_Simple │ └── MyClassForFacade.cs │ ├── PatternVersion │ ├── EmailCreator.cs │ ├── IEmailFluentInterface.cs │ └── MyClassForFacade.cs │ └── READ_ME.txt ├── LICENSE ├── README.md ├── TestEngine ├── BuilderPattern │ ├── NonPatternVersion │ │ └── TestNonPatternReport.cs │ └── PatternVersion │ │ └── TestPatternReport.cs ├── CommandPattern │ ├── PatternVersion │ │ └── TestCommandPattern.cs │ └── PatternVersion_WithUndo │ │ └── TestCommandPattern.cs ├── CompositionOverInheritance │ ├── Composition │ │ └── TestMonsterFactory.cs │ └── Inheritance │ │ └── TestMonsterFactory.cs ├── DependencyInversionPattern │ ├── NonPatternVersion │ │ └── TestPlayer.cs │ └── PatternVersion │ │ ├── MockPlayerDataMapper.cs │ │ └── TestPlayer.cs ├── FactoryPattern │ ├── TestFactoryPattern_NonPatternVersion.cs │ ├── TestFactoryPattern_PatternVersion_ExternalFactory.cs │ ├── TestFactoryPattern_PatternVersion_InternalFactory.cs │ └── TestFactoryPattern_PatternVersion_MultipleDatatypes.cs ├── MVVMPattern │ └── TestMVVMPattern.cs ├── MementoPattern │ ├── MementoPattern_BetterMemento.cs │ ├── MementoPattern_MultipleMemento.cs │ └── MementoPattern_SimpleMemento.cs ├── Properties │ └── AssemblyInfo.cs ├── PrototypePattern │ ├── NonPatternVersion │ │ └── TestMonster.cs │ └── PatternVersion_Simple │ │ └── TestMonster.cs ├── StrategyPattern │ ├── NonPatternVersion_MultipleMethods │ │ └── TestCalculator.cs │ ├── NonPatternVersion_SingleMethod │ │ └── TestCalculator.cs │ └── PatternVersion │ │ └── TestCalculator.cs └── TestEngine.csproj ├── WorckbenchWinForms ├── App.config ├── MVVMPattern │ └── PatternVersion │ │ ├── AccountCreationView.Designer.cs │ │ ├── AccountCreationView.cs │ │ └── AccountCreationView.resx ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── WorckbenchWinForms.csproj ├── Workbench ├── App.config ├── Form1.Designer.cs ├── Form1.cs ├── Form1.resx ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── Workbench.csproj └── WorkbenchWPF ├── App.config ├── App.xaml ├── App.xaml.cs ├── MVVMPattern ├── NonPatternVersion │ ├── AccountCreationView.xaml │ └── AccountCreationView.xaml.cs └── PatternVersion │ ├── AccountCreationView.xaml │ └── AccountCreationView.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings └── WorkbenchWPF.csproj /.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 | 25 | # Visual Studio 2015 cache/options directory 26 | .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 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | #Subversion 255 | *.svn 256 | .cr/Settings.xml -------------------------------------------------------------------------------- /CSharpDesignPatterns.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2006 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine.csproj", "{25D0207B-A871-4EF6-A23B-1FF7B15306FE}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestEngine", "TestEngine\TestEngine.csproj", "{C5FB76AA-6B81-4EDD-AB62-4786EE82440D}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workbench", "Workbench\Workbench.csproj", "{A3102E09-45C1-482E-8650-48CE48B3FBB4}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkbenchWPF", "WorkbenchWPF\WorkbenchWPF.csproj", "{6564A597-708D-4EB8-B41B-1922B3AA99BF}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorckbenchWinForms", "WorckbenchWinForms\WorckbenchWinForms.csproj", "{FABF680C-2A7C-4011-ADBE-BD1A5B612F0D}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {25D0207B-A871-4EF6-A23B-1FF7B15306FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {25D0207B-A871-4EF6-A23B-1FF7B15306FE}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {25D0207B-A871-4EF6-A23B-1FF7B15306FE}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {25D0207B-A871-4EF6-A23B-1FF7B15306FE}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {C5FB76AA-6B81-4EDD-AB62-4786EE82440D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {C5FB76AA-6B81-4EDD-AB62-4786EE82440D}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {C5FB76AA-6B81-4EDD-AB62-4786EE82440D}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C5FB76AA-6B81-4EDD-AB62-4786EE82440D}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {A3102E09-45C1-482E-8650-48CE48B3FBB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {A3102E09-45C1-482E-8650-48CE48B3FBB4}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {A3102E09-45C1-482E-8650-48CE48B3FBB4}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {A3102E09-45C1-482E-8650-48CE48B3FBB4}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {6564A597-708D-4EB8-B41B-1922B3AA99BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {6564A597-708D-4EB8-B41B-1922B3AA99BF}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {6564A597-708D-4EB8-B41B-1922B3AA99BF}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {6564A597-708D-4EB8-B41B-1922B3AA99BF}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {FABF680C-2A7C-4011-ADBE-BD1A5B612F0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {FABF680C-2A7C-4011-ADBE-BD1A5B612F0D}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {FABF680C-2A7C-4011-ADBE-BD1A5B612F0D}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {FABF680C-2A7C-4011-ADBE-BD1A5B612F0D}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | VisualSVNWorkingCopyRoot = . 48 | SolutionGuid = {3E208DF4-40BE-418E-899A-7065EBF7B0EC} 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /Engine/ActiveRecordPattern/Customer.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | 4 | namespace Engine.ActiveRecordPattern 5 | { 6 | public class Customer 7 | { 8 | private const string CONNECTION_STRING = 9 | "Data Source=(local);Initial Catalog=DesignPatterns;Integrated Security=True"; 10 | 11 | public int ID { get; set; } 12 | public string Name { get; set; } 13 | public bool IsPremiumMember { get; set; } 14 | 15 | // The constructor could be made "private", 16 | // with instantiation handled by static functions like "GetByID()". 17 | public Customer(int id, string name, bool isPremiumMember) 18 | { 19 | ID = id; 20 | Name = name; 21 | IsPremiumMember = isPremiumMember; 22 | } 23 | 24 | // This static method acts like an object factory for Customer objects, 25 | // reading the values from the database and creating the object. 26 | // 27 | // So, the code to get a customer from the database might be: 28 | // 29 | // Customer.GetByID(123); 30 | // 31 | public static Customer GetByID(int id) 32 | { 33 | using(SqlConnection connection = new SqlConnection(CONNECTION_STRING)) 34 | { 35 | connection.Open(); 36 | 37 | using(SqlCommand command = connection.CreateCommand()) 38 | { 39 | command.CommandType = CommandType.Text; 40 | 41 | command.CommandText = "SELECT TOP 1 * FROM [Customer] WHERE [ID] = @ID"; 42 | command.Parameters.AddWithValue("@ID", id); 43 | 44 | SqlDataReader reader = command.ExecuteReader(); 45 | 46 | // If the query returned a row, create the Customer object and return it. 47 | if(reader.HasRows) 48 | { 49 | reader.Read(); 50 | 51 | string name = (string)reader["Name"]; 52 | bool isPremiumMember = (bool)reader["IsPremiumMember"]; 53 | 54 | return new Customer(id, name, isPremiumMember); 55 | } 56 | } 57 | } 58 | 59 | return null; 60 | } 61 | 62 | public void Save() 63 | { 64 | // This method needs to handle INSERT (new Customer) and UPDATE (existing Customer). 65 | // Or, you would need to create two separate functions, and call them when appropriate. 66 | 67 | // This function would not need to receive a parameter, with the Customer object. 68 | // It's inside the Customer object, so all the property values are already available to it. 69 | 70 | // Pretend there is code here to do the insert and/or update to the database. 71 | } 72 | 73 | public void Delete() 74 | { 75 | using(SqlConnection connection = new SqlConnection(CONNECTION_STRING)) 76 | { 77 | connection.Open(); 78 | 79 | using(SqlCommand command = connection.CreateCommand()) 80 | { 81 | command.CommandType = CommandType.Text; 82 | 83 | command.CommandText = "DELETE FROM [Customer] WHERE [ID] = @ID"; 84 | // This method uses the ID value from this object's property. 85 | // This function didn't need to receive that value from a parameter. 86 | command.Parameters.AddWithValue("@ID", ID); 87 | 88 | command.ExecuteNonQuery(); 89 | } 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Engine/ActiveRecordPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Active Record Design Pattern 2 | 3 | This design pattern is one technique to handle creating objects from data in your database, and updating the database with changed values. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-data-mapper-and-active-record/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=xlSZDw5j4GM 8 | 9 | NOTE: This pattern does not have unit tests in the TestEngine project, because the code sample requires a database. 10 | 11 | Related/similar design patterns: 12 | Data Mapper 13 | -------------------------------------------------------------------------------- /Engine/BuilderPattern/NonPatternVersion/Report.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.BuilderPattern.NonPatternVersion 4 | { 5 | public class Report 6 | { 7 | public enum SortingMethod 8 | { 9 | BySalesperson, 10 | ByTaxCategory 11 | } 12 | 13 | private DateTime _fromDate; 14 | private DateTime _toDate; 15 | private bool _includeReturnedOrders; 16 | private bool _includeUnshippedOrders; 17 | private SortingMethod _sortBy; 18 | 19 | public Report(DateTime from, DateTime to, 20 | bool includeReturnedOrders, bool includeUnshippedOrders, SortingMethod sortBy) 21 | { 22 | _fromDate = from; 23 | _toDate = to; 24 | _includeReturnedOrders = includeReturnedOrders; 25 | _includeUnshippedOrders = includeUnshippedOrders; 26 | _sortBy = sortBy; 27 | } 28 | 29 | public object CreatePDFReport() 30 | { 31 | // Pretend this object is a PDF report, 32 | // built for the sales that match the passed-in constructor parameters. 33 | return new object(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Engine/BuilderPattern/PatternVersion/Report.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.BuilderPattern.PatternVersion 4 | { 5 | public class Report 6 | { 7 | public enum SortingMethod 8 | { 9 | BySalesperson, 10 | ByTaxCategory 11 | } 12 | 13 | private DateTime _fromDate; 14 | private DateTime _toDate; 15 | private bool _includeReturnedOrders; 16 | private bool _includeUnshippedOrders; 17 | private SortingMethod _sortBy; 18 | 19 | public Report(DateTime from, DateTime to, 20 | bool includeReturnedOrders, bool includeUnshippedOrders, SortingMethod sortBy) 21 | { 22 | _fromDate = from; 23 | _toDate = to; 24 | _includeReturnedOrders = includeReturnedOrders; 25 | _includeUnshippedOrders = includeUnshippedOrders; 26 | _sortBy = sortBy; 27 | } 28 | 29 | public object CreatePDFReport() 30 | { 31 | // Pretend this object is a PDF report, 32 | // built for the sales that match the passed-in constructor parameters. 33 | return new object(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Engine/BuilderPattern/PatternVersion/ReportBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.BuilderPattern.PatternVersion 4 | { 5 | public class ReportBuilder 6 | { 7 | private static Report CreateTaxReport(DateTime from, DateTime to) 8 | { 9 | return new Report(from, to, false, true, Report.SortingMethod.ByTaxCategory); 10 | } 11 | 12 | public static Report CreateMonthTaxReport(int month, int year) 13 | { 14 | return CreateTaxReport(new DateTime(year, month, 1), 15 | new DateTime(year, month, 1).AddMonths(1).AddSeconds(-1)); 16 | } 17 | 18 | public static Report CreateYearTaxReport(int year) 19 | { 20 | return CreateTaxReport(new DateTime(year, 1, 1), 21 | new DateTime(year, 12, 31)); 22 | } 23 | 24 | private static Report CreateCommissionReport(DateTime from, DateTime to) 25 | { 26 | return new Report(from, to, false, false, Report.SortingMethod.BySalesperson); 27 | } 28 | 29 | public static Report CreateMonthCommissionReport(int month, int year) 30 | { 31 | return CreateCommissionReport(new DateTime(year, month, 1), 32 | new DateTime(year, month, 1).AddMonths(1).AddSeconds(-1)); 33 | } 34 | 35 | public static Report CreateYearCommissionReport(int year) 36 | { 37 | return CreateCommissionReport(new DateTime(year, 1, 1), 38 | new DateTime(year, 12, 31)); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Engine/BuilderPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Builder Design Pattern 2 | 3 | This design pattern simplifies instantiating objects, which might have many different ways to be built. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-builder-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=38qbJT8FTRU 8 | 9 | Related/similar design patterns: 10 | Composition over Inheritance http://scottlilly.com/c-design-patterns-composition-over-inheritance/ 11 | Wrapper/Facade http://scottlilly.com/c-design-patterns-the-wrapperfacade-pattern/ 12 | Factory http://scottlilly.com/c-design-patterns-the-factory-pattern/ 13 | -------------------------------------------------------------------------------- /Engine/CommandPattern/BaseTransaction.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern 2 | { 3 | public abstract class BaseTransaction 4 | { 5 | public bool IsCompleted { get; set; } 6 | 7 | public abstract void Execute(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Engine/CommandPattern/NonPatternVersion/Account.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CommandPattern.NonPatternVersion 4 | { 5 | // This is a sample of a non-command version, where functions are executed on an object immediately. 6 | public class Account 7 | { 8 | public string OwnerName { get; set; } 9 | public decimal Balance { get; set; } 10 | 11 | public Account(string ownerName, decimal balance) 12 | { 13 | OwnerName = ownerName; 14 | Balance = balance; 15 | } 16 | 17 | public void Deposit(decimal amount) 18 | { 19 | Balance += amount; 20 | } 21 | 22 | public void Withdraw(decimal amount) 23 | { 24 | if(amount > Balance) 25 | { 26 | throw new ArgumentOutOfRangeException("Overdraft error"); 27 | } 28 | 29 | Balance -= amount; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion/Account.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion 2 | { 3 | public class Account 4 | { 5 | public string OwnerName { get; set; } 6 | public decimal Balance { get; set; } 7 | 8 | public Account(string ownerName, decimal balance) 9 | { 10 | OwnerName = ownerName; 11 | Balance = balance; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion/Deposit.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion 2 | { 3 | public class Deposit : ITransaction 4 | { 5 | private readonly Account _account; 6 | private readonly decimal _amount; 7 | 8 | public bool IsCompleted { get; set; } 9 | 10 | public Deposit(Account account, decimal amount) 11 | { 12 | _account = account; 13 | _amount = amount; 14 | 15 | IsCompleted = false; 16 | } 17 | 18 | public void Execute() 19 | { 20 | _account.Balance += _amount; 21 | 22 | IsCompleted = true; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion/ITransaction.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion 2 | { 3 | public interface ITransaction 4 | { 5 | bool IsCompleted { get; set; } 6 | void Execute(); 7 | } 8 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion/TransactionManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Engine.CommandPattern.PatternVersion 5 | { 6 | public class TransactionManager 7 | { 8 | private readonly List _transactions = new List(); 9 | 10 | public bool HasPendingTransactions 11 | { 12 | get { return _transactions.Any(x => !x.IsCompleted); } 13 | } 14 | 15 | public void AddTransaction(ITransaction transaction) 16 | { 17 | _transactions.Add(transaction); 18 | } 19 | 20 | public void ProcessPendingTransactions() 21 | { 22 | // Apply transactions in the order they were added. 23 | foreach(ITransaction transaction in _transactions.Where(x => !x.IsCompleted)) 24 | { 25 | transaction.Execute(); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion/Transfer.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion 2 | { 3 | public class Transfer : ITransaction 4 | { 5 | private readonly decimal _amount; 6 | private readonly Account _fromAccount; 7 | private readonly Account _toAccount; 8 | 9 | public bool IsCompleted { get; set; } 10 | 11 | public Transfer(Account fromAccount, Account toAccount, decimal amount) 12 | { 13 | _fromAccount = fromAccount; 14 | _toAccount = toAccount; 15 | _amount = amount; 16 | 17 | IsCompleted = false; 18 | } 19 | 20 | public void Execute() 21 | { 22 | if(_fromAccount.Balance >= _amount) 23 | { 24 | _fromAccount.Balance -= _amount; 25 | _toAccount.Balance += _amount; 26 | 27 | IsCompleted = true; 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion/Withdraw.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion 2 | { 3 | public class Withdraw : ITransaction 4 | { 5 | private readonly Account _account; 6 | private readonly decimal _amount; 7 | 8 | public bool IsCompleted { get; set; } 9 | 10 | public Withdraw(Account account, decimal amount) 11 | { 12 | _account = account; 13 | _amount = amount; 14 | 15 | IsCompleted = false; 16 | } 17 | 18 | public void Execute() 19 | { 20 | if(_account.Balance >= _amount) 21 | { 22 | _account.Balance -= _amount; 23 | 24 | IsCompleted = true; 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/Account.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion_WithUndo 2 | { 3 | public class Account 4 | { 5 | public string OwnerName { get; set; } 6 | public decimal Balance { get; set; } 7 | 8 | public Account(string ownerName, decimal balance) 9 | { 10 | OwnerName = ownerName; 11 | Balance = balance; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/Deposit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CommandPattern.PatternVersion_WithUndo 4 | { 5 | public class Deposit : ITransaction 6 | { 7 | private readonly Account _account; 8 | private readonly decimal _amount; 9 | 10 | public int ID { get; set; } 11 | public DateTime CreatedOn { get; set; } 12 | public CommandState Status { get; set; } 13 | 14 | public Deposit(int id, Account account, decimal amount) 15 | { 16 | ID = id; 17 | CreatedOn = DateTime.UtcNow; 18 | 19 | _account = account; 20 | _amount = amount; 21 | 22 | Status = CommandState.Unprocessed; 23 | } 24 | 25 | public void Execute() 26 | { 27 | _account.Balance += _amount; 28 | 29 | Status = CommandState.ExecuteSucceeded; 30 | } 31 | 32 | public void Undo() 33 | { 34 | if(_account.Balance >= _amount) 35 | { 36 | _account.Balance -= _amount; 37 | 38 | Status = CommandState.UndoSucceeded; 39 | } 40 | else 41 | { 42 | Status = CommandState.UndoFailed; 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CommandPattern.PatternVersion_WithUndo 2 | { 3 | public enum CommandState 4 | { 5 | Unprocessed, 6 | ExecuteFailed, 7 | ExecuteSucceeded, 8 | UndoFailed, 9 | UndoSucceeded 10 | } 11 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/ITransaction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CommandPattern.PatternVersion_WithUndo 4 | { 5 | public interface ITransaction 6 | { 7 | int ID { get; set; } 8 | DateTime CreatedOn { get; set; } 9 | CommandState Status { get; set; } 10 | void Execute(); 11 | void Undo(); 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/TransactionManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Engine.CommandPattern.PatternVersion_WithUndo 6 | { 7 | public class TransactionManager 8 | { 9 | private readonly List _transactions = new List(); 10 | 11 | public bool HasPendingTransactions 12 | { 13 | get 14 | { 15 | return _transactions.Any(x => 16 | x.Status == CommandState.Unprocessed || 17 | x.Status == CommandState.ExecuteFailed || 18 | x.Status == CommandState.UndoFailed); 19 | } 20 | } 21 | 22 | public void AddTransaction(ITransaction transaction) 23 | { 24 | _transactions.Add(transaction); 25 | } 26 | 27 | public void ProcessPendingTransactions() 28 | { 29 | // Execute transactions that are unprocessed, or had a previous Execute fail. 30 | foreach(ITransaction transaction in _transactions.Where(x => 31 | x.Status == CommandState.Unprocessed || 32 | x.Status == CommandState.ExecuteFailed)) 33 | { 34 | transaction.Execute(); 35 | } 36 | 37 | // Retry the Undo, for transactions that had a previous Undo fail. 38 | foreach(ITransaction transaction in _transactions.Where(x => 39 | x.Status == CommandState.UndoFailed)) 40 | { 41 | transaction.Undo(); 42 | } 43 | } 44 | 45 | public void UndoTransactionNumber(int id) 46 | { 47 | // Get the Command object that has the passed ID. 48 | // If it does not exist in _transactions, the result will be null (default, for this object type). 49 | ITransaction transaction = _transactions.FirstOrDefault(x => x.ID == id); 50 | 51 | if(transaction == null) 52 | { 53 | throw new ArgumentException(string.Format("There is no transaction number: {0}", id)); 54 | } 55 | 56 | if(transaction.Status != CommandState.ExecuteSucceeded) 57 | { 58 | throw new ArgumentException("Can only undo transactions that have been successfully executed."); 59 | } 60 | 61 | // We have a valid transaction, so perform the "undo". 62 | transaction.Undo(); 63 | 64 | // Remove the transaction, if it was successfully completed. 65 | if(transaction.Status == CommandState.UndoSucceeded) 66 | { 67 | _transactions.Remove(transaction); 68 | } 69 | } 70 | 71 | public void RemoveOldTransactions() 72 | { 73 | // Remove transaction that have been Executed, and are more than 15 days old. 74 | _transactions.RemoveAll(x => 75 | x.Status == CommandState.ExecuteSucceeded && 76 | (DateTime.UtcNow - x.CreatedOn).Days > 15); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/Transfer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CommandPattern.PatternVersion_WithUndo 4 | { 5 | public class Transfer : ITransaction 6 | { 7 | private readonly decimal _amount; 8 | private readonly Account _fromAccount; 9 | private readonly Account _toAccount; 10 | 11 | public int ID { get; set; } 12 | public DateTime CreatedOn { get; set; } 13 | public CommandState Status { get; set; } 14 | 15 | public Transfer(int id, Account fromAccount, Account toAccount, decimal amount) 16 | { 17 | ID = id; 18 | CreatedOn = DateTime.UtcNow; 19 | 20 | _fromAccount = fromAccount; 21 | _toAccount = toAccount; 22 | _amount = amount; 23 | 24 | Status = CommandState.Unprocessed; 25 | } 26 | 27 | public void Execute() 28 | { 29 | if(_fromAccount.Balance >= _amount) 30 | { 31 | _fromAccount.Balance -= _amount; 32 | _toAccount.Balance += _amount; 33 | 34 | Status = CommandState.ExecuteSucceeded; 35 | } 36 | else 37 | { 38 | Status = CommandState.ExecuteFailed; 39 | } 40 | } 41 | 42 | public void Undo() 43 | { 44 | // Remove the money from the original "to" account, 45 | // and add it back to the original "from" account. 46 | if(_toAccount.Balance >= _amount) 47 | { 48 | _toAccount.Balance -= _amount; 49 | _fromAccount.Balance += _amount; 50 | 51 | Status = CommandState.UndoSucceeded; 52 | } 53 | else 54 | { 55 | Status = CommandState.UndoFailed; 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/PatternVersion_WithUndo/Withdraw.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CommandPattern.PatternVersion_WithUndo 4 | { 5 | public class Withdraw : ITransaction 6 | { 7 | private readonly Account _account; 8 | private readonly decimal _amount; 9 | 10 | public int ID { get; set; } 11 | public DateTime CreatedOn { get; set; } 12 | public CommandState Status { get; set; } 13 | 14 | public Withdraw(int id, Account account, decimal amount) 15 | { 16 | ID = id; 17 | CreatedOn = DateTime.UtcNow; 18 | 19 | _account = account; 20 | _amount = amount; 21 | 22 | Status = CommandState.Unprocessed; 23 | } 24 | 25 | public void Execute() 26 | { 27 | if(_account.Balance >= _amount) 28 | { 29 | _account.Balance -= _amount; 30 | 31 | Status = CommandState.ExecuteSucceeded; 32 | } 33 | else 34 | { 35 | Status = CommandState.ExecuteFailed; 36 | } 37 | } 38 | 39 | public void Undo() 40 | { 41 | _account.Balance += _amount; 42 | 43 | Status = CommandState.UndoSucceeded; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Engine/CommandPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Command Design Pattern 2 | 3 | This design pattern is one technique to handle creating objects from data in your database, and updating the database with changed values. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-command-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=t_frFWqrnJE 8 | 9 | Related/similar design patterns: 10 | -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Composition_AFTER/Monster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Engine.CompositionOverInheritance.Composition_AFTER 5 | { 6 | public class Monster 7 | { 8 | public enum AttackType 9 | { 10 | Biting, 11 | Kicking, 12 | Punching, 13 | Spitting 14 | } 15 | 16 | public int HitPoints { get; set; } 17 | public Dictionary AttackTypes { get; set; } 18 | 19 | // These replace the functionality of checking an object's "type", 20 | // to see if it "is" a certain datatype (KickingMonster, BitingMonster, etc.) 21 | public bool CanBite => AttackTypes.ContainsKey(AttackType.Biting); 22 | public bool CanKick => AttackTypes.ContainsKey(AttackType.Kicking); 23 | public bool CanPunch => AttackTypes.ContainsKey(AttackType.Punching); 24 | public bool CanSpit => AttackTypes.ContainsKey(AttackType.Spitting); 25 | 26 | public int BiteDamage 27 | { 28 | get 29 | { 30 | if(CanBite) 31 | { 32 | return AttackTypes[AttackType.Biting]; 33 | } 34 | 35 | throw new NotSupportedException("This monster cannot bite."); 36 | } 37 | } 38 | 39 | public int KickDamage 40 | { 41 | get 42 | { 43 | if(CanKick) 44 | { 45 | return AttackTypes[AttackType.Kicking]; 46 | } 47 | 48 | throw new NotSupportedException("This monster cannot kick."); 49 | } 50 | } 51 | 52 | public int PunchDamage 53 | { 54 | get 55 | { 56 | if(CanPunch) 57 | { 58 | return AttackTypes[AttackType.Punching]; 59 | } 60 | 61 | throw new NotSupportedException("This monster cannot punch."); 62 | } 63 | } 64 | 65 | public int SpitDamage 66 | { 67 | get 68 | { 69 | if(CanSpit) 70 | { 71 | return AttackTypes[AttackType.Spitting]; 72 | } 73 | 74 | throw new NotSupportedException("This monster cannot spit."); 75 | } 76 | } 77 | 78 | public Monster(int hitPoints) 79 | { 80 | HitPoints = hitPoints; 81 | AttackTypes = new Dictionary(); 82 | } 83 | 84 | public void AddAttackType(AttackType attackType, int amountOfDamage) 85 | { 86 | AttackTypes[attackType] = amountOfDamage; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Composition_AFTER/MonsterFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CompositionOverInheritance.Composition_AFTER 4 | { 5 | public class MonsterFactory 6 | { 7 | public enum MonsterType 8 | { 9 | Horse, // BitingKickingMonster 10 | Orc, // BitingKickingPunchingMonster 11 | Crocodile, // BitingMonster 12 | MikeTyson, // BitingPunchingMonster 13 | Cobra, // BitingSpittingMonster 14 | Camel, // KickingSpittingMonster 15 | Kangaroo, // KickingPunchingMonster 16 | MantisShrimp //PunchingMonster 17 | } 18 | 19 | public static Monster CreateMonster(MonsterType monsterType) 20 | { 21 | Monster monster; 22 | 23 | switch(monsterType) 24 | { 25 | case MonsterType.Horse: 26 | monster = new Monster(10); 27 | monster.AddAttackType(Monster.AttackType.Biting, 5); 28 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 29 | break; 30 | case MonsterType.Orc: 31 | monster = new Monster(10); 32 | monster.AddAttackType(Monster.AttackType.Biting, 5); 33 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 34 | monster.AddAttackType(Monster.AttackType.Punching, 5); 35 | break; 36 | case MonsterType.Crocodile: 37 | monster = new Monster(10); 38 | monster.AddAttackType(Monster.AttackType.Biting, 5); 39 | break; 40 | case MonsterType.MikeTyson: 41 | monster = new Monster(10); 42 | monster.AddAttackType(Monster.AttackType.Biting, 5); 43 | monster.AddAttackType(Monster.AttackType.Punching, 5); 44 | break; 45 | case MonsterType.Cobra: 46 | monster = new Monster(10); 47 | monster.AddAttackType(Monster.AttackType.Biting, 5); 48 | monster.AddAttackType(Monster.AttackType.Spitting, 5); 49 | break; 50 | case MonsterType.Camel: 51 | monster = new Monster(10); 52 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 53 | monster.AddAttackType(Monster.AttackType.Spitting, 5); 54 | break; 55 | case MonsterType.Kangaroo: 56 | monster = new Monster(10); 57 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 58 | monster.AddAttackType(Monster.AttackType.Punching, 5); 59 | break; 60 | case MonsterType.MantisShrimp: 61 | monster = new Monster(10); 62 | monster.AddAttackType(Monster.AttackType.Punching, 5); 63 | break; 64 | default: 65 | throw new ArgumentException(); 66 | } 67 | 68 | return monster; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Composition_BEFORE/Monster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Engine.CompositionOverInheritance.Composition_BEFORE 5 | { 6 | public class Monster 7 | { 8 | public enum AttackType 9 | { 10 | Biting, 11 | Kicking, 12 | Punching 13 | } 14 | 15 | public int HitPoints { get; set; } 16 | public Dictionary AttackTypes { get; set; } 17 | 18 | // These replace the functionality of checking an object's "type", 19 | // to see if it "is" a certain datatype (KickingMonster, BitingMonster, etc.) 20 | public bool CanBite => AttackTypes.ContainsKey(AttackType.Biting); 21 | public bool CanKick => AttackTypes.ContainsKey(AttackType.Kicking); 22 | public bool CanPunch => AttackTypes.ContainsKey(AttackType.Punching); 23 | 24 | public int BiteDamage 25 | { 26 | get 27 | { 28 | if(CanBite) 29 | { 30 | return AttackTypes[AttackType.Biting]; 31 | } 32 | 33 | throw new NotSupportedException("This monster cannot bite."); 34 | } 35 | } 36 | 37 | public int KickDamage 38 | { 39 | get 40 | { 41 | if(CanKick) 42 | { 43 | return AttackTypes[AttackType.Kicking]; 44 | } 45 | 46 | throw new NotSupportedException("This monster cannot kick."); 47 | } 48 | } 49 | 50 | public int PunchDamage 51 | { 52 | get 53 | { 54 | if(CanPunch) 55 | { 56 | return AttackTypes[AttackType.Punching]; 57 | } 58 | 59 | throw new NotSupportedException("This monster cannot punch."); 60 | } 61 | } 62 | 63 | public Monster(int hitPoints) 64 | { 65 | HitPoints = hitPoints; 66 | AttackTypes = new Dictionary(); 67 | } 68 | 69 | public void AddAttackType(AttackType attackType, int amountOfDamage) 70 | { 71 | AttackTypes[attackType] = amountOfDamage; 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Composition_BEFORE/MonsterFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CompositionOverInheritance.Composition_BEFORE 4 | { 5 | public class MonsterFactory 6 | { 7 | public enum MonsterType 8 | { 9 | Horse, // BitingKickingMonster 10 | Orc, // BitingKickingPunchingMonster 11 | Crocodile, // BitingMonster 12 | MikeTyson, // BitingPunchingMonster 13 | Camel, // KickingMonster 14 | Kangaroo, // KickingPunchingMonster 15 | MantisShrimp //PunchingMonster 16 | } 17 | 18 | public static Monster CreateMonster(MonsterType monsterType) 19 | { 20 | Monster monster; 21 | 22 | switch(monsterType) 23 | { 24 | case MonsterType.Horse: 25 | monster = new Monster(10); 26 | monster.AddAttackType(Monster.AttackType.Biting, 5); 27 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 28 | break; 29 | case MonsterType.Orc: 30 | monster = new Monster(10); 31 | monster.AddAttackType(Monster.AttackType.Biting, 5); 32 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 33 | monster.AddAttackType(Monster.AttackType.Punching, 5); 34 | break; 35 | case MonsterType.Crocodile: 36 | monster = new Monster(10); 37 | monster.AddAttackType(Monster.AttackType.Biting, 5); 38 | break; 39 | case MonsterType.MikeTyson: 40 | monster = new Monster(10); 41 | monster.AddAttackType(Monster.AttackType.Biting, 5); 42 | monster.AddAttackType(Monster.AttackType.Punching, 5); 43 | break; 44 | case MonsterType.Camel: 45 | monster = new Monster(10); 46 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 47 | break; 48 | case MonsterType.Kangaroo: 49 | monster = new Monster(10); 50 | monster.AddAttackType(Monster.AttackType.Kicking, 5); 51 | monster.AddAttackType(Monster.AttackType.Punching, 5); 52 | break; 53 | case MonsterType.MantisShrimp: 54 | monster = new Monster(10); 55 | monster.AddAttackType(Monster.AttackType.Punching, 5); 56 | break; 57 | default: 58 | throw new ArgumentException(); 59 | } 60 | 61 | return monster; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/BitingKickingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class BitingKickingMonster : BitingMonster 4 | { 5 | public int KickDamage { get; set; } 6 | 7 | public BitingKickingMonster(int hitPoints, int biteDamage, int kickDamage) 8 | : base(hitPoints, biteDamage) 9 | { 10 | KickDamage = kickDamage; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/BitingKickingPunchingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class BitingKickingPunchingMonster : BitingMonster 4 | { 5 | public int KickDamage { get; set; } 6 | public int PunchDamage { get; set; } 7 | 8 | public BitingKickingPunchingMonster(int hitPoints, int biteDamage, int kickDamage, int punchDamage) 9 | : base(hitPoints, biteDamage) 10 | { 11 | KickDamage = kickDamage; 12 | PunchDamage = punchDamage; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/BitingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class BitingMonster : Monster 4 | { 5 | public int BiteDamage { get; set; } 6 | 7 | public BitingMonster(int hitPoints, int biteDamage) 8 | : base(hitPoints) 9 | { 10 | BiteDamage = biteDamage; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/BitingPunchingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class BitingPunchingMonster : BitingMonster 4 | { 5 | public int PunchDamage { get; set; } 6 | 7 | public BitingPunchingMonster(int hitPoints, int biteDamage, int punchDamage) 8 | : base(hitPoints, biteDamage) 9 | { 10 | PunchDamage = punchDamage; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/KickingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class KickingMonster : Monster 4 | { 5 | public int KickDamage { get; set; } 6 | 7 | public KickingMonster(int hitPoints, int kickDamage) 8 | : base(hitPoints) 9 | { 10 | KickDamage = kickDamage; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/KickingPunchingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class KickingPunchingMonster : KickingMonster 4 | { 5 | public int PunchDamage { get; set; } 6 | 7 | public KickingPunchingMonster(int hitPoints, int kickDamage, int punchDamage) 8 | : base(hitPoints, kickDamage) 9 | { 10 | PunchDamage = punchDamage; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/Monster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class Monster 4 | { 5 | public int HitPoints { get; set; } 6 | 7 | public Monster(int hitPoints) 8 | { 9 | HitPoints = hitPoints; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/MonsterFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 4 | { 5 | public class MonsterFactory 6 | { 7 | public enum MonsterType 8 | { 9 | Horse, // BitingKickingMonster 10 | Orc, // BitingKickingPunchingMonster 11 | Crocodile, // BitingMonster 12 | MikeTyson, // BitingPunchingMonster 13 | Camel, // KickingMonster 14 | Kangaroo, // KickingPunchingMonster 15 | MantisShrimp //PunchingMonster 16 | } 17 | 18 | public static Monster CreateMonster(MonsterType monsterType) 19 | { 20 | switch(monsterType) 21 | { 22 | case MonsterType.Horse: 23 | return new BitingKickingMonster(10, 5, 5); 24 | case MonsterType.Orc: 25 | return new BitingKickingPunchingMonster(10, 5, 5, 5); 26 | case MonsterType.Crocodile: 27 | return new BitingMonster(10, 5); 28 | case MonsterType.MikeTyson: 29 | return new BitingPunchingMonster(10, 5, 5); 30 | case MonsterType.Camel: 31 | return new KickingMonster(10, 5); 32 | case MonsterType.Kangaroo: 33 | return new KickingPunchingMonster(10, 5, 5); 34 | case MonsterType.MantisShrimp: 35 | return new PunchingMonster(10, 5); 36 | default: 37 | throw new ArgumentException(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_AFTER/PunchingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_AFTER 2 | { 3 | public class PunchingMonster : Monster 4 | { 5 | public int PunchDamage { get; set; } 6 | 7 | public PunchingMonster(int hitPoints, int punchDamage) 8 | : base(hitPoints) 9 | { 10 | PunchDamage = punchDamage; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/Inheritance_BEFORE/Monster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.CompositionOverInheritance.Inheritance_BEFORE 2 | { 3 | public class Monster 4 | { 5 | public int HitPoints { get; set; } 6 | public int AttackDamage { get; set; } 7 | 8 | public Monster(int hitPoints, int attackDamage) 9 | { 10 | HitPoints = hitPoints; 11 | AttackDamage = attackDamage; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Engine/CompositionOverInheritance/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Composition Over Inheritance 2 | 3 | When you want to have similar objects, but with slightly different behavior, you might use inheritance. 4 | Another option is to use object composition - which can be simpler, and easier to expand in the future. 5 | 6 | Website URL: http://scottlilly.com/c-design-patterns-composition-over-inheritance/ 7 | 8 | YouTube video URL: https://www.youtube.com/watch?v=pQm-BqK2fhc 9 | 10 | Related design patterns: 11 | Strategy http://scottlilly.com/c-design-patterns-the-strategy-pattern/ 12 | -------------------------------------------------------------------------------- /Engine/DataMapperPattern/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.DataMapperPattern 2 | { 3 | public class Customer 4 | { 5 | public int ID { get; set; } 6 | public string Name { get; set; } 7 | public bool IsPremiumMember { get; set; } 8 | 9 | public Customer(int id, string name, bool isPremiumMember) 10 | { 11 | ID = id; 12 | Name = name; 13 | IsPremiumMember = isPremiumMember; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Engine/DataMapperPattern/CustomerDataMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | 4 | namespace Engine.DataMapperPattern 5 | { 6 | public class CustomerDataMapper 7 | { 8 | private const string CONNECTION_STRING = 9 | "Data Source=(local);Initial Catalog=DesignPatterns;Integrated Security=True"; 10 | 11 | public static Customer GetByID(int id) 12 | { 13 | using(SqlConnection connection = new SqlConnection(CONNECTION_STRING)) 14 | { 15 | connection.Open(); 16 | 17 | using(SqlCommand command = connection.CreateCommand()) 18 | { 19 | command.CommandType = CommandType.Text; 20 | 21 | command.CommandText = "SELECT TOP 1 * FROM [Customer] WHERE [ID] = @ID"; 22 | command.Parameters.AddWithValue("@ID", id); 23 | 24 | SqlDataReader reader = command.ExecuteReader(); 25 | 26 | // If the query returned a row, create the Customer object and return it. 27 | if(reader.HasRows) 28 | { 29 | reader.Read(); 30 | 31 | var name = (string)reader["Name"]; 32 | var isPremiumMember = (bool)reader["IsPremiumMember"]; 33 | 34 | return new Customer(id, name, isPremiumMember); 35 | } 36 | } 37 | } 38 | 39 | return null; 40 | } 41 | 42 | // Notice that we need to pass in the Customer object (or some information from it) 43 | // to use some of the methods in the DataMapper class. 44 | 45 | public void Save(Customer customer) 46 | { 47 | // This method needs to handle INSERT (new Customer) and UPDATE (existing Customer). 48 | // Or, you would need to create two separate functions, and call them when appropriate. 49 | 50 | // Pretend there is code here to do the insert and/or update to the database. 51 | } 52 | 53 | // We also could have only passed in the ID for this method, 54 | // because that is the only value from the Customer object that this method needs. 55 | public void Delete(Customer customer) 56 | { 57 | using(SqlConnection connection = new SqlConnection(CONNECTION_STRING)) 58 | { 59 | connection.Open(); 60 | 61 | using(SqlCommand command = connection.CreateCommand()) 62 | { 63 | command.CommandType = CommandType.Text; 64 | 65 | command.CommandText = "DELETE FROM [Customer] WHERE [ID] = @ID"; 66 | command.Parameters.AddWithValue("@ID", customer.ID); 67 | 68 | command.ExecuteNonQuery(); 69 | } 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Engine/DataMapperPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Data Mapper Design Pattern 2 | 3 | This design pattern is one technique to handle creating objects from data in your database, and updating the database with changed values. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-data-mapper-and-active-record/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=xlSZDw5j4GM 8 | 9 | NOTE: This pattern does not have unit tests in the TestEngine project, because the code sample requires a database. 10 | 11 | Related/similar design patterns: 12 | Active Record 13 | -------------------------------------------------------------------------------- /Engine/DependencyInversionPattern/NonPatternVersion/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.DependencyInversionPattern.NonPatternVersion 4 | { 5 | public class Player 6 | { 7 | public string Name { get; private set; } 8 | public int ExperiencePoints { get; private set; } 9 | public int Gold { get; private set; } 10 | 11 | public Player(string name, int experiencePoints, int gold) 12 | { 13 | Name = name; 14 | ExperiencePoints = experiencePoints; 15 | Gold = gold; 16 | } 17 | 18 | public static Player CreateNewPlayer(string name) 19 | { 20 | if(string.IsNullOrWhiteSpace(name)) 21 | { 22 | throw new ArgumentException("Player name cannot be empty."); 23 | } 24 | 25 | // Create a Data Mapper object, to use to connect with the database 26 | PlayerDataMapper _playerDataMapper = new PlayerDataMapper(); 27 | 28 | // Throw an exception if there is already a player with this name in the database. 29 | if(_playerDataMapper.PlayerNameExistsInDatabase(name)) 30 | { 31 | throw new ArgumentException("Player name already exists."); 32 | } 33 | 34 | // Add the player to the database. 35 | _playerDataMapper.InsertNewPlayerIntoDatabase(name); 36 | 37 | return new Player(name, 0, 10); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Engine/DependencyInversionPattern/NonPatternVersion/PlayerDataMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | 4 | namespace Engine.DependencyInversionPattern.NonPatternVersion 5 | { 6 | public class PlayerDataMapper 7 | { 8 | private readonly string _connectionString = 9 | "Data Source=(local);Initial Catalog=MyGame;Integrated Security=True"; 10 | 11 | public bool PlayerNameExistsInDatabase(string name) 12 | { 13 | using(SqlConnection connection = new SqlConnection(_connectionString)) 14 | { 15 | connection.Open(); 16 | 17 | using(SqlCommand playersWithThisName = connection.CreateCommand()) 18 | { 19 | playersWithThisName.CommandType = CommandType.Text; 20 | playersWithThisName.CommandText = "SELECT count(*) FROM Player WHERE 'Name' = @Name"; 21 | 22 | playersWithThisName.Parameters.AddWithValue("@Name", name); 23 | 24 | // Get the number of player with this name 25 | var existingRowCount = (int)playersWithThisName.ExecuteScalar(); 26 | 27 | // Result is 0, if no player exists, or 1, if a player already exists 28 | return existingRowCount > 0; 29 | } 30 | } 31 | } 32 | 33 | public void InsertNewPlayerIntoDatabase(string name) 34 | { 35 | using(SqlConnection connection = new SqlConnection(_connectionString)) 36 | { 37 | connection.Open(); 38 | 39 | using(SqlCommand playersWithThisName = connection.CreateCommand()) 40 | { 41 | playersWithThisName.CommandType = CommandType.Text; 42 | playersWithThisName.CommandText = "INSERT INTO Player ([Name]) VALUES (@Name)"; 43 | 44 | playersWithThisName.Parameters.AddWithValue("@Name", name); 45 | 46 | playersWithThisName.ExecuteNonQuery(); 47 | } 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Engine/DependencyInversionPattern/PatternVersion/IPlayerDataMapper.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.DependencyInversionPattern.PatternVersion 2 | { 3 | public interface IPlayerDataMapper 4 | { 5 | bool PlayerNameExistsInDatabase(string name); 6 | void InsertNewPlayerIntoDatabase(string name); 7 | } 8 | } -------------------------------------------------------------------------------- /Engine/DependencyInversionPattern/PatternVersion/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.DependencyInversionPattern.PatternVersion 4 | { 5 | public class Player 6 | { 7 | public string Name { get; private set; } 8 | public int ExperiencePoints { get; private set; } 9 | public int Gold { get; private set; } 10 | 11 | public Player(string name, int experiencePoints, int gold) 12 | { 13 | Name = name; 14 | ExperiencePoints = experiencePoints; 15 | Gold = gold; 16 | } 17 | 18 | public static Player CreateNewPlayer(string name, IPlayerDataMapper playerDataMapper = null) 19 | { 20 | // If a PlayerDataMapper was not passed in, use a real one. 21 | // This allows us to pass in a "mock" PlayerDataMapper (for testing), 22 | // but use a real PlayerDataMapper, when running the program. 23 | if(playerDataMapper == null) 24 | { 25 | playerDataMapper = new PlayerDataMapper(); 26 | } 27 | 28 | if(string.IsNullOrWhiteSpace(name)) 29 | { 30 | throw new ArgumentException("Player name cannot be empty."); 31 | } 32 | 33 | // Throw an exception if there is already a player with this name in the database. 34 | if(playerDataMapper.PlayerNameExistsInDatabase(name)) 35 | { 36 | throw new ArgumentException("Player name already exists."); 37 | } 38 | 39 | // Add the player to the database. 40 | playerDataMapper.InsertNewPlayerIntoDatabase(name); 41 | 42 | return new Player(name, 0, 10); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Engine/DependencyInversionPattern/PatternVersion/PlayerDataMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | 4 | namespace Engine.DependencyInversionPattern.PatternVersion 5 | { 6 | public class PlayerDataMapper : IPlayerDataMapper 7 | { 8 | private readonly string _connectionString = 9 | "Data Source=(local);Initial Catalog=MyGame;Integrated Security=True"; 10 | 11 | public bool PlayerNameExistsInDatabase(string name) 12 | { 13 | using(SqlConnection connection = new SqlConnection(_connectionString)) 14 | { 15 | connection.Open(); 16 | 17 | using(SqlCommand playersWithThisName = connection.CreateCommand()) 18 | { 19 | playersWithThisName.CommandType = CommandType.Text; 20 | playersWithThisName.CommandText = "SELECT count(*) FROM Player WHERE 'Name' = @Name"; 21 | 22 | playersWithThisName.Parameters.AddWithValue("@Name", name); 23 | 24 | // Get the number of player with this name 25 | var existingRowCount = (int)playersWithThisName.ExecuteScalar(); 26 | 27 | // Result is 0, if no player exists, or 1, if a player already exists 28 | return existingRowCount > 0; 29 | } 30 | } 31 | } 32 | 33 | public void InsertNewPlayerIntoDatabase(string name) 34 | { 35 | using(SqlConnection connection = new SqlConnection(_connectionString)) 36 | { 37 | connection.Open(); 38 | 39 | using(SqlCommand playersWithThisName = connection.CreateCommand()) 40 | { 41 | playersWithThisName.CommandType = CommandType.Text; 42 | playersWithThisName.CommandText = "INSERT INTO Player ([Name]) VALUES (@Name)"; 43 | 44 | playersWithThisName.Parameters.AddWithValue("@Name", name); 45 | 46 | playersWithThisName.ExecuteNonQuery(); 47 | } 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Engine/DependencyInversionPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Dependency Inversion/Injection Design Pattern 2 | 3 | Instead of having ClassA create an instance of ClassB, pass a ClassB object into ClassA. 4 | This is commonly used for mocking external resources (database, disk, etc.) in unit tests. 5 | 6 | Website URL: http://scottlilly.com/c-design-patterns-the-dependency-injection-pattern/ 7 | 8 | YouTube video URL: https://www.youtube.com/watch?v=Ko1r9A8p-zo 9 | 10 | Related/similar design patterns: 11 | Strategy http://scottlilly.com/c-design-patterns-the-strategy-pattern/ 12 | -------------------------------------------------------------------------------- /Engine/FactoryPattern/NonPatternVersion/Player.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.NonPatternVersion 2 | { 3 | public class Player 4 | { 5 | public int HitPoints { get; private set; } 6 | public int ExperiencePoints { get; private set; } 7 | public int Gold { get; private set; } 8 | 9 | public Player(int hitPoints, int experiencePoints, int gold) 10 | { 11 | HitPoints = hitPoints; 12 | ExperiencePoints = experiencePoints; 13 | Gold = gold; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_ExternalFactory/Player.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_ExternalFactory 2 | { 3 | public class Player 4 | { 5 | public int HitPoints { get; private set; } 6 | public int ExperiencePoints { get; private set; } 7 | public int Gold { get; private set; } 8 | 9 | internal Player(int hitPoints, int experiencePoints, int gold) 10 | { 11 | HitPoints = hitPoints; 12 | ExperiencePoints = experiencePoints; 13 | Gold = gold; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_ExternalFactory/PlayerFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_ExternalFactory 2 | { 3 | public static class PlayerFactory 4 | { 5 | public static Player LoadPlayer() 6 | { 7 | return new Player(10, 0, 25); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_InternalFactory/Player.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_InternalFactory 2 | { 3 | public class Player 4 | { 5 | public int HitPoints { get; private set; } 6 | public int ExperiencePoints { get; private set; } 7 | public int Gold { get; private set; } 8 | 9 | private Player(int hitPoints, int experiencePoints, int gold) 10 | { 11 | HitPoints = hitPoints; 12 | ExperiencePoints = experiencePoints; 13 | Gold = gold; 14 | } 15 | 16 | public static Player CreateNewPlayer(int hitPoints, int experiencePoints, int gold) 17 | { 18 | return new Player(hitPoints, experiencePoints, gold); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_MultipleDatatypes/FlyingMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_MultipleDatatypes 2 | { 3 | public class FlyingMonster : Monster 4 | { 5 | public int AirSpeed { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_MultipleDatatypes/LandMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_MultipleDatatypes 2 | { 3 | public class LandMonster : Monster 4 | { 5 | public int RunningSpeed { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_MultipleDatatypes/Monster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_MultipleDatatypes 2 | { 3 | public abstract class Monster 4 | { 5 | public int HitPoints { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_MultipleDatatypes/MonsterFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_MultipleDatatypes 2 | { 3 | public static class MonsterFactory 4 | { 5 | public static Monster GetRandomMonster() 6 | { 7 | var randomNumber = 2; // Pretend we got a random number here. 8 | 9 | switch(randomNumber) 10 | { 11 | case 1: 12 | return new FlyingMonster(); 13 | case 2: 14 | return new LandMonster(); 15 | default: 16 | return new SeaMonster(); 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/PatternVersion_MultipleDatatypes/SeaMonster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.FactoryPattern.PatternVersion_MultipleDatatypes 2 | { 3 | public class SeaMonster : Monster 4 | { 5 | public int SwimmingSpeed { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Engine/FactoryPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Factory Design Pattern 2 | 3 | Create instances of your objects from a central class - the factory. This gives you flexibility, in case you need to change how an object is instantiated. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-factory-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=Y5X4odRW00M 8 | 9 | Related/similar design patterns: 10 | Composition over Inheritance http://scottlilly.com/c-design-patterns-composition-over-inheritance/ 11 | Wrapper/Facade http://scottlilly.com/c-design-patterns-the-wrapperfacade-pattern/ 12 | Builder http://scottlilly.com/c-design-patterns-the-builder-pattern/ 13 | -------------------------------------------------------------------------------- /Engine/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016 Scott Lilly 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | There are no restrictions for this Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | Latest source on GitHub: https://github.com/ScottLilly/CSharpDesignPatterns 10 | 11 | My website: http://scottlilly.com -------------------------------------------------------------------------------- /Engine/MVVMPattern/PatternVersion/Models/AccountModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Linq; 3 | 4 | namespace Engine.MVVMPattern.PatternVersion.Models 5 | { 6 | public class AccountModel : INotifyPropertyChanged 7 | { 8 | private string _name; 9 | private string _password; 10 | private string _validationMessage; 11 | 12 | public string Name 13 | { 14 | get { return _name; } 15 | set { _name = value; } 16 | } 17 | 18 | public string Password 19 | { 20 | get { return _password; } 21 | set 22 | { 23 | _password = value; 24 | 25 | OnPropertyChanged(nameof(Password)); 26 | } 27 | } 28 | 29 | public string ValidationMessage 30 | { 31 | get { return _validationMessage; } 32 | set 33 | { 34 | _validationMessage = value; 35 | 36 | OnPropertyChanged(nameof(ValidationMessage)); 37 | } 38 | } 39 | 40 | public event PropertyChangedEventHandler PropertyChanged; 41 | 42 | public void ValidatePassword() 43 | { 44 | if(Password == null || Password.Trim().Length < 8) 45 | { 46 | ValidationMessage = "Password must be at least eight characters long"; 47 | } 48 | else if(Password.Trim().Length > 20) 49 | { 50 | ValidationMessage = "Password cannot be more than twenty characters long"; 51 | } 52 | else if(!Password.Any(char.IsUpper)) 53 | { 54 | ValidationMessage = "Password must contain at least one upper-case character"; 55 | } 56 | else if(!Password.Any(char.IsLower)) 57 | { 58 | ValidationMessage = "Password must contain at least one lower-case character"; 59 | } 60 | else if(!Password.Any(char.IsNumber)) 61 | { 62 | ValidationMessage = "Password must contain at least one number"; 63 | } 64 | else 65 | { 66 | ValidationMessage = "Password is secure"; 67 | } 68 | } 69 | 70 | protected virtual void OnPropertyChanged(string propertyName) 71 | { 72 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Engine/MVVMPattern/PatternVersion/ViewModels/AccountCreationViewModel.cs: -------------------------------------------------------------------------------- 1 | using Engine.MVVMPattern.PatternVersion.Models; 2 | 3 | namespace Engine.MVVMPattern.PatternVersion.ViewModels 4 | { 5 | public class AccountCreationViewModel 6 | { 7 | public AccountModel NewAccount { get; set; } 8 | 9 | public AccountCreationViewModel() 10 | { 11 | NewAccount = new AccountModel(); 12 | } 13 | 14 | public void ValidatePassword() 15 | { 16 | NewAccount.ValidatePassword(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Engine/MVVMPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | MVVM (Model-View-ViewModel) Design Pattern 2 | 3 | Separate the UI from the business logic. 4 | 5 | NOTE: Non-pattern version is in WorkbenchWPF project, in the folder \MVVMPattern\NonPatternVersion 6 | 7 | Website URL: http://scottlilly.com/c-design-patterns-mvvm-model-view-viewmodel/ 8 | 9 | YouTube video URL: https://www.youtube.com/watch?v=oHxAIOxF1Ok -------------------------------------------------------------------------------- /Engine/MementoPattern/BetterMemento/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.MementoPattern.BetterMemento 2 | { 3 | public class Customer 4 | { 5 | // This is the memento object, which holds the original values. 6 | private readonly CustomerMemento _customerMemento; 7 | 8 | public int ID { get; set; } 9 | public string Name { get; set; } 10 | public string Address { get; set; } 11 | public string City { get; set; } 12 | public string StateProvince { get; set; } 13 | public string PostalCode { get; set; } 14 | 15 | public bool IsDirty 16 | { 17 | get 18 | { 19 | return Name != _customerMemento.Name || 20 | Address != _customerMemento.Address || 21 | City != _customerMemento.City || 22 | StateProvince != _customerMemento.StateProvince || 23 | PostalCode != _customerMemento.PostalCode; 24 | } 25 | } 26 | 27 | public Customer(int id, string name, string address, string city, string stateProvince, string postalCode) 28 | { 29 | ID = id; 30 | Name = name; 31 | Address = address; 32 | City = city; 33 | StateProvince = stateProvince; 34 | PostalCode = postalCode; 35 | 36 | // Save the originally-passed values to the "memento". 37 | _customerMemento = new CustomerMemento(name, address, city, stateProvince, postalCode); 38 | } 39 | 40 | public void RevertToOriginalValues() 41 | { 42 | Name = _customerMemento.Name; 43 | Address = _customerMemento.Address; 44 | City = _customerMemento.City; 45 | StateProvince = _customerMemento.StateProvince; 46 | PostalCode = _customerMemento.PostalCode; 47 | } 48 | 49 | // This is one of the rare cases where you might declare more than one class in a file. 50 | // The CustomerMemento class will never be used any place, other than in the Customer class. 51 | // So, you can make it a private class inside the one class where it's used. 52 | // Or, you could put it in its own file, and declare it an internal or public class. 53 | private class CustomerMemento 54 | { 55 | public string Name { get; private set; } 56 | public string Address { get; private set; } 57 | public string City { get; private set; } 58 | public string StateProvince { get; private set; } 59 | public string PostalCode { get; private set; } 60 | 61 | public CustomerMemento(string name, string address, 62 | string city, string stateProvince, string postalCode) 63 | { 64 | Name = name; 65 | Address = address; 66 | City = city; 67 | StateProvince = stateProvince; 68 | PostalCode = postalCode; 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Engine/MementoPattern/MultipleMemento/Customer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Engine.MementoPattern.MultipleMemento 5 | { 6 | public class Customer 7 | { 8 | // Save a list of memento objects, to allow for multiple "snapshots" of the Customer object. 9 | private readonly List _customerMementoes = new List(); 10 | 11 | public int ID { get; set; } 12 | public string Name { get; set; } 13 | public string Address { get; set; } 14 | public string City { get; set; } 15 | public string StateProvince { get; set; } 16 | public string PostalCode { get; set; } 17 | 18 | public bool IsDirty 19 | { 20 | get 21 | { 22 | if(_customerMementoes.Count == 0) 23 | { 24 | return false; 25 | } 26 | 27 | return Name != _customerMementoes.First().Name || 28 | Address != _customerMementoes.First().Address || 29 | City != _customerMementoes.First().City || 30 | StateProvince != _customerMementoes.First().StateProvince || 31 | PostalCode != _customerMementoes.First().PostalCode; 32 | } 33 | } 34 | 35 | public Customer(int id, string name, string address, string city, string stateProvince, string postalCode) 36 | { 37 | ID = id; 38 | Name = name; 39 | Address = address; 40 | City = city; 41 | StateProvince = stateProvince; 42 | PostalCode = postalCode; 43 | 44 | // Save the originally-passed values to the memento list. 45 | SaveMemento(); 46 | } 47 | 48 | public void SaveMemento() 49 | { 50 | CustomerMemento customerMemento = 51 | new CustomerMemento(Name, Address, City, StateProvince, PostalCode); 52 | 53 | _customerMementoes.Add(customerMemento); 54 | } 55 | 56 | public void RevertToOriginalValues() 57 | { 58 | // Get the first memento, if there is one (there always should be at least one). 59 | CustomerMemento firstMemento = _customerMementoes.FirstOrDefault(); 60 | 61 | // Check for null, just to be safe. 62 | if(firstMemento != null) 63 | { 64 | SetPropertyValuesFromMemento(firstMemento); 65 | 66 | // Remove all the mementoes, except for the first one. 67 | if(_customerMementoes.Count > 1) 68 | { 69 | _customerMementoes.RemoveRange(1, _customerMementoes.Count - 1); 70 | } 71 | } 72 | } 73 | 74 | public void RevertToLastValues() 75 | { 76 | // Get the last memento, if there is one (there always should be at least one). 77 | CustomerMemento lastMemento = _customerMementoes.LastOrDefault(); 78 | 79 | // Check for null, just to be safe. 80 | if(lastMemento != null) 81 | { 82 | SetPropertyValuesFromMemento(lastMemento); 83 | 84 | // Remove the last memento, unless it's the first one. 85 | if(lastMemento != _customerMementoes.First()) 86 | { 87 | _customerMementoes.Remove(lastMemento); 88 | } 89 | } 90 | } 91 | 92 | private void SetPropertyValuesFromMemento(CustomerMemento memento) 93 | { 94 | Name = memento.Name; 95 | Address = memento.Address; 96 | City = memento.City; 97 | StateProvince = memento.StateProvince; 98 | PostalCode = memento.PostalCode; 99 | } 100 | 101 | private class CustomerMemento 102 | { 103 | public string Name { get; } 104 | public string Address { get; } 105 | public string City { get; } 106 | public string StateProvince { get; } 107 | public string PostalCode { get; } 108 | 109 | public CustomerMemento(string name, string address, 110 | string city, string stateProvince, string postalCode) 111 | { 112 | Name = name; 113 | Address = address; 114 | City = city; 115 | StateProvince = stateProvince; 116 | PostalCode = postalCode; 117 | } 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /Engine/MementoPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Memento Design Pattern 2 | 3 | See if any of the properties of your object have changed, and add the ability to undo those changes. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-memento-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=ofp0o0J1dh0 8 | 9 | Related/similar design patterns: 10 | -------------------------------------------------------------------------------- /Engine/MementoPattern/SimpleMemento/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.MementoPattern.SimpleMemento 2 | { 3 | public class Customer 4 | { 5 | private readonly string _originalAddress; 6 | private readonly string _originalCity; 7 | // These are the memento variables, which hold the original values. 8 | private readonly string _originalName; 9 | private readonly string _originalPostalCode; 10 | private readonly string _originalStateProvince; 11 | 12 | public int ID { get; set; } 13 | public string Name { get; set; } 14 | public string Address { get; set; } 15 | public string City { get; set; } 16 | public string StateProvince { get; set; } 17 | public string PostalCode { get; set; } 18 | 19 | // Using the memento, to detect if the object has any changes. 20 | public bool IsDirty 21 | { 22 | get 23 | { 24 | return Name != _originalName || 25 | Address != _originalAddress || 26 | City != _originalCity || 27 | StateProvince != _originalStateProvince || 28 | PostalCode != _originalPostalCode; 29 | } 30 | } 31 | 32 | public Customer(int id, string name, string address, string city, string stateProvince, string postalCode) 33 | { 34 | ID = id; 35 | Name = name; 36 | Address = address; 37 | City = city; 38 | StateProvince = stateProvince; 39 | PostalCode = postalCode; 40 | 41 | // Save the originally-passed values to the "memento" variables. 42 | _originalName = name; 43 | _originalAddress = address; 44 | _originalCity = city; 45 | _originalStateProvince = stateProvince; 46 | _originalPostalCode = postalCode; 47 | } 48 | 49 | public void RevertToOriginalValues() 50 | { 51 | Name = _originalName; 52 | Address = _originalAddress; 53 | City = _originalCity; 54 | StateProvince = _originalStateProvince; 55 | PostalCode = _originalPostalCode; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Engine/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Engine")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Engine")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("25d0207b-a871-4ef6-a23b-1ff7b15306fe")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Engine/PrototypePattern/NonPatternVersion/Monster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PrototypePattern.NonPatternVersion 2 | { 3 | public class Monster 4 | { 5 | public string Name { get; private set; } 6 | public int HitPoints { get; private set; } 7 | 8 | public Monster(string name, int hitPoints) 9 | { 10 | Name = name; 11 | HitPoints = hitPoints; 12 | } 13 | 14 | public void ApplyDamage(int amountOfDamage) 15 | { 16 | HitPoints -= amountOfDamage; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Engine/PrototypePattern/PatternVersion_Complex/LootTableEntry.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PrototypePattern.PatternVersion_Complex 2 | { 3 | public class LootTableEntry 4 | { 5 | public int ItemID { get; set; } 6 | public int DropPercentage { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Engine/PrototypePattern/PatternVersion_Complex/Monster.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Engine.PrototypePattern.PatternVersion_Complex 4 | { 5 | public class Monster 6 | { 7 | public string Name { get; private set; } 8 | public int HitPoints { get; private set; } 9 | public List LootTable { get; set;} 10 | 11 | // Public constructor, called to create the prototype Monster object. 12 | public Monster(string name, int hitPoints) 13 | { 14 | Name = name; 15 | HitPoints = hitPoints; 16 | 17 | // In this part, pretend we are populating LootTable using a database query. 18 | LootTable = new List(); 19 | 20 | LootTable.Add(new LootTableEntry { ItemID = 1, DropPercentage = 10 }); 21 | LootTable.Add(new LootTableEntry { ItemID = 2, DropPercentage = 5 }); 22 | LootTable.Add(new LootTableEntry { ItemID = 5, DropPercentage = 1 }); 23 | LootTable.Add(new LootTableEntry { ItemID = 12, DropPercentage = 50 }); 24 | LootTable.Add(new LootTableEntry { ItemID = 27, DropPercentage = 33 }); 25 | LootTable.Add(new LootTableEntry { ItemID = 42, DropPercentage = 100 }); 26 | } 27 | 28 | // Private contructor called by Clone method. 29 | // Does not need to connect to the database to populate the LootTable property. 30 | private Monster(string name, int hitPoints, List lootTable) 31 | { 32 | Name = name; 33 | HitPoints = hitPoints; 34 | LootTable = lootTable; 35 | } 36 | 37 | public void ApplyDamage(int amountOfDamage) 38 | { 39 | HitPoints -= amountOfDamage; 40 | } 41 | 42 | public Monster Clone() 43 | { 44 | // This version of Clone calls the private constructor, 45 | // to prevent re-running the database query to populate LootTable. 46 | return new Monster(Name, HitPoints, LootTable); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Engine/PrototypePattern/PatternVersion_Simple/Monster.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PrototypePattern.PatternVersion_Simple 2 | { 3 | public class Monster 4 | { 5 | public string Name { get; private set; } 6 | public int HitPoints { get; private set; } 7 | 8 | public Monster(string name, int hitPoints) 9 | { 10 | Name = name; 11 | HitPoints = hitPoints; 12 | } 13 | 14 | public void ApplyDamage(int amountOfDamage) 15 | { 16 | HitPoints -= amountOfDamage; 17 | } 18 | 19 | public Monster Clone() 20 | { 21 | return new Monster(Name, HitPoints); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Engine/PrototypePattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Singleton Design Pattern 2 | 3 | Create clones of an existing object. This is useful when the constructor may be slow. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-prototype-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=cssLiHsnNI4 8 | 9 | Related/similar design patterns: 10 | Factory http://scottlilly.com/c-design-patterns-the-factory-pattern/ 11 | -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/NonPatternVersion/Models/Location.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PublishSubscribePattern.NonPatternVersion.Models 2 | { 3 | public class Location 4 | { 5 | public enum AtmosphereType 6 | { 7 | Normal, 8 | Poisonous 9 | } 10 | 11 | public AtmosphereType Atmosphere { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/NonPatternVersion/Models/Player.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PublishSubscribePattern.NonPatternVersion.Models 2 | { 3 | public class Player 4 | { 5 | public int HitPoints { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/NonPatternVersion/ViewModels/GameSession.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Engine.PublishSubscribePattern.NonPatternVersion.Models; 3 | 4 | namespace Engine.PublishSubscribePattern.NonPatternVersion.ViewModels 5 | { 6 | public class GameSession 7 | { 8 | public List Messages { get; set; } 9 | public Player CurrentPlayer { get; set; } 10 | public Location CurrentLocation { get; set; } 11 | 12 | public GameSession() 13 | { 14 | Messages = new List(); 15 | 16 | CurrentPlayer = new Player {HitPoints = 10}; 17 | CurrentLocation = new Location {Atmosphere = Location.AtmosphereType.Normal}; 18 | } 19 | 20 | public void MonsterAttackPlayer(int amountOfDamage) 21 | { 22 | CurrentPlayer.HitPoints -= amountOfDamage; 23 | 24 | CheckIfPlayerWasKilled(); 25 | } 26 | 27 | public void MoveToLocation(Location location) 28 | { 29 | CurrentLocation = location; 30 | 31 | if(CurrentLocation.Atmosphere == Location.AtmosphereType.Poisonous) 32 | { 33 | CurrentPlayer.HitPoints -= 1; 34 | 35 | CheckIfPlayerWasKilled(); 36 | } 37 | } 38 | 39 | private void CheckIfPlayerWasKilled() 40 | { 41 | if(CurrentPlayer.HitPoints <= 0) 42 | { 43 | Messages.Add("You were killed"); 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion/Models/Location.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PublishSubscribePattern.PatternVersion.Models 2 | { 3 | public class Location 4 | { 5 | public enum AtmosphereType 6 | { 7 | Normal, 8 | Poisonous 9 | } 10 | 11 | public AtmosphereType Atmosphere { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion/Models/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.PublishSubscribePattern.PatternVersion.Models 4 | { 5 | public class Player 6 | { 7 | private int _hitPoints; 8 | 9 | public EventHandler PlayerKilled; 10 | 11 | public int HitPoints 12 | { 13 | get { return _hitPoints; } 14 | set 15 | { 16 | _hitPoints = value; 17 | 18 | if(_hitPoints <= 0) 19 | { 20 | // When the player's HitPoint property is zero, or lower, 21 | // the player object will raise a PlayerKilled notification to all subscribed objects. 22 | OnPlayerKilled(); 23 | } 24 | } 25 | } 26 | 27 | private void OnPlayerKilled() 28 | { 29 | // If there are no subscribed objects, 30 | // the PlayerKilled EventHandler will be null, 31 | // and nothing will be notified of this event. 32 | PlayerKilled?.Invoke(this, EventArgs.Empty); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion/ViewModels/GameSession.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Engine.PublishSubscribePattern.PatternVersion.Models; 4 | 5 | namespace Engine.PublishSubscribePattern.PatternVersion.ViewModels 6 | { 7 | public class GameSession 8 | { 9 | public List Messages { get; set; } 10 | public Player CurrentPlayer { get; set; } 11 | public Location CurrentLocation { get; set; } 12 | 13 | public GameSession() 14 | { 15 | Messages = new List(); 16 | 17 | CurrentPlayer = new Player {HitPoints = 10}; 18 | CurrentLocation = new Location {Atmosphere = Location.AtmosphereType.Normal}; 19 | 20 | // "Subscribe" to the PlayerKilled event. 21 | // 22 | // When the GameSession object receives this notification, 23 | // it will run the HandlePlayerKilled function. 24 | CurrentPlayer.PlayerKilled += HandlePlayerKilled; 25 | } 26 | 27 | public void MonsterAttackPlayer(int amountOfDamage) 28 | { 29 | CurrentPlayer.HitPoints -= amountOfDamage; 30 | } 31 | 32 | public void MoveToLocation(Location location) 33 | { 34 | CurrentLocation = location; 35 | 36 | if(CurrentLocation.Atmosphere == Location.AtmosphereType.Poisonous) 37 | { 38 | CurrentPlayer.HitPoints -= 1; 39 | } 40 | } 41 | 42 | private void HandlePlayerKilled(object sender, EventArgs eventArgs) 43 | { 44 | Messages.Add("You were killed"); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_CustomEventArgs/Common/PlayerKilledEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.Common 4 | { 5 | public class PlayerKilledEventArgs : EventArgs 6 | { 7 | public int NumberOfDeaths { get; private set; } 8 | 9 | public PlayerKilledEventArgs(int numberOfDeaths) 10 | { 11 | NumberOfDeaths = numberOfDeaths; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_CustomEventArgs/Models/Location.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.Models 2 | { 3 | public class Location 4 | { 5 | public enum AtmosphereType 6 | { 7 | Normal, 8 | Poisonous 9 | } 10 | 11 | public AtmosphereType Atmosphere { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_CustomEventArgs/Models/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.Common; 3 | 4 | namespace Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.Models 5 | { 6 | public class Player 7 | { 8 | private int _hitPoints; 9 | private int _numberOfDeaths; 10 | 11 | public EventHandler PlayerKilled; 12 | 13 | public int HitPoints 14 | { 15 | get { return _hitPoints; } 16 | set 17 | { 18 | _hitPoints = value; 19 | 20 | if(_hitPoints <= 0) 21 | { 22 | // Increase the "number of deaths" counter. 23 | _numberOfDeaths++; 24 | 25 | // When the player's HitPoint property is zero, or lower, 26 | // the player object will raise a PlayerKilled notification to all subscribed objects. 27 | OnPlayerKilled(); 28 | } 29 | } 30 | } 31 | 32 | protected virtual void OnPlayerKilled() 33 | { 34 | PlayerKilled?.Invoke(this, new PlayerKilledEventArgs(_numberOfDeaths)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_CustomEventArgs/ViewModels/GameSession.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.Common; 3 | using Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.Models; 4 | 5 | namespace Engine.PublishSubscribePattern.PatternVersion_CustomEventArgs.ViewModels 6 | { 7 | public class GameSession 8 | { 9 | public List Messages { get; set; } 10 | public Player CurrentPlayer { get; set; } 11 | public Location CurrentLocation { get; set; } 12 | 13 | public GameSession() 14 | { 15 | Messages = new List(); 16 | 17 | CurrentPlayer = new Player {HitPoints = 10}; 18 | CurrentLocation = new Location {Atmosphere = Location.AtmosphereType.Normal}; 19 | 20 | // "Subscribe" to the PlayerKilled event. 21 | // 22 | // When the GameSession object receives this notification, 23 | // it will run the HandlePlayerKilled function. 24 | CurrentPlayer.PlayerKilled += HandlePlayerKilled; 25 | } 26 | 27 | public void MonsterAttackPlayer(int amountOfDamage) 28 | { 29 | CurrentPlayer.HitPoints -= amountOfDamage; 30 | } 31 | 32 | public void MoveToLocation(Location location) 33 | { 34 | CurrentLocation = location; 35 | 36 | if(CurrentLocation.Atmosphere == Location.AtmosphereType.Poisonous) 37 | { 38 | CurrentPlayer.HitPoints -= 1; 39 | } 40 | } 41 | 42 | private void HandlePlayerKilled(object sender, PlayerKilledEventArgs eventArgs) 43 | { 44 | Messages.Add("You were killed"); 45 | Messages.Add($"This was death number: {eventArgs.NumberOfDeaths}"); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_WithEvent/Models/Location.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.PublishSubscribePattern.PatternVersion_WithEvent.Models 2 | { 3 | public class Location 4 | { 5 | public enum AtmosphereType 6 | { 7 | Normal, 8 | Poisonous 9 | } 10 | 11 | public AtmosphereType Atmosphere { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_WithEvent/Models/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.PublishSubscribePattern.PatternVersion_WithEvent.Models 4 | { 5 | public class Player 6 | { 7 | private int _hitPoints; 8 | 9 | public event EventHandler PlayerKilled; 10 | 11 | public int HitPoints 12 | { 13 | get { return _hitPoints; } 14 | set 15 | { 16 | _hitPoints = value; 17 | 18 | if(_hitPoints <= 0) 19 | { 20 | // When the player's HitPoint property is zero, or lower, 21 | // the player object will raise a PlayerKilled notification to all subscribed objects. 22 | OnPlayerKilled(); 23 | } 24 | } 25 | } 26 | 27 | private void OnPlayerKilled() 28 | { 29 | // If there are no subscribed objects, 30 | // the PlayerKilled EventHandler will be null, 31 | // and nothing will be notified of this event. 32 | PlayerKilled?.Invoke(this, EventArgs.Empty); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/PatternVersion_WithEvent/ViewModels/GameSession.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Engine.PublishSubscribePattern.PatternVersion_WithEvent.Models; 4 | 5 | namespace Engine.PublishSubscribePattern.PatternVersion_WithEvent.ViewModels 6 | { 7 | public class GameSession 8 | { 9 | public List Messages { get; set; } 10 | public Player CurrentPlayer { get; set; } 11 | public Location CurrentLocation { get; set; } 12 | 13 | public GameSession() 14 | { 15 | Messages = new List(); 16 | 17 | CurrentPlayer = new Player {HitPoints = 10}; 18 | CurrentLocation = new Location {Atmosphere = Location.AtmosphereType.Normal}; 19 | 20 | // "Subscribe" to the PlayerKilled event. 21 | // 22 | // When the GameSession object receives this notification, 23 | // it will run the HandlePlayerKilled function. 24 | CurrentPlayer.PlayerKilled += HandlePlayerKilled; 25 | } 26 | 27 | public void MonsterAttackPlayer(int amountOfDamage) 28 | { 29 | CurrentPlayer.HitPoints -= amountOfDamage; 30 | } 31 | 32 | public void MoveToLocation(Location location) 33 | { 34 | CurrentLocation = location; 35 | 36 | if(CurrentLocation.Atmosphere == Location.AtmosphereType.Poisonous) 37 | { 38 | CurrentPlayer.HitPoints -= 1; 39 | } 40 | } 41 | 42 | private void HandlePlayerKilled(object sender, EventArgs eventArgs) 43 | { 44 | Messages.Add("You were killed"); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Engine/PublishSubscribePattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Publish/Subscribe Design Pattern 2 | 3 | Allows an object to notify any interested objects, when specific events happen to the object (e.g., values change) 4 | 5 | Website URL: http://scottlilly.com/c-design-pattern-publishsubscribe/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=D83e-GM_EnI 8 | 9 | Related/similar design patterns: 10 | -------------------------------------------------------------------------------- /Engine/READ_ME.txt: -------------------------------------------------------------------------------- 1 | The "Engine" project contains the code for each design pattern. 2 | 3 | Engine project notes 4 | ========================================= 5 | There is a folder for each pattern. 6 | - If there is only a single code example for the pattern, it will be in this folder. 7 | - If there is an example of how something might be done without the pattern, it will be in a sub-folder named "NonPatternVersion". 8 | - Examples using the design pattern will be in sub-folders named "PatternVersion" 9 | - If there is more than one example of the pattern, there will be multiple sun-directories that start with "PatternVersion". 10 | 11 | 12 | TestEngine project notes 13 | ========================================= 14 | This is an MSTest unit test project. It has tests that show how the pattern could be used, for many of the patterns. 15 | 16 | The directory structure matches the "Engine" project. 17 | 18 | 19 | If you have any questions or comments, please contact me at: http://scottlilly.com/contact-scott/ -------------------------------------------------------------------------------- /Engine/SingletonPattern/NonPatternVersion/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Engine.SingletonPattern.NonPatternVersion 4 | { 5 | public class Customer 6 | { 7 | private readonly Logger _logger; 8 | 9 | public string Name { get; set; } 10 | 11 | public Customer(string name) 12 | { 13 | _logger = Logger.GetLogger(); 14 | 15 | Name = name; 16 | } 17 | 18 | public void UpdateAddress(string streetAddress, string city) 19 | { 20 | // Pretend we update the database, and/or do other things here. 21 | 22 | // Now, write a log message, so we have a record of the update. 23 | _logger.WriteMessage(string.Format("Updated the address for: {0} at: {1}", Name, DateTime.Now)); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Engine/SingletonPattern/NonPatternVersion/Logger.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.SingletonPattern.NonPatternVersion 2 | { 3 | public class Logger 4 | { 5 | // Make the constructor private, to force instantiation through the factory design pattern 6 | private Logger() 7 | { 8 | } 9 | 10 | // Factory method, that returns a new Logger object 11 | public static Logger GetLogger() 12 | { 13 | return new Logger(); 14 | } 15 | 16 | // Pretend we're writing the message to a file here. 17 | public void WriteMessage(string message) 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Engine/SingletonPattern/PatternVersion_DoubleLock/Logger.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.SingletonPattern.PatternVersion_DoubleLock 2 | { 3 | public sealed class Logger 4 | { 5 | private static Logger _logger; 6 | private static readonly object _syncLock = new object(); 7 | 8 | private Logger() 9 | { 10 | } 11 | 12 | public static Logger GetLogger() 13 | { 14 | if(_logger == null) 15 | { 16 | lock(_syncLock) 17 | { 18 | if(_logger == null) 19 | { 20 | _logger = new Logger(); 21 | } 22 | } 23 | } 24 | 25 | return _logger; 26 | } 27 | 28 | public void WriteMessage(string message) 29 | { 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Engine/SingletonPattern/PatternVersion_StaticInitialization/Logger.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.SingletonPattern.PatternVersion_StaticInitialization 2 | { 3 | public sealed class Logger 4 | { 5 | private static readonly Logger _logger = new Logger(); 6 | 7 | private Logger() 8 | { 9 | } 10 | 11 | public static Logger GetLogger() 12 | { 13 | return _logger; 14 | } 15 | 16 | public void WriteMessage(string message) 17 | { 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Engine/SingletonPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Singleton Design Pattern 2 | 3 | Ensure your program only evers instantiates one object from a class. Useful for logging. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-singleton-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=nAKN48JiGyQ 8 | 9 | NOTE: This pattern does not have unit tests in the TestEngine project. 10 | 11 | Related/similar design patterns: 12 | Factory http://scottlilly.com/c-design-patterns-the-factory-pattern/ 13 | -------------------------------------------------------------------------------- /Engine/StrategyPattern/NonPatternVersion_MultipleMethods/Calculator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Engine.StrategyPattern.NonPatternVersion_MultipleMethods 5 | { 6 | public class Calculator 7 | { 8 | public double CalculateAverageByMean(List values) 9 | { 10 | return values.Sum() / values.Count; 11 | } 12 | 13 | public double CalculateAverageByMedian(List values) 14 | { 15 | var sortedValues = values.OrderBy(x => x).ToList(); 16 | 17 | if(sortedValues.Count % 2 == 1) 18 | { 19 | return sortedValues[(sortedValues.Count - 1) / 2]; 20 | } 21 | 22 | return (sortedValues[(sortedValues.Count / 2) - 1] + 23 | sortedValues[sortedValues.Count / 2]) / 2; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Engine/StrategyPattern/NonPatternVersion_SingleMethod/Calculator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Engine.StrategyPattern.NonPatternVersion_SingleMethod 6 | { 7 | public class Calculator 8 | { 9 | public enum AveragingMethod 10 | { 11 | Mean, 12 | Median 13 | } 14 | 15 | public double CalculateAverage(List values, AveragingMethod averagingMethod) 16 | { 17 | switch(averagingMethod) 18 | { 19 | case AveragingMethod.Mean: 20 | return values.Sum() / values.Count; 21 | 22 | case AveragingMethod.Median: 23 | var sortedValues = values.OrderBy(x => x).ToList(); 24 | 25 | if(sortedValues.Count % 2 == 1) 26 | { 27 | return sortedValues[(sortedValues.Count - 1) / 2]; 28 | } 29 | 30 | return (sortedValues[(sortedValues.Count / 2) - 1] + 31 | sortedValues[sortedValues.Count / 2]) / 2; 32 | 33 | default: 34 | throw new ArgumentException("Invalid averagingMethod value"); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Engine/StrategyPattern/PatternVersion/AverageByMean.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Engine.StrategyPattern.PatternVersion 5 | { 6 | public class AverageByMean : IAveragingMethod 7 | { 8 | public double AverageFor(List values) 9 | { 10 | // Simple method to calculate average: 11 | // sum of all values, divided by number of values. 12 | return values.Sum() / values.Count; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Engine/StrategyPattern/PatternVersion/AverageByMedian.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Engine.StrategyPattern.PatternVersion 5 | { 6 | public class AverageByMedian : IAveragingMethod 7 | { 8 | public double AverageFor(List values) 9 | { 10 | // Median average is the middle value of the values in the list. 11 | 12 | var sortedValues = values.OrderBy(x => x).ToList(); 13 | 14 | // Use the "%" (modulus) to determine if there is an even, or odd, number of values. 15 | if(sortedValues.Count % 2 == 1) 16 | { 17 | // Number of values is odd. 18 | // Return the middle value of the sorted list. 19 | // REMEMBER: The list's index is zero-based, so we subtract 1, instead of adding 1, 20 | // to determine which element of the list to return 21 | return sortedValues[(sortedValues.Count - 1) / 2]; 22 | } 23 | 24 | // Number of values is even. 25 | // Return the mean average of the two middle values. 26 | // REMEMBER: The list's index is zero-based, so we subtract 1, instead of adding 1, 27 | // to determine which elements of the list to use 28 | return (sortedValues[(sortedValues.Count / 2) - 1] + 29 | sortedValues[sortedValues.Count / 2]) / 2; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Engine/StrategyPattern/PatternVersion/Calculator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Engine.StrategyPattern.PatternVersion 4 | { 5 | public class Calculator 6 | { 7 | public double CalculateAverageFor(List values, IAveragingMethod averagingMethod) 8 | { 9 | return averagingMethod.AverageFor(values); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Engine/StrategyPattern/PatternVersion/IAveragingMethod.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Engine.StrategyPattern.PatternVersion 4 | { 5 | public interface IAveragingMethod 6 | { 7 | double AverageFor(List values); 8 | } 9 | } -------------------------------------------------------------------------------- /Engine/StrategyPattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Strategy Design Pattern 2 | 3 | Lets you use different techniques to perform a function. 4 | 5 | Often used to output data in different formats - for example, XML, JSON, CSV. 6 | Or, to do calculations using different methods. 7 | Or, to handle "fail-over" situations - for example, save something to the database, if that fails, save it to a file on disk. 8 | 9 | Website URL: http://scottlilly.com/c-design-patterns-the-strategy-pattern/ 10 | 11 | YouTube video URL: https://www.youtube.com/watch?v=b4ssMlADWTM 12 | 13 | Related/similar design patterns: 14 | Command http://scottlilly.com/c-design-patterns-the-command-pattern/ 15 | -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/NonPatternVersion_Complex/MyClassForFacade.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Mail; 3 | 4 | namespace Engine.WrapperFacadePattern.NonPatternVersion_Complex 5 | { 6 | public class MyClassForFacade 7 | { 8 | public void DoSomething() 9 | { 10 | // Pretend there is business-logic here 11 | 12 | // Send an e-mail - complex version, with multiple "to", "cc", and "bcc" addresses. 13 | MailMessage email = new MailMessage(); 14 | 15 | MailAddress fromAddress = new MailAddress("from@test.com"); 16 | email.From = fromAddress; 17 | 18 | MailAddress toAddress1 = new MailAddress("to1@test.com"); 19 | email.To.Add(toAddress1); 20 | MailAddress toAddress2 = new MailAddress("to2@test.com"); 21 | email.To.Add(toAddress2); 22 | MailAddress toAddress3 = new MailAddress("to3@test.com"); 23 | email.To.Add(toAddress3); 24 | 25 | MailAddress ccAddress1 = new MailAddress("cc1@test.com"); 26 | email.CC.Add(ccAddress1); 27 | MailAddress ccAddress2 = new MailAddress("cc2@test.com"); 28 | email.CC.Add(ccAddress2); 29 | 30 | MailAddress bccAddress1 = new MailAddress("bcc1@test.com"); 31 | email.Bcc.Add(bccAddress1); 32 | MailAddress bccAddress2 = new MailAddress("bcc2@test.com"); 33 | email.Bcc.Add(bccAddress2); 34 | MailAddress bccAddress3 = new MailAddress("bcc3@test.com"); 35 | email.Bcc.Add(bccAddress3); 36 | MailAddress bccAddress4 = new MailAddress("bcc4@test.com"); 37 | email.Bcc.Add(bccAddress4); 38 | 39 | email.Subject = "Email subject here"; 40 | email.Body = "Email body here"; 41 | 42 | // Set up the mail server 43 | SmtpClient smtpClient = new SmtpClient("mailservername"); 44 | smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials; 45 | smtpClient.Timeout = 100; 46 | 47 | // Send the email 48 | smtpClient.Send(email); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/NonPatternVersion_Medium/MyClassForFacade.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Mail; 3 | 4 | namespace Engine.WrapperFacadePattern.NonPatternVersion_Medium 5 | { 6 | public class MyClassForFacade 7 | { 8 | public void DoSomething() 9 | { 10 | // Pretend there is business-logic here 11 | 12 | // Send an e-mail - complex version, with multiple "to", "cc", and "bcc" addresses. 13 | MailMessage email = new MailMessage(); 14 | 15 | email.From = new MailAddress("from@test.com"); 16 | 17 | email.To.Add(new MailAddress("to1@test.com")); 18 | email.To.Add(new MailAddress("to2@test.com")); 19 | email.To.Add(new MailAddress("to3@test.com")); 20 | 21 | email.CC.Add(new MailAddress("cc1@test.com")); 22 | email.To.Add(new MailAddress("cc2@test.com")); 23 | 24 | email.Bcc.Add(new MailAddress("bcc1@test.com")); 25 | email.Bcc.Add(new MailAddress("bcc2@test.com")); 26 | email.Bcc.Add(new MailAddress("bcc3@test.com")); 27 | email.Bcc.Add(new MailAddress("bcc4@test.com")); 28 | 29 | email.Subject = "Email subject here"; 30 | email.Body = "Email body here"; 31 | 32 | // Set up the mail server 33 | SmtpClient smtpClient = new SmtpClient("mailservername"); 34 | smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials; 35 | smtpClient.Timeout = 100; 36 | 37 | // Send the email 38 | smtpClient.Send(email); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/NonPatternVersion_Simple/MyClassForFacade.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Mail; 3 | 4 | namespace Engine.WrapperFacadePattern.NonPatternVersion_Simple 5 | { 6 | public class MyClassForFacade 7 | { 8 | public void DoSomething() 9 | { 10 | // Pretend there is business-logic here 11 | 12 | // Send an e-mail - simple version, with one "to" address 13 | MailMessage simpleEmail = 14 | new MailMessage("from@test.com", "to@test.com", "Email subject here", "Email body here"); 15 | 16 | // Set up the mail server 17 | SmtpClient smtpClient = new SmtpClient("mailservername"); 18 | smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials; 19 | smtpClient.Timeout = 100; 20 | 21 | // Send the email 22 | smtpClient.Send(simpleEmail); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/PatternVersion/EmailCreator.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Mail; 3 | 4 | namespace Engine.WrapperFacadePattern.PatternVersion 5 | { 6 | public class EmailCreator : IEmailFluentInterface 7 | { 8 | private readonly MailMessage _mailMessage = new MailMessage(); 9 | 10 | private EmailCreator(string fromAddress) 11 | { 12 | _mailMessage.Sender = new MailAddress(fromAddress); 13 | } 14 | 15 | public static IEmailFluentInterface CreateEmailFrom(string fromAddress) 16 | { 17 | return new EmailCreator(fromAddress); 18 | } 19 | 20 | public IEmailFluentInterface From(string fromAddress) 21 | { 22 | return this; 23 | } 24 | 25 | public IEmailFluentInterface To(params string[] toAddresses) 26 | { 27 | foreach(var toAddress in toAddresses) 28 | { 29 | _mailMessage.To.Add(new MailAddress(toAddress)); 30 | } 31 | 32 | return this; 33 | } 34 | 35 | public IEmailFluentInterface CC(params string[] ccAddresses) 36 | { 37 | foreach(var ccAddress in ccAddresses) 38 | { 39 | _mailMessage.CC.Add(new MailAddress(ccAddress)); 40 | } 41 | 42 | return this; 43 | } 44 | 45 | public IEmailFluentInterface BCC(params string[] bccAddresses) 46 | { 47 | foreach(var bccAddress in bccAddresses) 48 | { 49 | _mailMessage.Bcc.Add(new MailAddress(bccAddress)); 50 | } 51 | 52 | return this; 53 | } 54 | 55 | public IEmailFluentInterface WithSubject(string subject) 56 | { 57 | _mailMessage.Subject = subject; 58 | 59 | return this; 60 | } 61 | 62 | public IEmailFluentInterface WithBody(string body) 63 | { 64 | _mailMessage.Body = body; 65 | 66 | return this; 67 | } 68 | 69 | public void Send() 70 | { 71 | // Set up the mail server 72 | SmtpClient smtpClient = new SmtpClient("mailservername"); 73 | smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials; 74 | smtpClient.Timeout = 100; 75 | 76 | // Send the email 77 | smtpClient.Send(_mailMessage); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/PatternVersion/IEmailFluentInterface.cs: -------------------------------------------------------------------------------- 1 | namespace Engine.WrapperFacadePattern.PatternVersion 2 | { 3 | public interface IEmailFluentInterface 4 | { 5 | IEmailFluentInterface From(string fromAddress); 6 | IEmailFluentInterface To(params string[] toAddresses); 7 | IEmailFluentInterface CC(params string[] ccAddresses); 8 | IEmailFluentInterface BCC(params string[] bccAddresses); 9 | IEmailFluentInterface WithSubject(string subject); 10 | IEmailFluentInterface WithBody(string body); 11 | void Send(); 12 | } 13 | } -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/PatternVersion/MyClassForFacade.cs: -------------------------------------------------------------------------------- 1 | using Engine.WrapperFacadePattern.PatternVersion; 2 | 3 | namespace DesignPatternDemos.Facade 4 | { 5 | public class MyClassForFacade 6 | { 7 | public void DoSomething() 8 | { 9 | // Pretend there is business-logic here 10 | 11 | // Send an e-mail - version behind wrapper/facade, with multiple "to", "cc", and "bcc" addresses. 12 | EmailCreator.CreateEmailFrom("from@test.com") 13 | .To("to1@test.com", "to2@test.com", "to2@test.com") 14 | .CC("cc1@test.com", "cc2@test.com") 15 | .BCC("bcc1@test.com", "bcc2@test.com", "bcc3@test.com", "bcc4@test.com") 16 | .WithSubject("Email subject here") 17 | .WithBody("Email body here") 18 | .Send(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Engine/WrapperFacadePattern/READ_ME.txt: -------------------------------------------------------------------------------- 1 | Wrapper/Facade Design Pattern 2 | 3 | Make it easier to use complex classes, and provide a single location to deal with classes with structures that are likely to change. 4 | 5 | Website URL: http://scottlilly.com/c-design-patterns-the-wrapperfacade-pattern/ 6 | 7 | YouTube video URL: https://www.youtube.com/watch?v=a2Qh10YjP6Y 8 | 9 | NOTE: This pattern does not have unit tests in the TestEngine project. Code samples are in the MyClassForFacade classes. 10 | 11 | Related/similar design patterns: 12 | Builder http://scottlilly.com/c-design-patterns-the-builder-pattern/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Scott Lilly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSharpDesignPatterns 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
This project is inactive and has been archived to read-only mode. Please contact me if you want it reopened.
10 | 11 | Examples of design patterns, using C# code. 12 | 13 | See the demonstrations of these design patterns at: http://scottlilly.com/c-design-patterns/ 14 | -------------------------------------------------------------------------------- /TestEngine/BuilderPattern/NonPatternVersion/TestNonPatternReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Engine.BuilderPattern.NonPatternVersion; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace TestEngine.BuilderPattern.NonPatternVersion 6 | { 7 | [TestClass] 8 | public class TestNonPatternReport 9 | { 10 | [TestMethod] 11 | public void Test_BuildReports() 12 | { 13 | DateTime now = DateTime.UtcNow; 14 | 15 | Report currentMonthTaxReport = 16 | new Report(new DateTime(now.Year, now.Month, 1), 17 | new DateTime(now.Year, now.Month, 1).AddMonths(1).AddSeconds(-1), 18 | false, true, Report.SortingMethod.ByTaxCategory); 19 | 20 | Report currentYearTaxReport = 21 | new Report(new DateTime(now.Year, 1, 1), 22 | new DateTime(now.Year, 12, 31), 23 | false, true, Report.SortingMethod.ByTaxCategory); 24 | 25 | Report currentMonthCommissionReport = 26 | new Report(new DateTime(now.Year, now.Month, 1), 27 | new DateTime(now.Year, now.Month, 1).AddMonths(1).AddSeconds(-1), 28 | false, false, Report.SortingMethod.BySalesperson); 29 | 30 | Report currentYearCommissionReport = 31 | new Report(new DateTime(now.Year, 1, 1), 32 | new DateTime(now.Year, 12, 31), 33 | false, false, Report.SortingMethod.BySalesperson); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /TestEngine/BuilderPattern/PatternVersion/TestPatternReport.cs: -------------------------------------------------------------------------------- 1 | using Engine.BuilderPattern.PatternVersion; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.BuilderPattern.PatternVersion 5 | { 6 | [TestClass] 7 | public class TestPatternReport 8 | { 9 | [TestMethod] 10 | public void Test_BuildReports() 11 | { 12 | Report currentMonthTaxReport = 13 | ReportBuilder.CreateMonthTaxReport(4, 2017); 14 | 15 | Report currentYearTaxReport = 16 | ReportBuilder.CreateYearTaxReport(2017); 17 | 18 | Report currentMonthCommissionReport = 19 | ReportBuilder.CreateMonthCommissionReport(4, 2017); 20 | 21 | Report currentYearCommissionReport = 22 | ReportBuilder.CreateYearCommissionReport(2017); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /TestEngine/CommandPattern/PatternVersion/TestCommandPattern.cs: -------------------------------------------------------------------------------- 1 | using Engine.CommandPattern.PatternVersion; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.CommandPattern.PatternVersion 5 | { 6 | [TestClass] 7 | public class TestCommandPattern 8 | { 9 | [TestMethod] 10 | public void Test_AllTransactionsSuccessful() 11 | { 12 | TransactionManager transactionManager = new TransactionManager(); 13 | 14 | Account suesAccount = new Account("Sue Smith", 0); 15 | 16 | Deposit deposit = new Deposit(suesAccount, 100); 17 | transactionManager.AddTransaction(deposit); 18 | 19 | // Command has been added to the queue, but not executed. 20 | Assert.IsTrue(transactionManager.HasPendingTransactions); 21 | Assert.AreEqual(0, suesAccount.Balance); 22 | 23 | // This executes the commands. 24 | transactionManager.ProcessPendingTransactions(); 25 | 26 | Assert.IsFalse(transactionManager.HasPendingTransactions); 27 | Assert.AreEqual(100, suesAccount.Balance); 28 | 29 | // Add a withdrawal, apply it, and verify the balance changed. 30 | Withdraw withdrawal = new Withdraw(suesAccount, 50); 31 | transactionManager.AddTransaction(withdrawal); 32 | 33 | transactionManager.ProcessPendingTransactions(); 34 | 35 | Assert.IsFalse(transactionManager.HasPendingTransactions); 36 | Assert.AreEqual(50, suesAccount.Balance); 37 | } 38 | 39 | [TestMethod] 40 | public void Test_OverdraftRemainsInPendingTransactions() 41 | { 42 | TransactionManager transactionManager = new TransactionManager(); 43 | 44 | // Create an account with a balance of 75 45 | Account bobsAccount = new Account("Bob Jones", 75); 46 | 47 | // The first command is a withdrawal that is larger than the account's balance. 48 | // It will not be executed, because of the check in Withdraw.Execute. 49 | // The deposit will be successful. 50 | transactionManager.AddTransaction(new Withdraw(bobsAccount, 100)); 51 | transactionManager.AddTransaction(new Deposit(bobsAccount, 75)); 52 | 53 | transactionManager.ProcessPendingTransactions(); 54 | 55 | // The withdrawal of 100 was not completed, 56 | // because there was not enough money in the account. 57 | // So, it is still pending. 58 | Assert.IsTrue(transactionManager.HasPendingTransactions); 59 | Assert.AreEqual(150, bobsAccount.Balance); 60 | 61 | // The pending transactions (the withdrawal of 100), should execute now. 62 | transactionManager.ProcessPendingTransactions(); 63 | 64 | Assert.IsFalse(transactionManager.HasPendingTransactions); 65 | Assert.AreEqual(50, bobsAccount.Balance); 66 | } 67 | 68 | [TestMethod] 69 | public void Test_Transfer() 70 | { 71 | TransactionManager transactionManager = new TransactionManager(); 72 | 73 | Account checking = new Account("Mike Brown", 1000); 74 | Account savings = new Account("Mike Brown", 100); 75 | 76 | transactionManager.AddTransaction(new Transfer(checking, savings, 750)); 77 | 78 | transactionManager.ProcessPendingTransactions(); 79 | 80 | Assert.AreEqual(250, checking.Balance); 81 | Assert.AreEqual(850, savings.Balance); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /TestEngine/CommandPattern/PatternVersion_WithUndo/TestCommandPattern.cs: -------------------------------------------------------------------------------- 1 | using Engine.CommandPattern.PatternVersion_WithUndo; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.CommandPattern.PatternVersion_WithUndo 5 | { 6 | [TestClass] 7 | public class TestCommandPattern 8 | { 9 | [TestMethod] 10 | public void Test_AllTransactionsSuccessful() 11 | { 12 | TransactionManager transactionManager = new TransactionManager(); 13 | 14 | Account suesAccount = new Account("Sue Smith", 0); 15 | 16 | Deposit deposit = new Deposit(1, suesAccount, 100); 17 | transactionManager.AddTransaction(deposit); 18 | 19 | // Command has been added to the queue, but not executed. 20 | Assert.IsTrue(transactionManager.HasPendingTransactions); 21 | Assert.AreEqual(0, suesAccount.Balance); 22 | 23 | // This executes the commands. 24 | transactionManager.ProcessPendingTransactions(); 25 | 26 | Assert.IsFalse(transactionManager.HasPendingTransactions); 27 | Assert.AreEqual(100, suesAccount.Balance); 28 | 29 | // Add a withdrawal, apply it, and verify the balance changed. 30 | Withdraw withdrawal = new Withdraw(2, suesAccount, 50); 31 | transactionManager.AddTransaction(withdrawal); 32 | 33 | transactionManager.ProcessPendingTransactions(); 34 | 35 | Assert.IsFalse(transactionManager.HasPendingTransactions); 36 | Assert.AreEqual(50, suesAccount.Balance); 37 | 38 | // Test the undo 39 | transactionManager.UndoTransactionNumber(2); 40 | 41 | Assert.IsFalse(transactionManager.HasPendingTransactions); 42 | Assert.AreEqual(100, suesAccount.Balance); 43 | } 44 | 45 | [TestMethod] 46 | public void Test_OverdraftRemainsInPendingTransactions() 47 | { 48 | TransactionManager transactionManager = new TransactionManager(); 49 | 50 | // Create an account with a balance of 75 51 | Account bobsAccount = new Account("Bob Jones", 75); 52 | 53 | // The first command is a withdrawal that is larger than the account's balance. 54 | // It will not be executed, because of the check in Withdraw.Execute. 55 | // The deposit will be successful. 56 | transactionManager.AddTransaction(new Withdraw(1, bobsAccount, 100)); 57 | transactionManager.AddTransaction(new Deposit(2, bobsAccount, 75)); 58 | 59 | transactionManager.ProcessPendingTransactions(); 60 | 61 | // The withdrawal of 100 was not completed, 62 | // because there was not enough money in the account. 63 | // So, it is still pending. 64 | Assert.IsTrue(transactionManager.HasPendingTransactions); 65 | Assert.AreEqual(150, bobsAccount.Balance); 66 | 67 | // The pending transactions (the withdrawal of 100), should execute now. 68 | transactionManager.ProcessPendingTransactions(); 69 | 70 | Assert.IsFalse(transactionManager.HasPendingTransactions); 71 | Assert.AreEqual(50, bobsAccount.Balance); 72 | 73 | // Test the undo 74 | transactionManager.UndoTransactionNumber(2); 75 | 76 | // The undo failed, because there is not enough money in the account to undo a deposit of 75 77 | Assert.IsTrue(transactionManager.HasPendingTransactions); 78 | Assert.AreEqual(50, bobsAccount.Balance); 79 | 80 | transactionManager.UndoTransactionNumber(1); 81 | 82 | // The previous undo (for transaction ID 2) is still pending. 83 | // But, we successfully undid transaction ID 1. 84 | Assert.IsTrue(transactionManager.HasPendingTransactions); 85 | Assert.AreEqual(150, bobsAccount.Balance); 86 | 87 | // This should re-do the failed undo for transaction ID 2 88 | transactionManager.ProcessPendingTransactions(); 89 | 90 | Assert.IsFalse(transactionManager.HasPendingTransactions); 91 | Assert.AreEqual(75, bobsAccount.Balance); 92 | } 93 | 94 | [TestMethod] 95 | public void Test_Transfer() 96 | { 97 | TransactionManager transactionManager = new TransactionManager(); 98 | 99 | Account checking = new Account("Mike Brown", 1000); 100 | Account savings = new Account("Mike Brown", 100); 101 | 102 | transactionManager.AddTransaction(new Transfer(1, checking, savings, 750)); 103 | 104 | transactionManager.ProcessPendingTransactions(); 105 | 106 | Assert.AreEqual(250, checking.Balance); 107 | Assert.AreEqual(850, savings.Balance); 108 | 109 | // Undo the transfer, and check the account balances. 110 | transactionManager.UndoTransactionNumber(1); 111 | 112 | Assert.IsFalse(transactionManager.HasPendingTransactions); 113 | Assert.AreEqual(1000, checking.Balance); 114 | Assert.AreEqual(100, savings.Balance); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /TestEngine/CompositionOverInheritance/Composition/TestMonsterFactory.cs: -------------------------------------------------------------------------------- 1 | using Engine.CompositionOverInheritance.Composition_BEFORE; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.CompositionOverInheritance.Composition 5 | { 6 | [TestClass] 7 | public class TestMonsterFactory 8 | { 9 | [TestMethod] 10 | public void Test_BitingMonster() 11 | { 12 | Monster crocodile = MonsterFactory.CreateMonster(MonsterFactory.MonsterType.Crocodile); 13 | 14 | Assert.IsTrue(crocodile.CanBite); 15 | Assert.IsFalse(crocodile.CanKick); 16 | Assert.IsFalse(crocodile.CanPunch); 17 | } 18 | 19 | [TestMethod] 20 | public void Test_BitingKickingMonster() 21 | { 22 | Monster horse = MonsterFactory.CreateMonster(MonsterFactory.MonsterType.Horse); 23 | 24 | Assert.IsTrue(horse.CanBite); 25 | Assert.IsTrue(horse.CanKick); 26 | Assert.IsFalse(horse.CanPunch); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /TestEngine/CompositionOverInheritance/Inheritance/TestMonsterFactory.cs: -------------------------------------------------------------------------------- 1 | using Engine.CompositionOverInheritance.Inheritance_AFTER; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.CompositionOverInheritance.Inheritance 5 | { 6 | [TestClass] 7 | public class TestMonsterFactory 8 | { 9 | [TestMethod] 10 | public void Test_BitingMonster() 11 | { 12 | Monster crocodile = MonsterFactory.CreateMonster(MonsterFactory.MonsterType.Crocodile); 13 | 14 | Assert.IsTrue(crocodile is BitingMonster); 15 | } 16 | 17 | [TestMethod] 18 | public void Test_BitingKickingMonster() 19 | { 20 | Monster horse = MonsterFactory.CreateMonster(MonsterFactory.MonsterType.Horse); 21 | 22 | Assert.IsTrue(horse is BitingMonster); 23 | 24 | // This test will fail, because we cannot inherit from multiple base classes. 25 | Assert.IsTrue(horse is KickingMonster); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /TestEngine/DependencyInversionPattern/NonPatternVersion/TestPlayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Engine.DependencyInversionPattern.NonPatternVersion; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace TestEngine.DependencyInversionPattern.NonPatternVersion 6 | { 7 | [TestClass] 8 | public class TestPlayer 9 | { 10 | // Test that we receive an exception, if the name parameter is an empty string. 11 | [TestMethod] 12 | [ExpectedException(typeof(ArgumentException))] 13 | public void Test_CreateNewPlayer_EmptyName() 14 | { 15 | Player player = Player.CreateNewPlayer(""); 16 | } 17 | 18 | // Other tests would require a running database, which might have problems. 19 | } 20 | } -------------------------------------------------------------------------------- /TestEngine/DependencyInversionPattern/PatternVersion/MockPlayerDataMapper.cs: -------------------------------------------------------------------------------- 1 | using Engine.DependencyInversionPattern.PatternVersion; 2 | 3 | namespace TestEngine.DependencyInversionPattern.PatternVersion 4 | { 5 | public class MockPlayerDataMapper : IPlayerDataMapper 6 | { 7 | // This property holds the value for PlayerNameExistsInDatabase to return. 8 | // This lets us "mock" the results that we would receive from a real database. 9 | public bool ResultToReturn { get; set; } 10 | 11 | // These functions implement the IPlayerDataMapper interface. 12 | public bool PlayerNameExistsInDatabase(string name) 13 | { 14 | // This is whatever answer we need, for the current unit test. 15 | return ResultToReturn; 16 | } 17 | 18 | public void InsertNewPlayerIntoDatabase(string name) 19 | { 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /TestEngine/DependencyInversionPattern/PatternVersion/TestPlayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Engine.DependencyInversionPattern.PatternVersion; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace TestEngine.DependencyInversionPattern.PatternVersion 6 | { 7 | [TestClass] 8 | public class TestPlayer 9 | { 10 | // Should receive an exception, because the name is an empty string. 11 | [TestMethod] 12 | [ExpectedException(typeof(ArgumentException))] 13 | public void Test_CreateNewPlayer_EmptyName() 14 | { 15 | Player player = Player.CreateNewPlayer(""); 16 | } 17 | 18 | // Should still receive an exception, because the name is an empty string. 19 | [TestMethod] 20 | [ExpectedException(typeof(ArgumentException))] 21 | public void Test_CreateNewPlayer_EmptyName_MockedDataMapper() 22 | { 23 | MockPlayerDataMapper mockPlayerDataMapper = new MockPlayerDataMapper(); 24 | 25 | Player player = Player.CreateNewPlayer("", mockPlayerDataMapper); 26 | } 27 | 28 | // Should receive an exception, because we set the mock PlayerDataMapper 29 | // to say the player name already exists in the database. 30 | [TestMethod] 31 | [ExpectedException(typeof(ArgumentException))] 32 | public void Test_CreateNewPlayer_AlreadyExistsInDatabase() 33 | { 34 | MockPlayerDataMapper mockPlayerDataMapper = new MockPlayerDataMapper(); 35 | 36 | mockPlayerDataMapper.ResultToReturn = true; 37 | 38 | Player player = Player.CreateNewPlayer("Test", mockPlayerDataMapper); 39 | } 40 | 41 | // Should succeed, because we set the mock PlayerDataMapper 42 | // to say the player name does not already exist in the database. 43 | // Also, when it calls the mock InsertNewPlayerIntoDatabase, 44 | // the mock mapper will not need a database running. 45 | [TestMethod] 46 | public void Test_CreateNewPlayer_DoesNotAlreadyExistInDatabase() 47 | { 48 | MockPlayerDataMapper mockPlayerDataMapper = new MockPlayerDataMapper(); 49 | 50 | mockPlayerDataMapper.ResultToReturn = false; 51 | 52 | Player player = Player.CreateNewPlayer("Test", mockPlayerDataMapper); 53 | 54 | Assert.AreEqual("Test", player.Name); 55 | Assert.AreEqual(0, player.ExperiencePoints); 56 | Assert.AreEqual(10, player.Gold); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /TestEngine/FactoryPattern/TestFactoryPattern_NonPatternVersion.cs: -------------------------------------------------------------------------------- 1 | using Engine.FactoryPattern.NonPatternVersion; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.FactoryPattern 5 | { 6 | [TestClass] 7 | public class TestFactoryPattern_NonPatternVersion 8 | { 9 | [TestMethod] 10 | public void Test_InstantiatePlayer() 11 | { 12 | Player player = new Player(10, 0, 25); 13 | 14 | Assert.AreEqual(10, player.HitPoints); 15 | Assert.AreEqual(0, player.ExperiencePoints); 16 | Assert.AreEqual(25, player.Gold); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /TestEngine/FactoryPattern/TestFactoryPattern_PatternVersion_ExternalFactory.cs: -------------------------------------------------------------------------------- 1 | using Engine.FactoryPattern.PatternVersion_ExternalFactory; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.FactoryPattern 5 | { 6 | [TestClass] 7 | public class TestFactoryPattern_PatternVersion_ExternalFactory 8 | { 9 | [TestMethod] 10 | public void Test_InstantiatePlayer() 11 | { 12 | Player player = PlayerFactory.LoadPlayer(); 13 | 14 | Assert.AreEqual(10, player.HitPoints); 15 | Assert.AreEqual(0, player.ExperiencePoints); 16 | Assert.AreEqual(25, player.Gold); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TestEngine/FactoryPattern/TestFactoryPattern_PatternVersion_InternalFactory.cs: -------------------------------------------------------------------------------- 1 | using Engine.FactoryPattern.PatternVersion_InternalFactory; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.FactoryPattern 5 | { 6 | [TestClass] 7 | public class TestFactoryPattern_PatternVersion_InternalFactory 8 | { 9 | [TestMethod] 10 | public void Test_InstantiatePlayer() 11 | { 12 | Player player = Player.CreateNewPlayer(10, 0, 25); 13 | 14 | Assert.AreEqual(10, player.HitPoints); 15 | Assert.AreEqual(0, player.ExperiencePoints); 16 | Assert.AreEqual(25, player.Gold); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TestEngine/FactoryPattern/TestFactoryPattern_PatternVersion_MultipleDatatypes.cs: -------------------------------------------------------------------------------- 1 | using Engine.FactoryPattern.PatternVersion_MultipleDatatypes; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.FactoryPattern 5 | { 6 | [TestClass] 7 | public class TestFactoryPattern_PatternVersion_MultipleDatatypes 8 | { 9 | [TestMethod] 10 | public void Test_InstantiateMonster() 11 | { 12 | Monster monster = MonsterFactory.GetRandomMonster(); 13 | 14 | Assert.IsTrue(monster is FlyingMonster || monster is LandMonster || monster is SeaMonster); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /TestEngine/MVVMPattern/TestMVVMPattern.cs: -------------------------------------------------------------------------------- 1 | using Engine.MVVMPattern.PatternVersion.ViewModels; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.MVVMPattern 5 | { 6 | [TestClass] 7 | public class TestMVVMPattern 8 | { 9 | [TestMethod] 10 | public void Test_PasswordIsTooShort() 11 | { 12 | AccountCreationViewModel viewModel = new AccountCreationViewModel(); 13 | viewModel.NewAccount.Password = "asd"; 14 | viewModel.ValidatePassword(); 15 | 16 | Assert.AreEqual("Password must be at least eight characters long", 17 | viewModel.NewAccount.ValidationMessage); 18 | } 19 | 20 | [TestMethod] 21 | public void Test_PasswordIsTooLong() 22 | { 23 | AccountCreationViewModel viewModel = new AccountCreationViewModel(); 24 | viewModel.NewAccount.Password = "asdasdasdasdasdasdasd"; 25 | viewModel.ValidatePassword(); 26 | 27 | Assert.AreEqual("Password cannot be more than twenty characters long", 28 | viewModel.NewAccount.ValidationMessage); 29 | } 30 | 31 | [TestMethod] 32 | public void Test_PasswordMustHaveAnUpperCaseCharacter() 33 | { 34 | AccountCreationViewModel viewModel = new AccountCreationViewModel(); 35 | viewModel.NewAccount.Password = "asdasdasd"; 36 | viewModel.ValidatePassword(); 37 | 38 | Assert.AreEqual("Password must contain at least one upper-case character", 39 | viewModel.NewAccount.ValidationMessage); 40 | } 41 | 42 | [TestMethod] 43 | public void Test_PasswordMustHaveALowerCaseCharacter() 44 | { 45 | AccountCreationViewModel viewModel = new AccountCreationViewModel(); 46 | viewModel.NewAccount.Password = "ASDASDASD"; 47 | viewModel.ValidatePassword(); 48 | 49 | Assert.AreEqual("Password must contain at least one lower-case character", 50 | viewModel.NewAccount.ValidationMessage); 51 | } 52 | 53 | [TestMethod] 54 | public void Test_PasswordMustHaveANumber() 55 | { 56 | AccountCreationViewModel viewModel = new AccountCreationViewModel(); 57 | viewModel.NewAccount.Password = "asdasdasdA"; 58 | viewModel.ValidatePassword(); 59 | 60 | Assert.AreEqual("Password must contain at least one number", 61 | viewModel.NewAccount.ValidationMessage); 62 | } 63 | 64 | [TestMethod] 65 | public void Test_PasswordIsSecure() 66 | { 67 | AccountCreationViewModel viewModel = new AccountCreationViewModel(); 68 | viewModel.NewAccount.Password = "asdasdasdA1"; 69 | viewModel.ValidatePassword(); 70 | 71 | Assert.AreEqual("Password is secure", 72 | viewModel.NewAccount.ValidationMessage); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /TestEngine/MementoPattern/MementoPattern_BetterMemento.cs: -------------------------------------------------------------------------------- 1 | using Engine.MementoPattern.BetterMemento; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.MementoPattern 5 | { 6 | [TestClass] 7 | public class MementoPattern_BetterMemento 8 | { 9 | private const string ORIGINAL_ADDRESS = "1234 Main Street"; 10 | private const string CHANGED_ADDRESS = "4321 Elm Street"; 11 | 12 | [TestMethod] 13 | public void Test_IsDirtyAndRevertWork() 14 | { 15 | Customer customer = new Customer(1, "ABC", ORIGINAL_ADDRESS, "Houston", "TX", "77777"); 16 | 17 | // Should not be "dirty", because the initial values have not changed. 18 | Assert.IsFalse(customer.IsDirty); 19 | Assert.AreEqual(ORIGINAL_ADDRESS, customer.Address); 20 | 21 | customer.Address = CHANGED_ADDRESS; 22 | 23 | // Should be "dirty". 24 | Assert.IsTrue(customer.IsDirty); 25 | Assert.AreEqual(CHANGED_ADDRESS, customer.Address); 26 | 27 | customer.RevertToOriginalValues(); 28 | 29 | // Should not be "dirty" after reverting values. 30 | Assert.IsFalse(customer.IsDirty); 31 | Assert.AreEqual(ORIGINAL_ADDRESS, customer.Address); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TestEngine/MementoPattern/MementoPattern_MultipleMemento.cs: -------------------------------------------------------------------------------- 1 | using Engine.MementoPattern.MultipleMemento; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.MementoPattern 5 | { 6 | [TestClass] 7 | public class MementoPattern_MultipleMemento 8 | { 9 | private const string ORIGINAL_ADDRESS = "1234 Main Street"; 10 | private const string CHANGED_ADDRESS_1 = "4321 Elm Street"; 11 | private const string CHANGED_ADDRESS_2 = "1111 Pine Road"; 12 | private const string CHANGED_ADDRESS_3 = "5555 5th Avenue"; 13 | 14 | [TestMethod] 15 | public void Test_IsDirtyAndRevertWork() 16 | { 17 | Customer customer = new Customer(1, "ABC", ORIGINAL_ADDRESS, "Houston", "TX", "77777"); 18 | 19 | // Should not be "dirty", because the initial values have not changed. 20 | Assert.IsFalse(customer.IsDirty); 21 | Assert.AreEqual(ORIGINAL_ADDRESS, customer.Address); 22 | 23 | customer.Address = CHANGED_ADDRESS_1; 24 | customer.SaveMemento(); 25 | 26 | // Should be "dirty". 27 | Assert.IsTrue(customer.IsDirty); 28 | Assert.AreEqual(CHANGED_ADDRESS_1, customer.Address); 29 | 30 | customer.Address = CHANGED_ADDRESS_2; 31 | customer.SaveMemento(); 32 | 33 | // Should be "dirty". 34 | Assert.IsTrue(customer.IsDirty); 35 | Assert.AreEqual(CHANGED_ADDRESS_2, customer.Address); 36 | 37 | customer.Address = CHANGED_ADDRESS_3; 38 | 39 | // Should be "dirty". 40 | Assert.IsTrue(customer.IsDirty); 41 | Assert.AreEqual(CHANGED_ADDRESS_3, customer.Address); 42 | 43 | // Revert the current change, to latest saved memento. 44 | customer.RevertToLastValues(); 45 | 46 | // Should be "dirty". 47 | Assert.IsTrue(customer.IsDirty); 48 | Assert.AreEqual(CHANGED_ADDRESS_2, customer.Address); 49 | 50 | // Go back to original values. 51 | customer.RevertToOriginalValues(); 52 | 53 | // Should not be "dirty" after reverting values. 54 | Assert.IsFalse(customer.IsDirty); 55 | Assert.AreEqual(ORIGINAL_ADDRESS, customer.Address); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /TestEngine/MementoPattern/MementoPattern_SimpleMemento.cs: -------------------------------------------------------------------------------- 1 | using Engine.MementoPattern.SimpleMemento; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.MementoPattern 5 | { 6 | [TestClass] 7 | public class MementoPattern_SimpleMemento 8 | { 9 | private const string ORIGINAL_ADDRESS = "1234 Main Street"; 10 | private const string CHANGED_ADDRESS = "4321 Elm Street"; 11 | 12 | [TestMethod] 13 | public void Test_IsDirtyAndRevertWork() 14 | { 15 | Customer customer = new Customer(1, "ABC", ORIGINAL_ADDRESS, "Houston", "TX", "77777"); 16 | 17 | // Should not be "dirty", because the initial values have not changed. 18 | Assert.IsFalse(customer.IsDirty); 19 | Assert.AreEqual(ORIGINAL_ADDRESS, customer.Address); 20 | 21 | customer.Address = CHANGED_ADDRESS; 22 | 23 | // Should be "dirty". 24 | Assert.IsTrue(customer.IsDirty); 25 | Assert.AreEqual(CHANGED_ADDRESS, customer.Address); 26 | 27 | customer.RevertToOriginalValues(); 28 | 29 | // Should not be "dirty" after reverting values. 30 | Assert.IsFalse(customer.IsDirty); 31 | Assert.AreEqual(ORIGINAL_ADDRESS, customer.Address); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /TestEngine/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestEngine")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestEngine")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c5fb76aa-6b81-4edd-ab62-4786ee82440d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /TestEngine/PrototypePattern/NonPatternVersion/TestMonster.cs: -------------------------------------------------------------------------------- 1 | using Engine.PrototypePattern.NonPatternVersion; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.PrototypePattern.NonPatternVersion 5 | { 6 | [TestClass] 7 | public class TestMonster 8 | { 9 | [TestMethod] 10 | public void Test_ReferenceProblem() 11 | { 12 | Monster spider1 = new Monster("Giant Spider", 10); 13 | Monster spider2 = spider1; 14 | 15 | Assert.AreEqual(10, spider1.HitPoints); 16 | Assert.AreEqual(10, spider2.HitPoints); 17 | 18 | spider2.ApplyDamage(2); 19 | 20 | // Even though we only called ApplyDamage on spider2, 21 | // the HitPoints for both spider objects is 8. 22 | // 23 | // This is because the spider variables are pointing to (referencing) 24 | // a single spider object - the original spider1. 25 | Assert.AreEqual(8, spider1.HitPoints); 26 | Assert.AreEqual(8, spider2.HitPoints); 27 | } 28 | 29 | [TestMethod] 30 | public void Test_ReferenceProblemSolution() 31 | { 32 | Monster spider1 = new Monster("Giant Spider", 10); 33 | Monster spider2 = new Monster("Giant Spider", 10); 34 | 35 | Assert.AreEqual(10, spider1.HitPoints); 36 | Assert.AreEqual(10, spider2.HitPoints); 37 | 38 | spider2.ApplyDamage(2); 39 | 40 | // There is no reference problem, 41 | // because we created spider2 by calling the Monster constructor. 42 | Assert.AreEqual(10, spider1.HitPoints); 43 | Assert.AreEqual(8, spider2.HitPoints); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TestEngine/PrototypePattern/PatternVersion_Simple/TestMonster.cs: -------------------------------------------------------------------------------- 1 | using Engine.PrototypePattern.PatternVersion_Simple; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace TestEngine.PrototypePattern.PatternVersion_Simple 5 | { 6 | [TestClass] 7 | public class TestMonster 8 | { 9 | [TestMethod] 10 | public void Test_PrototypePattern() 11 | { 12 | Monster standardGiantSpider = new Monster("Giant Spider", 10); 13 | 14 | // Calling the Clone method is how the Prototype Pattern is implemented. 15 | Monster spider2 = standardGiantSpider.Clone(); 16 | 17 | Assert.AreEqual(10, standardGiantSpider.HitPoints); 18 | Assert.AreEqual(10, spider2.HitPoints); 19 | 20 | spider2.ApplyDamage(2); 21 | 22 | // There is no reference problem, 23 | // because the Clone method constructs a new Monster object. 24 | Assert.AreEqual(10, standardGiantSpider.HitPoints); 25 | Assert.AreEqual(8, spider2.HitPoints); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /TestEngine/StrategyPattern/NonPatternVersion_MultipleMethods/TestCalculator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Engine.StrategyPattern.NonPatternVersion_MultipleMethods; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace TestEngine.StrategyPattern.NonPatternVersion_MultipleMethods 7 | { 8 | [TestClass] 9 | public class TestCalculator 10 | { 11 | private readonly List _values = new List {10, 5, 7, 15, 13, 12, 8, 7, 4, 2, 9}; 12 | 13 | [TestMethod] 14 | public void Test_AverageByMean() 15 | { 16 | Calculator calculator = new Calculator(); 17 | 18 | var averageByMean = calculator.CalculateAverageByMean(_values); 19 | 20 | Assert.IsTrue(ResultsAreCloseEnough(8.3636363, averageByMean)); 21 | } 22 | 23 | [TestMethod] 24 | public void Test_AverageByMedian() 25 | { 26 | Calculator calculator = new Calculator(); 27 | 28 | var averageByMedian = calculator.CalculateAverageByMedian(_values); 29 | 30 | Assert.IsTrue(ResultsAreCloseEnough(8, averageByMedian)); 31 | } 32 | 33 | // Because we are using doubles (floating point values), the values may not exactly match. 34 | // If the difference between the expected result, and the calculated result is less than .000001, 35 | // consider the two values as "equal". 36 | private bool ResultsAreCloseEnough(double expectedResult, double calculatedResult) 37 | { 38 | var difference = Math.Abs(expectedResult - calculatedResult); 39 | 40 | return difference < .000001; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /TestEngine/StrategyPattern/NonPatternVersion_SingleMethod/TestCalculator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Engine.StrategyPattern.NonPatternVersion_SingleMethod; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace TestEngine.StrategyPattern.NonPatternVersion_SingleMethod 7 | { 8 | [TestClass] 9 | public class TestCalculator 10 | { 11 | private readonly List _values = new List {10, 5, 7, 15, 13, 12, 8, 7, 4, 2, 9}; 12 | 13 | [TestMethod] 14 | public void Test_AverageByMean() 15 | { 16 | Calculator calculator = new Calculator(); 17 | 18 | var averageByMean = calculator.CalculateAverage(_values, Calculator.AveragingMethod.Mean); 19 | 20 | Assert.IsTrue(ResultsAreCloseEnough(8.3636363, averageByMean)); 21 | } 22 | 23 | [TestMethod] 24 | public void Test_AverageByMedian() 25 | { 26 | Calculator calculator = new Calculator(); 27 | 28 | var averageByMedian = calculator.CalculateAverage(_values, Calculator.AveragingMethod.Median); 29 | 30 | Assert.IsTrue(ResultsAreCloseEnough(8, averageByMedian)); 31 | } 32 | 33 | // Because we are using doubles (floating point values), the values may not exactly match. 34 | // If the difference between the expected result, and the calculated result is less than .000001, 35 | // consider the two values as "equal". 36 | private bool ResultsAreCloseEnough(double expectedResult, double calculatedResult) 37 | { 38 | var difference = Math.Abs(expectedResult - calculatedResult); 39 | 40 | return difference < .000001; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /TestEngine/StrategyPattern/PatternVersion/TestCalculator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Engine.StrategyPattern.PatternVersion; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace TestEngine.StrategyPattern.PatternVersion 7 | { 8 | [TestClass] 9 | public class TestCalculator 10 | { 11 | private readonly List _values = new List {10, 5, 7, 15, 13, 12, 8, 7, 4, 2, 9}; 12 | 13 | [TestMethod] 14 | public void Test_AverageByMean() 15 | { 16 | Calculator calculator = new Calculator(); 17 | 18 | var averageByMean = calculator.CalculateAverageFor(_values, new AverageByMean()); 19 | 20 | Assert.IsTrue(ResultsAreCloseEnough(8.3636363, averageByMean)); 21 | } 22 | 23 | [TestMethod] 24 | public void Test_AverageByMedian() 25 | { 26 | Calculator calculator = new Calculator(); 27 | 28 | var averageByMedian = calculator.CalculateAverageFor(_values, new AverageByMedian()); 29 | 30 | Assert.IsTrue(ResultsAreCloseEnough(8, averageByMedian)); 31 | } 32 | 33 | // Because we are using doubles (floating point values), the values may not exactly match. 34 | // If the difference between the expected result, and the calculated result is less than .000001, 35 | // consider the two values as "equal". 36 | private bool ResultsAreCloseEnough(double expectedResult, double calculatedResult) 37 | { 38 | var difference = Math.Abs(expectedResult - calculatedResult); 39 | 40 | return difference < .000001; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /WorckbenchWinForms/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WorckbenchWinForms/MVVMPattern/PatternVersion/AccountCreationView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using Engine.MVVMPattern.PatternVersion.ViewModels; 4 | 5 | namespace WorckbenchWinForms.MVVMPattern.PatternVersion 6 | { 7 | public partial class AccountCreationView : Form 8 | { 9 | private readonly AccountCreationViewModel _viewModel = new AccountCreationViewModel(); 10 | 11 | public AccountCreationView() 12 | { 13 | InitializeComponent(); 14 | 15 | label_ValidationMessage.DataBindings.Add(new Binding("Text", _viewModel, "NewAccount.ValidationMessage",true)); 16 | textBox_Password.DataBindings.Add(new Binding("Text", _viewModel, "NewAccount.Password", true)); 17 | } 18 | 19 | private void OnClick_ValidatePassword(object sender, EventArgs e) 20 | { 21 | _viewModel.ValidatePassword(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /WorckbenchWinForms/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WorckbenchWinForms 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Variable nécessaire au concepteur. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Nettoyage des ressources utilisées. 12 | /// 13 | /// true si les ressources managées doivent être supprimées ; sinon, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Code généré par le Concepteur Windows Form 24 | 25 | /// 26 | /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas 27 | /// le contenu de cette méthode avec l'éditeur de code. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.button = new System.Windows.Forms.Button(); 32 | this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); 33 | this.tableLayoutPanel1.SuspendLayout(); 34 | this.SuspendLayout(); 35 | // 36 | // button 37 | // 38 | this.button.Dock = System.Windows.Forms.DockStyle.Fill; 39 | this.button.Location = new System.Drawing.Point(189, 132); 40 | this.button.Name = "button"; 41 | this.button.Size = new System.Drawing.Size(181, 53); 42 | this.button.TabIndex = 0; 43 | this.button.Text = "MVVM Pattern: Pattern version"; 44 | this.button.UseVisualStyleBackColor = true; 45 | this.button.Click += new System.EventHandler(this.OnClick_MVVMPattern_PatternVersion); 46 | // 47 | // tableLayoutPanel1 48 | // 49 | this.tableLayoutPanel1.ColumnCount = 3; 50 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); 51 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33334F)); 52 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33334F)); 53 | this.tableLayoutPanel1.Controls.Add(this.button, 1, 1); 54 | this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; 55 | this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); 56 | this.tableLayoutPanel1.Name = "tableLayoutPanel1"; 57 | this.tableLayoutPanel1.RowCount = 3; 58 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 40.65041F)); 59 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 18.69918F)); 60 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 40.65041F)); 61 | this.tableLayoutPanel1.Size = new System.Drawing.Size(561, 319); 62 | this.tableLayoutPanel1.TabIndex = 2; 63 | // 64 | // MainForm 65 | // 66 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 67 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 68 | this.ClientSize = new System.Drawing.Size(561, 319); 69 | this.Controls.Add(this.tableLayoutPanel1); 70 | this.Name = "MainForm"; 71 | this.Text = "MainForm"; 72 | this.tableLayoutPanel1.ResumeLayout(false); 73 | this.ResumeLayout(false); 74 | 75 | } 76 | 77 | #endregion 78 | 79 | private System.Windows.Forms.Button button; 80 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /WorckbenchWinForms/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace WorckbenchWinForms 12 | { 13 | public partial class MainForm : Form 14 | { 15 | public MainForm() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void OnClick_MVVMPattern_PatternVersion(object sender, EventArgs e) 21 | { 22 | MVVMPattern.PatternVersion.AccountCreationView view = 23 | new MVVMPattern.PatternVersion.AccountCreationView(); 24 | 25 | view.ShowDialog(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /WorckbenchWinForms/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using WorckbenchWinForms.MVVMPattern.PatternVersion; 4 | 5 | namespace WorckbenchWinForms 6 | { 7 | static class Program 8 | { 9 | /// 10 | /// Point d'entrée principal de l'application. 11 | /// 12 | [STAThread] 13 | static void Main() 14 | { 15 | Application.EnableVisualStyles(); 16 | Application.SetCompatibleTextRenderingDefault(false); 17 | Application.Run(new MainForm()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /WorckbenchWinForms/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Les informations générales relatives à un assembly dépendent de 6 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations 7 | // associées à un assembly. 8 | [assembly: AssemblyTitle("WorckbenchWinForms")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WorckbenchWinForms")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly 18 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de 19 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM 23 | [assembly: Guid("fabf680c-2a7c-4011-adbe-bd1a5b612f0d")] 24 | 25 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes : 26 | // 27 | // Version principale 28 | // Version secondaire 29 | // Numéro de build 30 | // Révision 31 | // 32 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut 33 | // en utilisant '*', comme indiqué ci-dessous : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WorckbenchWinForms/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Ce code a été généré par un outil. 4 | // Version du runtime :4.0.30319.42000 5 | // 6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si 7 | // le code est régénéré. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WorckbenchWinForms.Properties 12 | { 13 | 14 | 15 | /// 16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. 17 | /// 18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder 19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio. 20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen 21 | // avec l'option /str ou régénérez votre projet VS. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WorckbenchWinForms.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes 56 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /WorckbenchWinForms/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WorckbenchWinForms.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /WorckbenchWinForms/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WorckbenchWinForms/WorckbenchWinForms.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FABF680C-2A7C-4011-ADBE-BD1A5B612F0D} 8 | WinExe 9 | WorckbenchWinForms 10 | WorckbenchWinForms 11 | v4.6.1 12 | 512 13 | true 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Form 50 | 51 | 52 | MainForm.cs 53 | 54 | 55 | Form 56 | 57 | 58 | AccountCreationView.cs 59 | 60 | 61 | 62 | 63 | MainForm.cs 64 | 65 | 66 | AccountCreationView.cs 67 | 68 | 69 | ResXFileCodeGenerator 70 | Resources.Designer.cs 71 | Designer 72 | 73 | 74 | True 75 | Resources.resx 76 | 77 | 78 | SettingsSingleFileGenerator 79 | Settings.Designer.cs 80 | 81 | 82 | True 83 | Settings.settings 84 | True 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | {25d0207b-a871-4ef6-a23b-1ff7b15306fe} 93 | Engine 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Workbench/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Workbench/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Workbench 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if(disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btnTest = new System.Windows.Forms.Button(); 32 | this.SuspendLayout(); 33 | // 34 | // btnTest 35 | // 36 | this.btnTest.Location = new System.Drawing.Point(105, 119); 37 | this.btnTest.Name = "btnTest"; 38 | this.btnTest.Size = new System.Drawing.Size(75, 23); 39 | this.btnTest.TabIndex = 0; 40 | this.btnTest.Text = "Test"; 41 | this.btnTest.UseVisualStyleBackColor = true; 42 | this.btnTest.Click += new System.EventHandler(this.btnTest_Click); 43 | // 44 | // Form1 45 | // 46 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 47 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 48 | this.ClientSize = new System.Drawing.Size(284, 261); 49 | this.Controls.Add(this.btnTest); 50 | this.Name = "Form1"; 51 | this.Text = "Form1"; 52 | this.ResumeLayout(false); 53 | 54 | } 55 | 56 | #endregion 57 | 58 | private System.Windows.Forms.Button btnTest; 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /Workbench/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using Engine.PublishSubscribePattern.PatternVersion.Models; 4 | 5 | namespace Workbench 6 | { 7 | public partial class Form1 : Form 8 | { 9 | private readonly Player _currentPlayer = new Player {HitPoints = 10}; 10 | 11 | public Form1() 12 | { 13 | InitializeComponent(); 14 | 15 | _currentPlayer.PlayerKilled += PlayerKilled; 16 | } 17 | 18 | private void PlayerKilled(object sender, EventArgs eventArgs) 19 | { 20 | MessageBox.Show("Got here!"); 21 | } 22 | 23 | private void btnTest_Click(object sender, EventArgs e) 24 | { 25 | _currentPlayer.HitPoints -= 3; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Workbench/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace Workbench 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new Form1()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Workbench/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Workbench")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Workbench")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a3102e09-45c1-482e-8650-48ce48b3fbb4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Workbench/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Workbench.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Workbench.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Workbench/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Workbench.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Workbench/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Workbench/Workbench.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A3102E09-45C1-482E-8650-48CE48B3FBB4} 8 | WinExe 9 | Properties 10 | Workbench 11 | Workbench 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Form 51 | 52 | 53 | Form1.cs 54 | 55 | 56 | 57 | 58 | Form1.cs 59 | 60 | 61 | ResXFileCodeGenerator 62 | Resources.Designer.cs 63 | Designer 64 | 65 | 66 | True 67 | Resources.resx 68 | 69 | 70 | SettingsSingleFileGenerator 71 | Settings.Designer.cs 72 | 73 | 74 | True 75 | Settings.settings 76 | True 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | {25d0207b-a871-4ef6-a23b-1ff7b15306fe} 85 | Engine 86 | 87 | 88 | 89 | 96 | -------------------------------------------------------------------------------- /WorkbenchWPF/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /WorkbenchWPF/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WorkbenchWPF/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace WorkbenchWPF 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WorkbenchWPF/MVVMPattern/NonPatternVersion/AccountCreationView.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 30 |