├── .gitattributes ├── .gitignore ├── DesignPattern ├── AdpterPattern │ ├── AdpterPattern.csproj │ ├── App.config │ ├── FileAdapter.cs │ ├── FileReader.cs │ ├── IPlugin.cs │ ├── IReadData.cs │ ├── KoreaPlugin.cs │ ├── MyPhone.cs │ ├── Plugadapter.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Readme.md │ └── WebReader.cs ├── BridgePattern │ ├── AdidasBag.cs │ ├── App.config │ ├── BagBase.cs │ ├── BridgePattern.csproj │ ├── ColorBase.cs │ ├── ColorBlue.cs │ ├── ColorRed.cs │ ├── NickBag.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Readme.md ├── CommandPattern │ ├── App.config │ ├── CommandPattern.csproj │ ├── DishList.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── chief.cs ├── CommandPatternDemo │ ├── CommandPatternDemo.csproj │ ├── IStateCommnad.cs │ ├── Product.cs │ ├── ProductState.cs │ └── Program.cs ├── CompositePattern │ ├── App.config │ ├── CompositePattern.csproj │ ├── Program.cs │ └── Properties │ │ └── AssemblyInfo.cs ├── DecoratePattern │ ├── DecoratePattern │ │ ├── App.config │ │ ├── DecoratePattern.csproj │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ └── packages.config │ ├── DecoratePatternTests │ │ ├── DecoratorTests.csproj │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── ZipProcessTests.cs │ │ └── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Readme.md ├── DesignPattern.sln ├── FactoryMethodPattern │ ├── App.config │ ├── Car.cs │ ├── CarFactory.cs │ ├── FactoryMethodPattern.csproj │ ├── IFactory.cs │ ├── IFireable.cs │ ├── IMoveable.cs │ ├── Plane.cs │ ├── PlaneFactory.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Tank.cs │ └── Warships.cs ├── MediatorPattern │ ├── App.config │ ├── DBAdmin.cs │ ├── MediatorPattern.csproj │ ├── OriginReqBase.cs │ ├── ProductManager.cs │ ├── Program.cs │ ├── Programer.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Readme.md │ └── packages.config ├── NullObjectPattern │ ├── App.config │ ├── CartModel.cs │ ├── Items.cs │ ├── NullObjectPattern.csproj │ ├── PaymentService.cs │ ├── PaymentServiceNormal.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Readme.md ├── ObserverPattern │ ├── App.config │ ├── IObserveable.cs │ ├── ObserverPattern.csproj │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Taiwanese.cs │ └── Youtuber.cs ├── ProxyPattern │ ├── App.config │ ├── DynamicProxy │ │ ├── DynamicProxy.cs │ │ ├── IInterception.cs │ │ ├── LogAttribute.cs │ │ └── Logicservice.cs │ ├── MockUserData.cs │ ├── Normal │ │ └── LoginService.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ProxyPattern.csproj │ ├── Readme.md │ ├── StaticProxy │ │ ├── ISubject.cs │ │ ├── LogicProxyService.cs │ │ └── Logicservice.cs │ └── UserModel.cs ├── SimpleFactory │ ├── App.config │ ├── ConnectionFactory.cs │ ├── DBType.cs │ ├── IDbConcrete.cs │ ├── MSSQL.cs │ ├── MySQL.cs │ ├── Oracle.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Readme.md │ └── SimpleFactory.csproj ├── StatePattern │ ├── App.config │ ├── Normal │ │ └── PaymentContext.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Readme.md │ ├── State │ │ ├── CancelStatus.cs │ │ ├── InitStatus.cs │ │ ├── PaymentGate.cs │ │ ├── PaymentStatusBase.cs │ │ ├── ProcessStatus.cs │ │ └── SuccessStatus.cs │ ├── StatePattern.csproj │ └── StatePattern.csproj.DotSettings ├── StatePatternTests │ ├── Normal │ │ └── PaymentContextTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── StatePatternTests.csproj ├── StrategyPattern │ ├── App.config │ ├── Person.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SortExtension.cs │ ├── Strategy │ │ ├── CompareInt.cs │ │ ├── ComparePerson.cs │ │ └── ICompareStrategy.cs │ └── StrategyPattern.csproj ├── StrategyPatternTests │ ├── CompareIntTests.cs │ ├── ComparePersonTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── StrategyPatternTests.csproj ├── TemplatePattern │ ├── App.config │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Readme.md │ ├── TemplatePattern.csproj │ ├── UnitCounter.cs │ └── UnitFlowBase.cs └── img │ ├── Adpter │ ├── Adaper.jpg │ └── Plugin.jpg │ ├── Bridge │ ├── BridgePattern1.PNG │ └── brigdeUML.png │ ├── Decorator │ ├── 0c8920b50c8eea2da95c25a033f19872.jpg │ ├── 688215012311271.jpg │ ├── Thumbs.db │ └── decorator.png │ ├── Status │ └── 1.png │ ├── TemplateMethod │ └── TemplateMethod.PNG │ └── simpleFactory │ └── simpleFatory.png ├── LICENSE └── Readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | *.vcxproj.filters 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # .NET Core 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | **/Properties/launchSettings.json 51 | 52 | *_i.c 53 | *_p.c 54 | *_i.h 55 | *.ilk 56 | *.meta 57 | *.obj 58 | *.pch 59 | *.pdb 60 | *.pgc 61 | *.pgd 62 | *.rsp 63 | *.sbr 64 | *.tlb 65 | *.tli 66 | *.tlh 67 | *.tmp 68 | *.tmp_proj 69 | *.log 70 | *.vspscc 71 | *.vssscc 72 | .builds 73 | *.pidb 74 | *.svclog 75 | *.scc 76 | 77 | # Chutzpah Test files 78 | _Chutzpah* 79 | 80 | # Visual C++ cache files 81 | ipch/ 82 | *.aps 83 | *.ncb 84 | *.opendb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | *.VC.db 89 | *.VC.VC.opendb 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | *.sap 96 | 97 | # TFS 2012 Local Workspace 98 | $tf/ 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | *.DotSettings.user 107 | 108 | # JustCode is a .NET coding add-in 109 | .JustCode 110 | 111 | # TeamCity is a build add-in 112 | _TeamCity* 113 | 114 | # DotCover is a Code Coverage Tool 115 | *.dotCover 116 | 117 | # Visual Studio code coverage results 118 | *.coverage 119 | *.coveragexml 120 | 121 | # NCrunch 122 | _NCrunch_* 123 | .*crunch*.local.xml 124 | nCrunchTemp_* 125 | 126 | # MightyMoose 127 | *.mm.* 128 | AutoTest.Net/ 129 | 130 | # Web workbench (sass) 131 | .sass-cache/ 132 | 133 | # Installshield output folder 134 | [Ee]xpress/ 135 | 136 | # DocProject is a documentation generator add-in 137 | DocProject/buildhelp/ 138 | DocProject/Help/*.HxT 139 | DocProject/Help/*.HxC 140 | DocProject/Help/*.hhc 141 | DocProject/Help/*.hhk 142 | DocProject/Help/*.hhp 143 | DocProject/Help/Html2 144 | DocProject/Help/html 145 | 146 | # Click-Once directory 147 | publish/ 148 | 149 | # Publish Web Output 150 | *.[Pp]ublish.xml 151 | *.azurePubxml 152 | # TODO: Comment the next line if you want to checkin your web deploy settings 153 | # but database connection strings (with potential passwords) will be unencrypted 154 | *.pubxml 155 | *.publishproj 156 | 157 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 158 | # checkin your Azure Web App publish settings, but sensitive information contained 159 | # in these scripts will be unencrypted 160 | PublishScripts/ 161 | 162 | # NuGet Packages 163 | *.nupkg 164 | # The packages folder can be ignored because of Package Restore 165 | **/packages/* 166 | # except build/, which is used as an MSBuild target. 167 | !**/packages/build/ 168 | # Uncomment if necessary however generally it will be regenerated when needed 169 | #!**/packages/repositories.config 170 | # NuGet v3's project.json files produces more ignoreable files 171 | *.nuget.props 172 | *.nuget.targets 173 | 174 | # Microsoft Azure Build Output 175 | csx/ 176 | *.build.csdef 177 | 178 | # Microsoft Azure Emulator 179 | ecf/ 180 | rcf/ 181 | 182 | # Windows Store app package directories and files 183 | AppPackages/ 184 | BundleArtifacts/ 185 | Package.StoreAssociation.xml 186 | _pkginfo.txt 187 | 188 | # Visual Studio cache files 189 | # files ending in .cache can be ignored 190 | *.[Cc]ache 191 | # but keep track of directories ending in .cache 192 | !*.[Cc]ache/ 193 | 194 | # Others 195 | ClientBin/ 196 | ~$* 197 | *~ 198 | *.dbmdl 199 | *.dbproj.schemaview 200 | *.jfm 201 | *.pfx 202 | *.publishsettings 203 | node_modules/ 204 | orleans.codegen.cs 205 | 206 | # Since there are multiple workflows, uncomment next line to ignore bower_components 207 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 208 | #bower_components/ 209 | 210 | # RIA/Silverlight projects 211 | Generated_Code/ 212 | 213 | # Backup & report files from converting an old project file 214 | # to a newer Visual Studio version. Backup files are not needed, 215 | # because we have git ;-) 216 | _UpgradeReport_Files/ 217 | Backup*/ 218 | UpgradeLog*.XML 219 | UpgradeLog*.htm 220 | 221 | # SQL Server files 222 | *.mdf 223 | *.ldf 224 | 225 | # Business Intelligence projects 226 | *.rdl.data 227 | *.bim.layout 228 | *.bim_*.settings 229 | 230 | # Microsoft Fakes 231 | FakesAssemblies/ 232 | 233 | # GhostDoc plugin setting file 234 | *.GhostDoc.xml 235 | 236 | # Node.js Tools for Visual Studio 237 | .ntvs_analysis.dat 238 | 239 | # Visual Studio 6 build log 240 | *.plg 241 | 242 | # Visual Studio 6 workspace options file 243 | *.opt 244 | 245 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 246 | *.vbw 247 | 248 | # Visual Studio LightSwitch build output 249 | **/*.HTMLClient/GeneratedArtifacts 250 | **/*.DesktopClient/GeneratedArtifacts 251 | **/*.DesktopClient/ModelManifest.xml 252 | **/*.Server/GeneratedArtifacts 253 | **/*.Server/ModelManifest.xml 254 | _Pvt_Extensions 255 | 256 | # Paket dependency manager 257 | .paket/paket.exe 258 | paket-files/ 259 | 260 | # FAKE - F# Make 261 | .fake/ 262 | 263 | # JetBrains Rider 264 | .idea/ 265 | *.sln.iml 266 | 267 | # CodeRush 268 | .cr/ 269 | 270 | # Python Tools for Visual Studio (PTVS) 271 | __pycache__/ 272 | *.pyc 273 | 274 | # Cake - Uncomment if you are using it 275 | # tools/ 276 | 277 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/AdpterPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2348B810-4970-4B49-B839-492338FAA74A} 8 | Exe 9 | Properties 10 | AdapterPattern 11 | AdapterPattern 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 | 51 | 58 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/FileAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace AdapterPattern 2 | { 3 | public class FileAdapter : IReadData 4 | { 5 | public string GetJsonData(string parameter) 6 | { 7 | var reader = new FileReader(); 8 | return reader.Read(parameter); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/FileReader.cs: -------------------------------------------------------------------------------- 1 | namespace AdapterPattern 2 | { 3 | public class FileReader 4 | { 5 | public string Read(string parameter) 6 | { 7 | string result = string.Empty; 8 | //實作硬碟讀取 9 | return result; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/IPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace AdapterPattern 7 | { 8 | public interface IPlugin 9 | { 10 | int Power(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/IReadData.cs: -------------------------------------------------------------------------------- 1 | namespace AdapterPattern 2 | { 3 | public interface IReadData 4 | { 5 | string GetJsonData(string parameter); 6 | } 7 | } -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/KoreaPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace AdapterPattern 7 | { 8 | public class KoreaPlugin 9 | { 10 | public int Power() { 11 | return 220; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/MyPhone.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace AdapterPattern 7 | { 8 | public class MyPhone 9 | { 10 | /// 11 | /// 對手機充電 12 | /// 13 | public void Fill_Cellphone(int power) { 14 | if (power==110) 15 | { 16 | Console.WriteLine("充電成功"); 17 | } 18 | else 19 | { 20 | Console.WriteLine("電壓太高!手機爆炸!"); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/Plugadapter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace AdapterPattern 7 | { 8 | public class PlugAdapter: IPlugin 9 | { 10 | private KoreaPlugin _plugin; 11 | /// 12 | /// 13 | /// 14 | /// 15 | public PlugAdapter(KoreaPlugin plugin) { 16 | _plugin = plugin; 17 | } 18 | 19 | public int Power() 20 | { 21 | return _plugin.Power()-110; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace AdapterPattern 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | #region 手機爆炸 13 | KoreaPlugin p = new KoreaPlugin(); 14 | int power = p.Power(); 15 | MyPhone phone = new MyPhone(); 16 | phone.Fill_Cellphone(power); 17 | #endregion; 18 | PlugAdapter adapter = new PlugAdapter(new KoreaPlugin()); 19 | int power_safe = adapter.Power(); 20 | phone.Fill_Cellphone(power_safe); 21 | 22 | Console.ReadKey(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("AdpterPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AdpterPattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("2348b810-4970-4b49-b839-492338faa74a")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/Readme.md: -------------------------------------------------------------------------------- 1 | ## AdpterPattern,轉接器模式 2 | 3 | 轉接器模式 是一個蠻實用的設計範式 4 | 5 | 舉例: 6 | 7 | 前一陣子出國去韓國玩,有去韓國的朋友都知道他們的插座和台灣的插座不一樣 而且電壓是220V,到這我也是矇了 8 | 9 | ![Alt text](../img/Adpter/Plugin.jpg "Optional title") 10 | 11 | (圖片來源:網路截圖) 12 | 13 | 所幸導遊有給我們插頭的轉接器,讓我們用可以幫我解決 14 | 15 | ![Alt text](../img/Adpter/Adaper.jpg "Optional title") 16 | 17 | (圖片來源:網路截圖) 18 | 19 | 1. 電壓220V->110V 20 | 2. 形狀可以符合台灣一般的插頭 21 | 22 | > 為什麼會舉這個例子呢? 23 | 24 | 因為轉接器模式和我剛剛舉的例子有異曲同工之妙 25 | 26 | ----- 27 | 28 | 例子來寫個簡單的小程式: 29 | 30 | 首先我們先創建一個類別`KoreaPlugin`(韓國插座) 31 | 32 | 裡面有個方法: 33 | 34 | Power供電220V 35 | 36 | ```C# 37 | public class KoreaPlugin 38 | { 39 | public int Power(){ 40 | return 220; 41 | } 42 | } 43 | ``` 44 | 45 | 在創建一個類我的手機: 46 | 47 | 他只能承受110V的電壓 48 | 49 | 超過就爆炸了!! 50 | 51 | ```C# 52 | public class MyPhone 53 | { 54 | /// 55 | /// 對手機充電 56 | /// 57 | public void Fill_Cellphone(int power) { 58 | if (power==110) 59 | { 60 | Console.WriteLine("充電成功"); 61 | } 62 | else 63 | { 64 | Console.WriteLine("電壓太高!手機爆炸!"); 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | 如果要充電怎麼辦? 71 | 72 | 這時我們的轉接頭發揮功用了 73 | 74 | 創建一個轉接頭的類別: 75 | 76 | ```C# 77 | public class PlugAdapter: IPlugin 78 | { 79 | private KoreaPlugin _plugin; 80 | /// 81 | /// 82 | /// 83 | /// 84 | public PlugAdapter(KoreaPlugin plugin) 85 | { 86 | _plugin = plugin; 87 | } 88 | 89 | public int Power() 90 | { 91 | return _plugin.Power()-110; 92 | } 93 | } 94 | ``` 95 | 96 | 在上面可以看到它 內部幫我們做了電壓轉換 (重要注意!!) 97 | 98 | 所以我們就可以進行充電了 99 | 100 | ```c# 101 | static void Main(string[] args) 102 | { 103 | #region 手機爆炸 104 | KoreaPlugin p = new KoreaPlugin(); 105 | int power = p.Power(); 106 | MyPhone phone = new MyPhone(); 107 | phone.Fill_Cellphone(power); 108 | #endregion; 109 | 110 | #region 正常充電 111 | IPlugin adapter = new PlugAdapter(new KoreaPlugin()); 112 | int power_safe = adapter.Power(); 113 | phone.Fill_Cellphone(power_safe); 114 | #endregion; 115 | 116 | Console.ReadKey(); 117 | } 118 | ``` 119 | 120 | 現實生活中轉接器幫我解決 121 | 122 | 可用110V充電 123 | 用台灣一般的插頭充電 124 | 而內部實現機制我們不用理只管用就好 125 | 126 | 就像上面的範例: 127 | 128 | `PlugAdapter`在內部幫我們進行電壓轉換封裝,而我們可以直接用就好 129 | 130 | `AdapterPattern`使用時機: 131 | 132 | 有一或多個類別或介面,不符合我們的需求 133 | 134 | 但不能在裡面直接改內部方法或實現方式 135 | 136 | 那我們可以使用`AdapterPattern`來當我們的轉換器 137 | 138 | 轉成我適合我們使用介面或接口 139 | 140 | ----- 141 | 142 | ## 實戰範例: 143 | 144 | 需求要讀取資料,所以我們有一個類別`FileReader` 145 | 146 | 裡面有一個`Read`方法來讀取硬碟資料 147 | 148 | ```c# 149 | public class FileReader 150 | { 151 | public string Read(string parameter) 152 | { 153 | string result = string.Empty; 154 | //實作硬碟讀取 155 | return result; 156 | } 157 | } 158 | ``` 159 | 160 | 日後需求增加可能從網路,資料庫其他來源讀取我們要的資料,所以我們開出一個 **Interface** 可以搭配[工廠模式](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/SimpleFactory) 來掌控我們的產品 161 | 162 | ```c# 163 | public interface IReadData 164 | { 165 | string GetJsonData(string parameter); 166 | } 167 | ``` 168 | 169 | 新增的`WebReader`可以繼承此介面 170 | 171 | ```c# 172 | /// 173 | /// 從網路上讀取要的資料 174 | /// 175 | public class WebReader : IReadData 176 | { 177 | public string GetJsonData(string parameter) 178 | { 179 | string result = string.Empty; 180 | //實作網路讀取 181 | return result; 182 | } 183 | } 184 | ``` 185 | 186 | 但如果想讓舊有的`FileReader`也共享此介面怎麼處理呢? 187 | 188 | 這時可以考慮使用`Adapter` 來做銜接處理 189 | 190 | ```c# 191 | public class FileAdapter : IReadData 192 | { 193 | public string GetJsonData(string parameter) 194 | { 195 | var reader = new FileReader(); 196 | return reader.Read(parameter); 197 | } 198 | } 199 | ``` 200 | 201 | 建立一個`FileAdapter`並實現`IReadData`裡的方法,我們可以看到裡面我們一樣是使用`FileReader`,但外部的看到的介面已經不一樣了. 202 | 203 | 我們就可以讓`WebReader`和`FileAdapter` 達成相同介面. 204 | 205 | 206 | -------------------------------------------------------------------------------- /DesignPattern/AdpterPattern/WebReader.cs: -------------------------------------------------------------------------------- 1 | namespace AdapterPattern 2 | { 3 | /// 4 | /// 從網路上讀取要的資料 5 | /// 6 | public class WebReader : IReadData 7 | { 8 | public string GetJsonData(string parameter) 9 | { 10 | string result = string.Empty; 11 | //實作網路讀取 12 | return result; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/AdidasBag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | public class AdidasBag : BagBase 9 | { 10 | public AdidasBag(ColorBase color) : base(color) 11 | { 12 | } 13 | 14 | public override void GetBag() 15 | { 16 | Console.WriteLine($"It is Adidas Bag,Color is {color.Color()}"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/BagBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | public abstract class BagBase 9 | { 10 | protected ColorBase color{ get; set; } 11 | 12 | public BagBase(ColorBase color) { 13 | this.color = color; 14 | } 15 | public abstract void GetBag(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/BridgePattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AB99CF29-C71A-4F11-9E81-7DE2FB2AE96C} 8 | Exe 9 | Properties 10 | BridgePattern 11 | BridgePattern 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 | 51 | 52 | 53 | 60 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/ColorBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | public abstract class ColorBase 9 | { 10 | public abstract string Color(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/ColorBlue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | class ColorBlue : ColorBase 9 | { 10 | public override string Color() 11 | { 12 | return "Blue"; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/ColorRed.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | public class ColorRed : ColorBase 9 | { 10 | public override string Color() 11 | { 12 | return "Red"; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/NickBag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | public class NickBag : BagBase 9 | { 10 | public NickBag(ColorBase color) : base(color) 11 | { 12 | } 13 | 14 | public override void GetBag() 15 | { 16 | Console.WriteLine($"It is nick Bag,Color is {color.Color()}"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace BridgePattern 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | AdidasBag nick = new AdidasBag(new ColorBlue()); 13 | nick.GetBag(); 14 | Console.ReadKey(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("BridgePattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("BridgePattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("ab99cf29-c71a-4f11-9e81-7de2fb2ae96c")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/BridgePattern/Readme.md: -------------------------------------------------------------------------------- 1 | # 橋接模式(BridgePattern) 2 | 3 | 目的: 4 | 如果有兩大類模組是多對多的組合,如本次Smaple Code. Nick和Addidas 包包都有紅、藍、黃....或其他顏色 5 | 6 | 就可能呈現下面6種組合 7 | 8 | * Nick(紅) 9 | * Nick(藍) 10 | * Nick(黃) 11 | * Addidas(紅) 12 | * Addidas(藍) 13 | * Addidas(黃) 14 | 15 | 如果此建立類別的話 可能情況如下面的UNL圖 16 | 17 | ![bridge](../img/Bridge/BridgePattern1.PNG) 18 | 19 | > 類別數量 = 顏色數量 * 包包品牌數量 20 | 21 | 這樣會有兩個問題 22 | 23 | 1. 隨著品牌和顏色增多,包包類別數量急速增長 **(X = m*n)個** 24 | 2. 顏色我們可看做一個抽象 不應當和包包合在一起 25 | 26 | 其中的第二點我覺得最重要 27 | 28 | 這時候就很適合帶入我們的主角**BridgePattern** 29 | 30 | ---- 31 | 32 | ## 範例介紹 33 | 34 | 關係變成下圖UML 35 | 36 | ![bridge](../img/Bridge/brigdeUML.png) 37 | 38 | 我們可以看到`BagBsae`去引用`ColorBase` 可以看到我們所需的子類別變成五個而已,重點是類別關係變得更有條理了,顏色和包包分開可調整性更大。 39 | 40 | OOP有一個很重要的設計觀念 41 | > 盡量用組合取代繼承,因為繼承耦合性遠大於組合! 42 | 43 | 因為子類別繼承父類別,子類別無條件都擁有protect已上的方法或成員資料.這就會造成一個耦合性(使用繼承須看情況),而A類別對於B類別進行組合就可達到繼承效果但不造成像繼承般的強耦合. 44 | 45 | 我們的背包一樣可擁有多種顏色,但耦合度跟類別關係變得更清晰了。 46 | 47 | ----- 48 | 49 | ## 程式碼解說 50 | 51 | 建立 `BagBase` 類別並將 `ColorBase` 當建構傳入(因為`Bag`需要上顏色) 52 | 53 | ```c# 54 | public abstract class BagBase 55 | { 56 | protected ColorBase color{ get; set; } 57 | 58 | public BagBase(ColorBase color) { 59 | this.color = color; 60 | } 61 | public abstract void GetBag(); 62 | } 63 | 64 | public abstract class ColorBase 65 | { 66 | public abstract string Color(); 67 | } 68 | ``` 69 | 70 | 這邊我只介紹一種顏色和包包來當作範例,因為其他概念都一樣 71 | 72 | ```c# 73 | public class AdidasBag : BagBase 74 | { 75 | public AdidasBag(ColorBase color) : base(color) 76 | { 77 | } 78 | 79 | public override void GetBag() 80 | { 81 | Console.WriteLine($"It is Addidas Bag,Color is {color.Color()}"); 82 | } 83 | } 84 | 85 | class ColorBlue : ColorBase 86 | { 87 | public override string Color() 88 | { 89 | return "Blue"; 90 | } 91 | } 92 | ``` 93 | 94 | 建立 95 | * `AdidasBag`類別重載`GetBag`方法 96 | * `ColorBlue`類別重載`Color`方法 97 | 98 | 因為`BagBase`要傳入顏色`GetBag`就可幫包包上色. 99 | 100 | 使用如下外面看起來很合理乾淨. 101 | 102 | ```c# 103 | class Program 104 | { 105 | static void Main(string[] args) 106 | { 107 | AdidasBag nick = new AdidasBag(new ColorBlue()); 108 | nick.GetBag(); 109 | Console.ReadKey(); 110 | } 111 | } 112 | ``` 113 | ---- 114 | 115 | ## 實際案例 116 | 117 | 前陣子在做一個Unity2D遊戲,遇到一組遊戲邏輯 118 | 119 | 一個人物要移動有分兩種移動方式 120 | 1. 自動移動 121 | 2. 玩家手動點擊移動 122 | 123 | 因為是2D遊戲 有 `上下左右` 四個方位移動,四個方位配上兩個移動方式,人物會有不一樣的移動邏輯. 124 | 125 | 這邊我貼上部分程式碼 126 | 127 | 建立一個 `RoadActionBase`裡面有三個必要屬性需要給 `上下左右` 實現 128 | 129 | 1. `ArrowType` 2D人物移動箭頭方向 130 | 2. `OffSetPos` 移動距離 131 | 3. `PlayerDirction` 這是一個Unity2D座標屬性 132 | 133 | ```c# 134 | public abstract class RoadActionBase 135 | { 136 | 137 | protected int _level; 138 | 139 | public RoadActionBase() 140 | { 141 | _level = SenceParamter.RoadCount; 142 | } 143 | 144 | public abstract ArrowType ArrowType { get; } 145 | 146 | public abstract int OffSetPos { get; } 147 | 148 | public abstract Vector2 PlayerDirction { get; } 149 | } 150 | ``` 151 | 152 | `UpRoadAction`類別對於往`上`時的狀態做給值 153 | 154 | ```c# 155 | public class UpRoadAction : RoadActionBase 156 | { 157 | public override ArrowType ArrowType 158 | { 159 | get 160 | { 161 | return ArrowType.Up; 162 | } 163 | } 164 | 165 | public override int OffSetPos 166 | { 167 | get 168 | { 169 | return -_level; 170 | } 171 | } 172 | 173 | public override Vector2 PlayerDirction 174 | { 175 | get 176 | { 177 | return Vector2.up; 178 | } 179 | } 180 | } 181 | ``` 182 | 183 | `DownRoadAction`類別對於往`下`時的狀態做給值 184 | 185 | ```c# 186 | public class DownRoadAction : RoadActionBase 187 | { 188 | public override ArrowType ArrowType 189 | { 190 | get 191 | { 192 | return ArrowType.Down; 193 | } 194 | } 195 | 196 | public override int OffSetPos 197 | { 198 | get 199 | { 200 | return _level; 201 | } 202 | } 203 | 204 | public override Vector2 PlayerDirction 205 | { 206 | get 207 | { 208 | return Vector2.down; 209 | } 210 | } 211 | } 212 | ``` 213 | 214 | `RightRoadAction`類別對於往`右`時的狀態做給值 215 | 216 | ```c# 217 | public class RightRoadAction : RoadActionBase 218 | { 219 | public override ArrowType ArrowType 220 | { 221 | get 222 | { 223 | return ArrowType.Right; 224 | } 225 | } 226 | 227 | public override int OffSetPos 228 | { 229 | get 230 | { 231 | return 1; 232 | } 233 | } 234 | 235 | public override Vector2 PlayerDirction 236 | { 237 | get 238 | { 239 | return Vector2.right; 240 | } 241 | } 242 | } 243 | ``` 244 | 245 | 246 | `LeftRoadAction`類別對於往`左`時的狀態做給值 247 | 248 | ```c# 249 | public class LeftRoadAction : RoadActionBase 250 | { 251 | public override ArrowType ArrowType 252 | { 253 | get 254 | { 255 | return ArrowType.Left; 256 | } 257 | } 258 | 259 | public override int OffSetPos 260 | { 261 | get 262 | { 263 | return -1; 264 | } 265 | } 266 | 267 | public override Vector2 PlayerDirction 268 | { 269 | get 270 | { 271 | return Vector2.left; 272 | } 273 | } 274 | } 275 | ``` 276 | 277 | 建立一個 `MoveBase` 並將 `RoadActionBase`當作建構子傳入(內部邏輯有寫注解). 278 | 279 | > 重點在於一個 `IsWalkNext`方法 提供Hock給子類別做實現,因為手動和自動移動邏輯不一樣. 280 | 281 | ```c# 282 | /// 283 | /// 橋接模式 284 | /// 285 | public abstract class MoveBase 286 | { 287 | protected PlayerController _player; 288 | 289 | protected int _level; 290 | 291 | protected float _Scape; 292 | 293 | public RoadActionBase RoadAction { get; protected set; } 294 | 295 | public MoveBase(RoadActionBase roadAction) 296 | { 297 | _player = PlayerController.Instance; 298 | _level = SenceParamter.RoadCount; 299 | _Scape = SenceParamter.Scape + SenceParamter.RoadHeigh; 300 | RoadAction = roadAction; 301 | } 302 | 303 | public virtual void Move(RoadContext currentRoad, RoadContext nextRoad) 304 | { 305 | //取得下一個位置 306 | Vector2 nextPos = nextRoad.transform.localPosition; 307 | 308 | if (IsWalkNext(currentRoad, nextRoad, _player.targetPos, nextPos)) 309 | { 310 | //將下一個資料塞給當前玩家 311 | _player.targetPos = nextPos; 312 | _player.RoadContext = nextRoad; 313 | _player.moveDirction = RoadAction.PlayerDirction; 314 | 315 | currentRoad.SetIsWalk(true); 316 | 317 | //加入等待轉換的地方 318 | ReloadRoadController.Instance.AddRoadContext(currentRoad); 319 | } 320 | } 321 | 322 | protected abstract bool IsWalkNext(RoadContext currentRoad, RoadContext nextRoad, Vector3 targetPos, Vector3 nextPos); 323 | } 324 | ``` 325 | `TouchMove` 類別重載 `IsWalkNext`實現自己的邏輯 326 | 327 | ```c# 328 | public class TouchMove : MoveBase 329 | { 330 | public TouchMove(RoadActionBase roadAction) : base(roadAction) 331 | { 332 | } 333 | 334 | /// 335 | /// 判斷是否可以 前往下一個目標 336 | /// 337 | /// 338 | /// 339 | /// 340 | /// 341 | /// 342 | protected override bool IsWalkNext(RoadContext currentRoad, RoadContext nextRoad, Vector3 targetPos, Vector3 nextPos) 343 | { 344 | ArrowType arrowType = RoadAction.ArrowType; 345 | //1.下一個道路要可以進去 346 | //2.當前道路要可以出來 347 | //3.必須為四周的道路 348 | return 349 | arrowType.CanWalk(currentRoad.CanWalkOut) && 350 | arrowType.CanWalk(nextRoad.CanWalkIn) && 351 | CanMoveNextPos(targetPos, nextPos); 352 | 353 | } 354 | 355 | private bool CanMoveNextPos(Vector3 targetPos, Vector3 nextPos) 356 | { 357 | return ((int)Vector2.Distance(targetPos, nextPos)) % 358 | ((int)_Scape) == 0; 359 | } 360 | } 361 | ``` 362 | `AutoMove` 類別重載 `IsWalkNext`實現自己的邏輯 363 | 364 | ```c# 365 | public class AutoMove : MoveBase 366 | { 367 | public AutoMove(RoadActionBase roadAction) : base(roadAction) 368 | { 369 | } 370 | 371 | /// 372 | /// 判斷是否可以 前往下一個目標 373 | /// 374 | /// 375 | /// 376 | /// 377 | /// 378 | /// 379 | protected override bool IsWalkNext(RoadContext currentRoad, RoadContext nextRoad, Vector3 targetPos, Vector3 nextPos) 380 | { 381 | //1.下一個道路要可以進去 382 | //2.當前道路要可以出來 383 | //3.必須為四周的道路 384 | //4.步數必須大於0 385 | return 386 | currentRoad.CurrentArrow.CanWalk(nextRoad.CanWalkIn) && 387 | currentRoad.CurrentArrow.CanWalk(currentRoad.CanWalkOut) && 388 | CanMoveNextPos(targetPos, nextPos) && 389 | !nextRoad.IsChangeState && 390 | GameModel.Step >0; 391 | } 392 | 393 | private bool CanMoveNextPos(Vector3 targetPos, Vector3 nextPos) 394 | { 395 | return ((int)Vector2.Distance(targetPos, nextPos)) % 396 | ((int)_Scape) == 0; 397 | } 398 | } 399 | ``` 400 | 401 | 402 | 上面程式碼最主要是跟大家分享移動方式和方位的關係,`上下左右`值和方位式固定,將此配上不同的移動方式有不一樣的邏輯. -------------------------------------------------------------------------------- /DesignPattern/CommandPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/CommandPattern/CommandPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0A3C9A75-257D-4A74-A0A3-AC1527681465} 8 | Exe 9 | Properties 10 | CommandPattern 11 | CommandPattern 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 | 56 | -------------------------------------------------------------------------------- /DesignPattern/CommandPattern/DishList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace CommandPattern 7 | { 8 | public class DishList 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DesignPattern/CommandPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace CommandPattern 7 | { 8 | class Program 9 | { 10 | static Invoker invoker; 11 | static void Main(string[] args) 12 | { 13 | invoker = new Invoker(); 14 | Console.WriteLine("請輸入 動作 1.新增日誌 2.調用目前記錄 3.刪除前一筆資料 其他任意按鈕離開"); 15 | 16 | while (Invoke(Console.ReadKey(true).Key)) 17 | { 18 | 19 | } 20 | Console.WriteLine("結束!"); 21 | } 22 | 23 | static bool Invoke(ConsoleKey keyPress) 24 | { 25 | bool result = true; 26 | switch (keyPress) 27 | { 28 | case ConsoleKey.NumPad1: 29 | string input = Console.ReadLine(); 30 | invoker.Add(new LogCommand(new KeyboradInfo() { Name = input, CreateDate = DateTime.Now })); 31 | break; 32 | case ConsoleKey.NumPad2: 33 | invoker.Excute(); 34 | break; 35 | case ConsoleKey.NumPad3: 36 | invoker.UnExcute(); 37 | break; 38 | default: 39 | result = false; 40 | break; 41 | } 42 | return result; 43 | } 44 | } 45 | 46 | public interface ICommand { 47 | void Execute(); 48 | void UnExecute(); 49 | } 50 | 51 | public class Invoker 52 | { 53 | private Stack _commandList = new Stack(); 54 | 55 | public void Excute() 56 | { 57 | foreach (var command in _commandList) 58 | { 59 | command.Execute(); 60 | } 61 | } 62 | 63 | public void Add(ICommand command) 64 | { 65 | _commandList.Push(command); 66 | } 67 | 68 | public void UnExcute() { 69 | ICommand current = _commandList.Pop(); 70 | current.UnExecute(); 71 | } 72 | } 73 | 74 | public class LogCommand : ICommand 75 | { 76 | public KeyboradInfo Info { get; set; } 77 | 78 | public LogCommand(KeyboradInfo _info) { 79 | Info = _info; 80 | } 81 | public void Execute() 82 | { 83 | Console.WriteLine($"Create Date:{Info.CreateDate.ToLongTimeString()} Data:{Info.Name}"); 84 | } 85 | 86 | public void UnExecute() 87 | { 88 | Console.WriteLine($"Data haskk Remove {Info.Name}"); 89 | } 90 | } 91 | 92 | public class KeyboradInfo 93 | { 94 | 95 | public string Name { get; set; } 96 | 97 | public DateTime CreateDate { get; set; } = DateTime.Now; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /DesignPattern/CommandPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("CommandPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("CommandPattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("0a3c9a75-257d-4a74-a0a3-ac1527681465")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/CommandPattern/chief.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace CommandPattern 7 | { 8 | public class chief 9 | { 10 | public void cook(string dish) { 11 | Console.WriteLine($"廚師煮菜{dish}"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DesignPattern/CommandPatternDemo/CommandPatternDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DesignPattern/CommandPatternDemo/IStateCommnad.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | public interface IStateCommnad{ 3 | void Execute(Product product); 4 | ProductState CurrentState { get; } 5 | 6 | HashSet AllowState {get;} 7 | } 8 | // See https://aka.ms/new-console-template for more information 9 | 10 | public interface IStateCommnadHandler{ 11 | void Execute(IStateCommnad command,Product product); 12 | } 13 | 14 | // public class StateCommnadHandler : IStateCommnadHandler 15 | // { 16 | // public void Execute(IStateCommnad command) 17 | // { 18 | // if (command.AllowState.Contains(product.State)) 19 | // { 20 | // System.Console.WriteLine($"將 {product.Name} => {CurrentState} 更新狀態到 {product.State}"); 21 | // } 22 | // else { 23 | // throw new Exception($"Not Allow Action CurrentState:{CurrentState} try to {product.State}"); 24 | // } 25 | 26 | // command.Execute(product); 27 | // } 28 | // } 29 | 30 | public class NewState : IStateCommnad 31 | { 32 | public ProductState CurrentState { get; } = ProductState.New; 33 | 34 | public HashSet AllowState {get;}= new HashSet(){ 35 | ProductState.New 36 | }; 37 | public void Execute(Product product) 38 | { 39 | if (AllowState.Contains(product.State)) 40 | { 41 | System.Console.WriteLine($"將 {product.Name} => 新增物件 狀態:{CurrentState} "); 42 | } 43 | else { 44 | throw new Exception($"Not Allow Action CurrentState:{product.State} try to {CurrentState}"); 45 | } 46 | } 47 | } 48 | 49 | public class CancelState : IStateCommnad 50 | { 51 | public ProductState CurrentState { get; } = ProductState.Cancel; 52 | 53 | public HashSet AllowState {get;} = new HashSet(){ 54 | ProductState.New, 55 | ProductState.Processing 56 | }; 57 | public void Execute(Product product) 58 | { 59 | if (AllowState.Contains(product.State)) 60 | { 61 | System.Console.WriteLine($"將 {product.Name} => {product.State} 更新狀態到 {CurrentState}"); 62 | product.State = CurrentState; 63 | } 64 | else { 65 | throw new Exception($"Not Allow Action CurrentState:{product.State} try to {CurrentState}"); 66 | } 67 | } 68 | } 69 | 70 | public class ProcessingState : IStateCommnad 71 | { 72 | public ProductState CurrentState { get; } = ProductState.Processing; 73 | 74 | public HashSet AllowState {get;} = new HashSet(){ 75 | ProductState.New 76 | }; 77 | public void Execute(Product product) 78 | { 79 | if (AllowState.Contains(product.State)) 80 | { 81 | System.Console.WriteLine($"將 {product.Name} => {product.State} 更新狀態到 {CurrentState}"); 82 | product.State = CurrentState; 83 | } 84 | else { 85 | throw new Exception($"Not Allow Action CurrentState:{product.State} try to {CurrentState}"); 86 | } 87 | } 88 | } 89 | 90 | 91 | 92 | public class DeliverState : IStateCommnad 93 | { 94 | public ProductState CurrentState { get; } = ProductState.Deliver; 95 | 96 | public HashSet AllowState {get;} = new HashSet(){ 97 | ProductState.Processing 98 | }; 99 | public void Execute(Product product) 100 | { 101 | if (AllowState.Contains(product.State)) 102 | { 103 | System.Console.WriteLine($"將 {product.Name} => {product.State} 更新狀態到 {CurrentState}"); 104 | product.State = CurrentState; 105 | } 106 | else { 107 | throw new Exception($"Not Allow Action CurrentState:{product.State} try to {CurrentState}"); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /DesignPattern/CommandPatternDemo/Product.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | 4 | 5 | public class Product{ 6 | public string Name { get; set; } 7 | public ProductState State { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /DesignPattern/CommandPatternDemo/ProductState.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | public enum ProductState 4 | { 5 | New, 6 | Processing, 7 | Cancel, 8 | Deliver, 9 | Finish 10 | } -------------------------------------------------------------------------------- /DesignPattern/CommandPatternDemo/Program.cs: -------------------------------------------------------------------------------- 1 |  2 | Product p = new Product(){ 3 | Name = "test", 4 | State = ProductState.New 5 | }; 6 | 7 | new NewState().Execute(p); 8 | 9 | new DeliverState().Execute(p); 10 | 11 | -------------------------------------------------------------------------------- /DesignPattern/CompositePattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/CompositePattern/CompositePattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B23426BE-04DA-4835-A1CD-8C3251FDD388} 8 | Exe 9 | Properties 10 | CompositePattern 11 | CompositePattern 12 | v4.5 13 | 512 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 | 53 | -------------------------------------------------------------------------------- /DesignPattern/CompositePattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace CompositePattern 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | 13 | IToDoList toDo = new Project(); 14 | 15 | toDo.Add(new ToDo() { Text = "test1" }); 16 | toDo.Add(new ToDo() { Text = "test2" }); 17 | 18 | var project = new Project(); 19 | project.Add(new ToDo() { Text = "test222" }); 20 | toDo.Add(project); 21 | Console.WriteLine(toDo.GetHtml()); 22 | 23 | Console.ReadKey(); 24 | } 25 | } 26 | 27 | public interface IToDoList{ 28 | string GetHtml(); 29 | 30 | void Add(IToDoList toDo); 31 | 32 | void Remove(IToDoList toDo); 33 | } 34 | 35 | public class Project : IToDoList 36 | { 37 | private List _toDoList = new List(); 38 | 39 | public void Add(IToDoList toDo) 40 | { 41 | _toDoList.Add(toDo); 42 | } 43 | 44 | public string GetHtml() 45 | { 46 | StringBuilder sb = new StringBuilder(); 47 | sb.AppendLine("
    "); 48 | 49 | foreach (var todo in _toDoList) 50 | { 51 | sb.AppendFormat("
  • {0}
  • ", todo.GetHtml()); 52 | } 53 | 54 | sb.AppendLine("
"); 55 | 56 | return sb.ToString(); 57 | } 58 | 59 | public void Remove(IToDoList toDo) 60 | { 61 | _toDoList.Remove(toDo); 62 | } 63 | } 64 | 65 | public class ToDo : IToDoList { 66 | 67 | public string Text{ get; set; } 68 | 69 | public void Add(IToDoList toDo) 70 | { 71 | 72 | } 73 | 74 | public string GetHtml() 75 | { 76 | return Text; 77 | } 78 | 79 | public void Remove(IToDoList toDo) 80 | { 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /DesignPattern/CompositePattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("CompositePattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("CompositePattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("b23426be-04da-4835-a1cd-8c3251fdd388")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePattern/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePattern/DecoratePattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {863663A6-A2AF-4FAA-9FBD-75C8100420DB} 8 | Exe 9 | Properties 10 | DecoratePattern 11 | DecoratePattern 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Designer 51 | 52 | 53 | 54 | 55 | 62 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("ZipLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ZipLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("863663a6-a2af-4faa-9fbd-75c8100420db")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePattern/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePatternTests/DecoratorTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {9A6F47AF-A80C-4338-B1CB-6CC3D43B693B} 7 | Library 8 | Properties 9 | DecoratorTests 10 | DecoratorTests 11 | v4.5.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | ..\..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll 41 | True 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {863663A6-A2AF-4FAA-9FBD-75C8100420DB} 60 | Decorator 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | False 71 | 72 | 73 | False 74 | 75 | 76 | False 77 | 78 | 79 | False 80 | 81 | 82 | 83 | 84 | 85 | 86 | 93 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePatternTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("ZipLibTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ZipLibTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("9a6f47af-a80c-4338-b1cb-6cc3d43b693b")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePatternTests/ZipProcessTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using ZipLib; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.IO; 8 | 9 | namespace ZipLib.Tests 10 | { 11 | [TestFixture()] 12 | public class ZipProcessTests 13 | { 14 | private string newline = Environment.NewLine; 15 | 16 | private void DeleteFile(string path) 17 | { 18 | if (File.Exists(path)) 19 | { 20 | File.Delete(path); 21 | } 22 | } 23 | 24 | [Test()] 25 | public void Zip_RaedFile() 26 | { 27 | string filePath = @"test.zip"; 28 | string except = $"你好 123456 12@()!@ {newline} fsfd嘻嘻哈哈!!"; 29 | DecorateFactory factory = new DecorateFactory(new FileProcess()); 30 | 31 | factory.SetProcess(new ZipProcess() 32 | { 33 | PassWord = "123456", 34 | FileName = "Hell.log" 35 | }); 36 | 37 | IProcess process = factory.GetProcess(); 38 | 39 | process.Write(filePath, Encoding.UTF8.GetBytes(except)); 40 | byte[] buffer = process.Read(filePath); 41 | 42 | DeleteFile(filePath); 43 | string result = Encoding.UTF8.GetString(buffer); 44 | 45 | Assert.AreEqual(result, except); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/DecoratePatternTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("DecoratePattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("DecoratePattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("715f9bca-d665-4c72-b2e5-891a9a970b4b")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/DecoratePattern/Readme.md: -------------------------------------------------------------------------------- 1 | ## 裝飾者模式(Decorator Pattern) 2 | 3 | 本篇使用 文字內容->AES加密->Zip檔附加密碼->輸出儲存 4 | 5 | 向大家介紹這個優雅又精美的設計模式 6 | 7 | 情境 8 | 有個需求要做 9 | 10 | > 文字內容->壓縮zip(附上密碼)->輸出儲存 11 | 又改成... 12 | 13 | > 文字內容->AES加密->輸出儲存 14 | 需求又改成.... 15 | 16 | > 文字內容->AES加密->Zip檔附加密碼->輸出儲存 17 | 18 | 可發現需求一直在對於文字內容操作順序做變化,但他們核心離不開對於文字內容的操作 19 | 20 | 這種情境很適合來使用 [`裝飾者模式`] 21 | 22 | 裝飾者模式 有兩個主要腳色 **被裝飾物件(Decorated)** & **裝飾物件(Decorator)** 23 | 24 | **被裝飾物件(Decorated)** 就像蛋糕的一樣, **裝飾物件(Decorator)**就是上的水果,奶油,巧克力...等等裝飾物品 25 | 26 | 一般先有蛋糕被裝飾物件(Decorated),後再將裝飾物品加上去裝飾物件(Decorator) 27 | 28 | **被裝飾物件(Decorated)** 如下圖 蛋糕的原型 29 | 30 | 31 | 32 | ![Alt text](https://raw.githubusercontent.com/isdaniel/DesignPattern/master/DesignPattern/img/Decorator/688215012311271.jpg "Optional title") 33 | 34 | > 將物件有效的往上附加職責,不動到內部的程式碼, 在原來職責上附加額外的職責 35 | 36 | 裝飾者模式運作就像 俄羅斯娃娃一樣 一層包一層 37 | 38 | ![Alt text](https://raw.githubusercontent.com/isdaniel/DesignPattern/master/DesignPattern/img/Decorator/0c8920b50c8eea2da95c25a033f19872.jpg "Optional title") 39 | 40 | ----- 41 | 42 | ## 第一步 先找尋他們共同裝飾東西,因為是讀寫檔案 所以我們可以對於Byte 起手 43 | 44 | 先可以開出 **讀** 跟 **寫** 介面簽章當作裝飾動作的統一介面 45 | 46 | 47 | public interface IProcess 48 | { 49 | byte[] Read(string path); 50 | 51 | void Write(string writePath, byte[] buffer); 52 | } 53 | 54 | 在創建一個 `ProcessBase` 給日後裝飾物品(`Decorator`)來繼承 55 | 56 | public abstract class ProcessBase : IProcess 57 | { 58 | /// 59 | /// 儲存被裝飾的物件 60 | /// 61 | protected IProcess _process; 62 | 63 | public abstract byte[] Read(string path); 64 | 65 | public abstract void Write(string writePath, byte[] buffer); 66 | 67 | public virtual void SetDecorated(IProcess process) 68 | { 69 | _process = process; 70 | } 71 | } 72 | 73 | 有兩點特別說明 74 | 75 | 1. protected IProcess _process; 儲存被裝飾的物件 76 | 2. 由 SetDecorated 方法來設置被裝飾的物件 77 | 78 | > 像俄羅斯娃娃只包裹一個娃娃,不管被包裹娃娃之前包含哪些娃娃 79 | 80 | ----- 81 | 82 | ## 第二步 創建被裝飾物品(Decorated) 83 | 84 | 因為是檔案我們直接使用 85 | 86 | 1. `File.ReadAllBytes` **讀** 檔案 87 | 2. `File.WriteAllBytes` **寫** 檔案 88 | 89 | /// 90 | /// 讀取檔案 91 | /// 92 | public class FileProcess : IProcess 93 | { 94 | public byte[] Read(string path) 95 | { 96 | return File.ReadAllBytes(path); 97 | } 98 | 99 | public void Write(string writePath, byte[] buffer) 100 | { 101 | File.WriteAllBytes(writePath, buffer); 102 | } 103 | } 104 | 105 | ----- 106 | 107 | ## 第三步 創建裝飾物品(Decorator) 108 | 109 | 這次主要裝飾物品有兩個 110 | 111 | * 加壓解壓ZIP檔 112 | * 加解密 113 | 114 | 115 | 加密裝飾器繼承`ProcessBase`並按照加解密重寫 `Write` ​和 `read` 方法 116 | 117 | /// 118 | /// Aes 加密裝飾器 119 | /// 120 | public class AESCrypProcess : ProcessBase 121 | { 122 | private AesCryptoServiceProvider aes; 123 | 124 | public string AESKey { get; set; } = "1776D8E110124E75"; 125 | public string AESIV { get; set; } = "B890E7F6BA01C273"; 126 | 127 | public AESCrypProcess() 128 | { 129 | aes = new AesCryptoServiceProvider(); 130 | aes.Key = Encoding.UTF8.GetBytes(AESKey); 131 | aes.IV = Encoding.UTF8.GetBytes(AESIV); 132 | } 133 | 134 | public override byte[] Read(string path) 135 | { 136 | byte[] encryptBytes = _process.Read(path); 137 | return DecryptData(encryptBytes); 138 | } 139 | 140 | /// 141 | /// 進行解密 142 | /// 143 | /// 144 | /// 145 | private byte[] DecryptData(byte[] encryptBytes) 146 | { 147 | byte[] outputBytes = null; 148 | using (MemoryStream memoryStream = new MemoryStream(encryptBytes)) 149 | { 150 | using (CryptoStream decryptStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read)) 151 | { 152 | MemoryStream outputStream = new MemoryStream(); 153 | decryptStream.CopyTo(outputStream); 154 | outputBytes = outputStream.ToArray(); 155 | } 156 | } 157 | return outputBytes; 158 | } 159 | 160 | /// 161 | /// 裝飾者呼叫方法 162 | /// 163 | /// 164 | /// 165 | public override void Write(string path, byte[] data) 166 | { 167 | byte[] outputBytes = EncryptData(data); 168 | _process.Write(path, outputBytes); 169 | } 170 | 171 | private byte[] EncryptData(byte[] data) 172 | { 173 | byte[] outputBytes = null; 174 | using (MemoryStream memoryStream = new MemoryStream()) 175 | { 176 | using (CryptoStream encryptStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) 177 | { 178 | MemoryStream inputStream = new MemoryStream(data); 179 | inputStream.CopyTo(encryptStream); 180 | encryptStream.FlushFinalBlock(); 181 | outputBytes = memoryStream.ToArray(); 182 | } 183 | } 184 | 185 | return outputBytes; 186 | } 187 | } 188 | 189 | 上面就把我們要用的裝飾物品 (備料) 準備完成 190 | 191 | ----- 192 | 193 | ## 第四步 創建使用(開始擺盤) 194 | 195 | 196 | 創建一個 DecorateFactory 來當生產 裝飾產品的工廠 197 | 198 | 建構子傳入一個 被裝飾的物件(`FileProcess`) 之後可依照喜好一直疊加 裝飾物品(`ZipProcess,AESCrypProcess...`) 199 | 200 | 201 | public class DecorateFactory 202 | { 203 | IProcess _original; 204 | 205 | public DecorateFactory(IProcess original) 206 | { 207 | _original = original; 208 | } 209 | 210 | public DecorateFactory SetProcess(ProcessBase process) 211 | { 212 | process.SetDecorated(_original); 213 | _original = process; 214 | return this; 215 | } 216 | 217 | public IProcess GetProcess() 218 | { 219 | return _original; 220 | } 221 | } 222 | 裝飾者模式順序是很重要的一個流程 223 | 224 | 225 | 為了方便讀者閱讀 我使用小畫家畫出 讀寫順序 226 | 227 | 如下圖 228 | 229 | ![Alt text](https://raw.githubusercontent.com/isdaniel/DesignPattern/master/DesignPattern/img/Decorator/decorator.png "Optional title") 230 | 231 | 232 | 使用就可很清晰來用 233 | 234 | 利用 `DecorateFactory`來創建裝飾流程 235 | 使用 `factroy.GetProcess();` 方法取得完成後的產品 236 | 在簡單呼叫讀和寫方法 237 | 238 | string filePath = @"C:\Users\daniel.shih\Desktop\test.zip"; 239 | string content = $"你好 123456 12@()!@ {Environment.NewLine} fsfd嘻嘻哈哈!!"; 240 | 241 | //設置初始化的被裝飾者 242 | DecorateFactory factroy = new DecorateFactory(new FileProcess()); 243 | 244 | //設置裝飾的順序 245 | factroy.SetProcess(new AESCrypProcess()) 246 | .SetProcess(new ZipProcess() { FileName = "1.txt",PassWord ="1234567"}); 247 | 248 | IProcess process = factroy.GetProcess(); 249 | 250 | byte[] data_buffer = Encoding.UTF8.GetBytes(content); 251 | process.Write(filePath, data_buffer); 252 | 253 | byte[] buffer = process.Read(filePath); 254 | Console.WriteLine(Encoding.UTF8.GetString(buffer)); 255 | 256 | 日後不管需求是改成 257 | 258 | * 文字內容->壓縮zip(附上密碼)->輸出儲存 259 | * 文字內容->AES加密->輸出儲存 260 | * 文字內容->AES加密->Zip檔附加密碼->輸出儲存 261 | 262 | 還是..... 263 | 264 | 我們都不怕 因為我們把各種操作封裝和多態 265 | 266 | 各個模組間都是獨立的很好映證 高內聚低耦合 的設計原則 267 | 268 | 269 | ## 小結: 270 | 271 | 裝飾者模式是一個很精美且優雅的模式 希望這篇文章可讓讀者對於此模式有更加了解 -------------------------------------------------------------------------------- /DesignPattern/DesignPattern.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdpterPattern", "AdpterPattern\AdpterPattern.csproj", "{2348B810-4970-4B49-B839-492338FAA74A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleFactory", "SimpleFactory\SimpleFactory.csproj", "{35A3A267-4ECC-411D-A163-E718A17AED30}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FactoryMethodPattern", "FactoryMethodPattern\FactoryMethodPattern.csproj", "{81DD9CC8-42FD-4BC7-8E1A-030CB7DA8576}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObserverPattern", "ObserverPattern\ObserverPattern.csproj", "{D3D657F1-A949-4BF4-B8A5-280C8024C398}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BridgePattern", "BridgePattern\BridgePattern.csproj", "{AB99CF29-C71A-4F11-9E81-7DE2FB2AE96C}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxyPattern", "ProxyPattern\ProxyPattern.csproj", "{41A8AFD7-9699-44F2-A992-5340E717BFCD}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecoratePattern", "DecoratePattern\DecoratePattern\DecoratePattern.csproj", "{863663A6-A2AF-4FAA-9FBD-75C8100420DB}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecoratorTests", "DecoratePattern\DecoratePatternTests\DecoratorTests.csproj", "{9A6F47AF-A80C-4338-B1CB-6CC3D43B693B}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandPattern", "CommandPattern\CommandPattern.csproj", "{0A3C9A75-257D-4A74-A0A3-AC1527681465}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompositePattern", "CompositePattern\CompositePattern.csproj", "{B23426BE-04DA-4835-A1CD-8C3251FDD388}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePattern", "StatePattern\StatePattern.csproj", "{10EC9E65-1D6F-4B0D-A06C-9F5BF5306505}" 27 | EndProject 28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatePatternTests", "StatePatternTests\StatePatternTests.csproj", "{5D69CC35-D38F-47AF-9BF3-2F81D69442CE}" 29 | EndProject 30 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediatorPattern", "MediatorPattern\MediatorPattern.csproj", "{B7B1451B-21CB-49A0-BADF-B5758AEFFD82}" 31 | EndProject 32 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplatePattern", "TemplatePattern\TemplatePattern.csproj", "{10392CBE-21FF-45DA-A1B1-5F71E356740F}" 33 | EndProject 34 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrategyPattern", "StrategyPattern\StrategyPattern.csproj", "{1BF8C0B1-23F7-497C-94EE-EA239936E730}" 35 | EndProject 36 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrategyPatternTests", "StrategyPatternTests\StrategyPatternTests.csproj", "{9858DFFF-FC73-491F-AE59-E91E588E90A8}" 37 | EndProject 38 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NullObjectPattern", "NullObjectPattern\NullObjectPattern.csproj", "{B44B3D59-73E8-4D10-898A-13DA8CB788E5}" 39 | EndProject 40 | Global 41 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 42 | Debug|Any CPU = Debug|Any CPU 43 | Release|Any CPU = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 46 | {2348B810-4970-4B49-B839-492338FAA74A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {2348B810-4970-4B49-B839-492338FAA74A}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {2348B810-4970-4B49-B839-492338FAA74A}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {2348B810-4970-4B49-B839-492338FAA74A}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {35A3A267-4ECC-411D-A163-E718A17AED30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {35A3A267-4ECC-411D-A163-E718A17AED30}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {35A3A267-4ECC-411D-A163-E718A17AED30}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {35A3A267-4ECC-411D-A163-E718A17AED30}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {81DD9CC8-42FD-4BC7-8E1A-030CB7DA8576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {81DD9CC8-42FD-4BC7-8E1A-030CB7DA8576}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {81DD9CC8-42FD-4BC7-8E1A-030CB7DA8576}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {81DD9CC8-42FD-4BC7-8E1A-030CB7DA8576}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {D3D657F1-A949-4BF4-B8A5-280C8024C398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 59 | {D3D657F1-A949-4BF4-B8A5-280C8024C398}.Debug|Any CPU.Build.0 = Debug|Any CPU 60 | {D3D657F1-A949-4BF4-B8A5-280C8024C398}.Release|Any CPU.ActiveCfg = Release|Any CPU 61 | {D3D657F1-A949-4BF4-B8A5-280C8024C398}.Release|Any CPU.Build.0 = Release|Any CPU 62 | {AB99CF29-C71A-4F11-9E81-7DE2FB2AE96C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {AB99CF29-C71A-4F11-9E81-7DE2FB2AE96C}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {AB99CF29-C71A-4F11-9E81-7DE2FB2AE96C}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {AB99CF29-C71A-4F11-9E81-7DE2FB2AE96C}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {41A8AFD7-9699-44F2-A992-5340E717BFCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 67 | {41A8AFD7-9699-44F2-A992-5340E717BFCD}.Debug|Any CPU.Build.0 = Debug|Any CPU 68 | {41A8AFD7-9699-44F2-A992-5340E717BFCD}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {41A8AFD7-9699-44F2-A992-5340E717BFCD}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {863663A6-A2AF-4FAA-9FBD-75C8100420DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 71 | {863663A6-A2AF-4FAA-9FBD-75C8100420DB}.Debug|Any CPU.Build.0 = Debug|Any CPU 72 | {863663A6-A2AF-4FAA-9FBD-75C8100420DB}.Release|Any CPU.ActiveCfg = Release|Any CPU 73 | {863663A6-A2AF-4FAA-9FBD-75C8100420DB}.Release|Any CPU.Build.0 = Release|Any CPU 74 | {9A6F47AF-A80C-4338-B1CB-6CC3D43B693B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 75 | {9A6F47AF-A80C-4338-B1CB-6CC3D43B693B}.Debug|Any CPU.Build.0 = Debug|Any CPU 76 | {9A6F47AF-A80C-4338-B1CB-6CC3D43B693B}.Release|Any CPU.ActiveCfg = Release|Any CPU 77 | {9A6F47AF-A80C-4338-B1CB-6CC3D43B693B}.Release|Any CPU.Build.0 = Release|Any CPU 78 | {0A3C9A75-257D-4A74-A0A3-AC1527681465}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 79 | {0A3C9A75-257D-4A74-A0A3-AC1527681465}.Debug|Any CPU.Build.0 = Debug|Any CPU 80 | {0A3C9A75-257D-4A74-A0A3-AC1527681465}.Release|Any CPU.ActiveCfg = Release|Any CPU 81 | {0A3C9A75-257D-4A74-A0A3-AC1527681465}.Release|Any CPU.Build.0 = Release|Any CPU 82 | {B23426BE-04DA-4835-A1CD-8C3251FDD388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 83 | {B23426BE-04DA-4835-A1CD-8C3251FDD388}.Debug|Any CPU.Build.0 = Debug|Any CPU 84 | {B23426BE-04DA-4835-A1CD-8C3251FDD388}.Release|Any CPU.ActiveCfg = Release|Any CPU 85 | {B23426BE-04DA-4835-A1CD-8C3251FDD388}.Release|Any CPU.Build.0 = Release|Any CPU 86 | {10EC9E65-1D6F-4B0D-A06C-9F5BF5306505}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 87 | {10EC9E65-1D6F-4B0D-A06C-9F5BF5306505}.Debug|Any CPU.Build.0 = Debug|Any CPU 88 | {10EC9E65-1D6F-4B0D-A06C-9F5BF5306505}.Release|Any CPU.ActiveCfg = Release|Any CPU 89 | {10EC9E65-1D6F-4B0D-A06C-9F5BF5306505}.Release|Any CPU.Build.0 = Release|Any CPU 90 | {5D69CC35-D38F-47AF-9BF3-2F81D69442CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 91 | {5D69CC35-D38F-47AF-9BF3-2F81D69442CE}.Debug|Any CPU.Build.0 = Debug|Any CPU 92 | {5D69CC35-D38F-47AF-9BF3-2F81D69442CE}.Release|Any CPU.ActiveCfg = Release|Any CPU 93 | {5D69CC35-D38F-47AF-9BF3-2F81D69442CE}.Release|Any CPU.Build.0 = Release|Any CPU 94 | {B7B1451B-21CB-49A0-BADF-B5758AEFFD82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 95 | {B7B1451B-21CB-49A0-BADF-B5758AEFFD82}.Debug|Any CPU.Build.0 = Debug|Any CPU 96 | {B7B1451B-21CB-49A0-BADF-B5758AEFFD82}.Release|Any CPU.ActiveCfg = Release|Any CPU 97 | {B7B1451B-21CB-49A0-BADF-B5758AEFFD82}.Release|Any CPU.Build.0 = Release|Any CPU 98 | {10392CBE-21FF-45DA-A1B1-5F71E356740F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 99 | {10392CBE-21FF-45DA-A1B1-5F71E356740F}.Debug|Any CPU.Build.0 = Debug|Any CPU 100 | {10392CBE-21FF-45DA-A1B1-5F71E356740F}.Release|Any CPU.ActiveCfg = Release|Any CPU 101 | {10392CBE-21FF-45DA-A1B1-5F71E356740F}.Release|Any CPU.Build.0 = Release|Any CPU 102 | {1BF8C0B1-23F7-497C-94EE-EA239936E730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 103 | {1BF8C0B1-23F7-497C-94EE-EA239936E730}.Debug|Any CPU.Build.0 = Debug|Any CPU 104 | {1BF8C0B1-23F7-497C-94EE-EA239936E730}.Release|Any CPU.ActiveCfg = Release|Any CPU 105 | {1BF8C0B1-23F7-497C-94EE-EA239936E730}.Release|Any CPU.Build.0 = Release|Any CPU 106 | {9858DFFF-FC73-491F-AE59-E91E588E90A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 107 | {9858DFFF-FC73-491F-AE59-E91E588E90A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 108 | {9858DFFF-FC73-491F-AE59-E91E588E90A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 109 | {9858DFFF-FC73-491F-AE59-E91E588E90A8}.Release|Any CPU.Build.0 = Release|Any CPU 110 | {B44B3D59-73E8-4D10-898A-13DA8CB788E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 111 | {B44B3D59-73E8-4D10-898A-13DA8CB788E5}.Debug|Any CPU.Build.0 = Debug|Any CPU 112 | {B44B3D59-73E8-4D10-898A-13DA8CB788E5}.Release|Any CPU.ActiveCfg = Release|Any CPU 113 | {B44B3D59-73E8-4D10-898A-13DA8CB788E5}.Release|Any CPU.Build.0 = Release|Any CPU 114 | EndGlobalSection 115 | GlobalSection(SolutionProperties) = preSolution 116 | HideSolutionNode = FALSE 117 | EndGlobalSection 118 | EndGlobal 119 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/Car.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public class Car : IMoveable 9 | { 10 | public void run() 11 | { 12 | Console.WriteLine("車車跑跑跑~~"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/CarFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public class CarFactory: IFactory 9 | { 10 | public IMoveable create() => new Car(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/FactoryMethodPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {81DD9CC8-42FD-4BC7-8E1A-030CB7DA8576} 8 | Exe 9 | Properties 10 | FactoryMethodPattern 11 | FactoryMethodPattern 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 | 51 | 52 | 53 | 54 | 55 | 56 | 63 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/IFactory.cs: -------------------------------------------------------------------------------- 1 | namespace FactoryMethodPattern 2 | { 3 | public interface IFactory 4 | { 5 | IMoveable create(); 6 | } 7 | } -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/IFireable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public interface IFireable 9 | { 10 | void Fire(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/IMoveable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public interface IMoveable 9 | { 10 | void run(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/Plane.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public class Plane : IMoveable 9 | { 10 | 11 | public void run() 12 | { 13 | Console.WriteLine("飛機飛飛飛~~"); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/PlaneFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public class PlaneFactory: IFactory 9 | { 10 | public IMoveable create() => new Plane(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.Remoting.Contexts; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace FactoryMethodPattern 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | 14 | IFactory factory = new PlaneFactory(); 15 | IMoveable m= factory.create(); 16 | m.run(); 17 | Console.ReadKey(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("FactoryMethodPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("FactoryMethodPattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("81dd9cc8-42fd-4bc7-8e1a-030cb7da8576")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/Tank.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public class Tank : IFireable 9 | { 10 | public void Fire() 11 | { 12 | Console.WriteLine("Tank Fire!!"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/FactoryMethodPattern/Warships.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace FactoryMethodPattern 7 | { 8 | public class Warships : IFireable 9 | { 10 | public void Fire() 11 | { 12 | Console.WriteLine("Warships Fire"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/DBAdmin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MediatorPattern 4 | { 5 | public class DBAdmin : OriginReqBase 6 | { 7 | 8 | public void DoProcess(string message) 9 | { 10 | Console.WriteLine($"DBA:{message}"); 11 | } 12 | 13 | public DBAdmin(ProductManager productManager) : base(productManager) 14 | { 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/MediatorPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B7B1451B-21CB-49A0-BADF-B5758AEFFD82} 8 | Exe 9 | Properties 10 | MediatorPattern 11 | MediatorPattern 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 | ..\packages\Autofac.4.2.0\lib\net45\Autofac.dll 38 | True 39 | 40 | 41 | ..\packages\MediatR.5.1.0\lib\net45\MediatR.dll 42 | True 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 67 | -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/OriginReqBase.cs: -------------------------------------------------------------------------------- 1 | namespace MediatorPattern 2 | { 3 | public abstract class OriginReqBase 4 | { 5 | protected ProductManager _productManager; 6 | 7 | protected OriginReqBase(ProductManager productManager) 8 | { 9 | _productManager = productManager; 10 | } 11 | 12 | public virtual void Requirement(string message) 13 | { 14 | _productManager.Send(message, this); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/ProductManager.cs: -------------------------------------------------------------------------------- 1 | namespace MediatorPattern 2 | { 3 | public class ProductManager 4 | { 5 | public DBAdmin DbAdmin { get; set; } 6 | public Programer Programer { get; set; } 7 | 8 | internal void Send(string message, OriginReqBase req) 9 | { 10 | //如果是DBAdmin傳遞訊息由Programer執行,反之 11 | if (req.GetType() == typeof(DBAdmin)) 12 | Programer.DoProcess(message); 13 | else if(req.GetType() == typeof(Programer)) 14 | DbAdmin.DoProcess(message); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace MediatorPattern 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | ProductManager pm = new ProductManager(); 16 | 17 | DBAdmin DBA1 = new DBAdmin(pm); //DBA知道PM存在 18 | Programer RD1 = new Programer(pm); //RD知道PM存在 19 | 20 | pm.Programer = RD1; //PM知道DBA 21 | pm.DbAdmin = DBA1; //PM知道RD 22 | 23 | //現在DBA和RD只需要傳訊息就可將訊息轉到需要知道的人 24 | RD1.Requirement("DB modify Requirement."); 25 | DBA1.Requirement("DB Process doing."); 26 | 27 | Console.ReadKey(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/Programer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MediatorPattern 4 | { 5 | public class Programer : OriginReqBase 6 | { 7 | 8 | public void DoProcess(string message) 9 | { 10 | Console.WriteLine($"Programer: {message}"); 11 | } 12 | 13 | public Programer(ProductManager productManager) : base(productManager) 14 | { 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("MediatorPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("HP Inc.")] 12 | [assembly: AssemblyProduct("MediatorPattern")] 13 | [assembly: AssemblyCopyright("Copyright © HP Inc. 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("b7b1451b-21cb-49a0-badf-b5758aeffd82")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/Readme.md: -------------------------------------------------------------------------------- 1 | # MediatorPattern(中介者模式) 2 | 3 | 系統模塊存在很多複雜的耦合問題,很適合使用中介者模式來解耦合 4 | 5 | ## 說明 6 | 7 | 在現實中如果組織有一定規模可能構通如下圖那般複 8 | 9 | ![Alt text](https://dotblogsfile.blob.core.windows.net/user/%E4%B9%9D%E6%A1%83/f718d961-2f8b-46ac-a2f7-b95af802f23a/1549790323_53498.png "Optional title") 10 | 11 | 12 | 如果有一個人或組織負責幫大家協助溝通,就可解決上面複雜問題 13 | 14 | ![Alt text](https://dotblogsfile.blob.core.windows.net/user/%E4%B9%9D%E6%A1%83/f718d961-2f8b-46ac-a2f7-b95af802f23a/1549790493_52417.png "Optional title") 15 | 16 | 17 | 這就是我們這次的核心中介者 18 | 19 | ----- 20 | 21 | ## 中介者模式有幾個角色 22 | 23 | * AbstractMediator (抽像中介者):定義中介者和各個同事者之間的通信的介面 24 | * ConcreteMediator (中介者):知道每個同事物件,實現抽像中介者,負責協調和各個具體的同事的交互關係 25 | * AbstractColleague (抽象同事者):定義同事者和中介者通信的接口 26 | * ConcreteColleague (同事者):實現自己的業務,並且實現抽象方法,跟中介者進行通信 27 | 中介者模式特點是 28 | 29 | 中介者知道所有同事者物件,但同事者互相不知道對方存在需透過中介者傳遞訊息 30 | 如何傳遞和通知各個同事者由中介者內部決定 31 | 在裡面第二點是很重要的目標,把傳遞訊息的邏輯封裝在中介者裡面 32 | 33 | 程式碼 34 | 35 | public class ProductManager 36 | { 37 | public DBAdmin DbAdmin { get; set; } 38 | public Programer Programer { get; set; } 39 | 40 | internal void Send(string message, OriginReqBase req) 41 | { 42 |        //如果是DBAdmin傳遞訊息由Programer執行,反之 43 | if (req.GetType() == typeof(DBAdmin)) 44 | Programer.DoProcess(message); 45 | else if(req.GetType() == typeof(Programer)) 46 | DbAdmin.DoProcess(message); 47 | } 48 | } 49 | 50 | 傳遞通知或訊息邏輯寫在`Send` 方法裡面. 51 | 52 | 本次範例依照傳入的型別,如果是`DBAdmin`傳遞訊息由`Programer`執行,反之 53 | 54 | public abstract class OriginReqBase 55 | { 56 | protected ProductManager _productManager; 57 | 58 | protected OriginReqBase(ProductManager productManager) 59 | { 60 | _productManager = productManager; 61 | } 62 | 63 | public virtual void Requirement(string message) 64 | { 65 | _productManager.Send(message, this); 66 | } 67 | } 68 | 69 | `OriginReqBase`(抽象同事者) 因為每個角色 `ConcreteColleague` 都需要知道中介者存在,所以把參數設定在建構子上。 70 | 71 | `Requirement` 方法通知 `PM` 中介者將資料傳遞出去 72 | 73 | public class Programer : OriginReqBase 74 | { 75 | 76 | public void DoProcess(string message) 77 | { 78 | Console.WriteLine($"Programer: {message}"); 79 | } 80 | 81 | public Programer(ProductManager productManager) : base(productManager) 82 | { 83 | } 84 | } 85 | 86 | public class DBAdmin : OriginReqBase 87 | { 88 | 89 | public void DoProcess(string message) 90 | { 91 | Console.WriteLine($"DBA:{message}"); 92 | } 93 | 94 | public DBAdmin(ProductManager productManager) : base(productManager) 95 | { 96 | } 97 | } 98 | DoProcess 方法 PM 中介者呼叫使用 99 | 100 | ProductManager pm = new ProductManager(); 101 | 102 | DBAdmin DBA1 = new DBAdmin(pm); //DBA知道PM存在 103 | Programer RD1 = new Programer(pm); //RD知道PM存在 104 | 105 | pm.Programer = RD1; //PM知道DBA 106 | pm.DbAdmin = DBA1; //PM知道RD 107 | 108 | //現在DBA和RD只需要傳訊息就可將訊息轉到需要知道的人 109 | 110 | RD1.Requirement("DB modify Requestment."); 111 | DBA1.Requirement("DB Process doing."); 112 | 113 | 有三大重點 114 | 115 | 1. `DBA`和`RD`(同事者) 知道`PM`(中介者)存在 116 | 2. `PM`(中介者)知道`DBA`和`RD`(同事者)存在 117 | 3. `DBA`和`RD`不用知道對方存在但卻可以互相傳遞訊息(因為PM已經幫助我們解耦合了) 118 | 119 | ![Alt text](https://dotblogsfile.blob.core.windows.net/user/%E4%B9%9D%E6%A1%83/f718d961-2f8b-46ac-a2f7-b95af802f23a/1549792143_37531.png "Optional title") 120 | 121 | > UML圖 (有標示相對應的角色關係) 122 | 123 | 我看來這個解耦合核心思想跟容器有點像,因為需要做溝通或通知時我們統一只需要轉交給中介者會幫助我們處理溝通事宜 124 | 125 | ## 小結 126 | 127 | 在CQRS架構中介者模式很好幫助我們傳送命令間的解耦合,有機會在跟大家分享[MediatR](https://github.com/jbogard/MediatR)這個框架 128 | -------------------------------------------------------------------------------- /DesignPattern/MediatorPattern/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/CartModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NullObjectPattern 4 | { 5 | public class CartModel 6 | { 7 | public int UserID { get; set; } 8 | public IEnumerable Items { get; set; } = new List(); 9 | } 10 | } -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/Items.cs: -------------------------------------------------------------------------------- 1 | namespace NullObjectPattern 2 | { 3 | public class Items 4 | { 5 | public string Name { get; set; } 6 | public decimal Price { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/NullObjectPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B44B3D59-73E8-4D10-898A-13DA8CB788E5} 8 | Exe 9 | Properties 10 | NullObjectPattern 11 | NullObjectPattern 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 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/PaymentService.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace NullObjectPattern 4 | { 5 | public class PaymentService : IPaymentService 6 | { 7 | public decimal calculate(CartModel model) 8 | { 9 | decimal result = model.Items.Sum(x => x.Price); 10 | 11 | if (result > 400m) 12 | result *= 0.8m; 13 | 14 | return result; 15 | } 16 | } 17 | 18 | public interface IPaymentService 19 | { 20 | decimal calculate(CartModel model); 21 | } 22 | 23 | public class NullPayment : IPaymentService 24 | { 25 | public decimal calculate(CartModel model) 26 | { 27 | return 0m; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/PaymentServiceNormal.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace NullObjectPattern 4 | { 5 | 6 | public class PaymentServiceNormal 7 | { 8 | public decimal calculate(CartModel model) 9 | { 10 | decimal result = 0m; 11 | if (model == null) 12 | return result; 13 | 14 | result = model.Items.Sum(x => x.Price); 15 | 16 | if (result > 400m) 17 | result *= 0.8m; 18 | 19 | return result; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using System.Xml.Linq; 6 | 7 | namespace NullObjectPattern 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | CartModel model = null; 14 | Console.WriteLine(Calculate(model)); 15 | Console.ReadKey(); 16 | } 17 | 18 | static decimal Calculate(CartModel model) 19 | { 20 | var paymentService = model == null 21 | ? (IPaymentService) 22 | new NullPayment() 23 | : new PaymentService(); 24 | return paymentService.calculate(model); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("NullObjectPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("HP Inc.")] 12 | [assembly: AssemblyProduct("NullObjectPattern")] 13 | [assembly: AssemblyCopyright("Copyright © HP Inc. 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("b44b3d59-73e8-4d10-898a-13da8cb788e5")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/NullObjectPattern/Readme.md: -------------------------------------------------------------------------------- 1 | # Null Object Pattern 2 | 3 | ## 前言: 4 | 5 | 假如在系統中`null`散佈在有許多地方且`null`有相對應的邏輯或行為.這時候就很適合使用`NullObject Pattern`來解決,已Null Object取代`null`邏輯. 6 | 7 | ## Null可能引申出來問題 8 | 9 | 我們知道在.Net或Java中大部分都是參考類型,而null是參考類型的預設值,我們來看看以下程式. 10 | 11 | ```csharp 12 | Person p = null; 13 | Console.WriteLine(p.Age); 14 | ``` 15 | 16 | 如果物件`p`指向`null`且取得`p.Age`時就會`throw NullReferenceException`,所以我們在使用一些參考類型物件前都會先判斷此物件是否為null,在執行後續邏輯. 17 | 18 | 在系統中某一兩個地方這樣判斷還好,但如果一直重複這樣的判斷會造成程式碼不必要的膨脹.... 19 | 20 | 相較於「不帶有null邏輯」的程式碼,面對null邏輯往往需要花費更多心力. 21 | 22 | ## 範例程式 23 | 24 | 下面有段程式碼在`calculate`方法中會判斷`CartModel`物件是否為null並執行相對應邏輯 25 | 26 | ```csharp 27 | public class PaymentServiceNormal 28 | { 29 | public decimal calculate(CartModel model) 30 | { 31 | decimal result = 0m; 32 | if (model == null) 33 | return result; 34 | 35 | result = model.Items.Sum(x => x.Price); 36 | 37 | if (result > 400m) 38 | result *= 0.8m; 39 | 40 | return result; 41 | } 42 | } 43 | ``` 44 | 45 | 我們可以將`calculate`方法提取出一個介面並對於null部份提取成一個類別實現此介面 46 | 47 | 能看到`NullPayment`這個類別已經被賦予相對應動作操作. 48 | 49 | ```csharp 50 | public interface IPaymentService 51 | { 52 | decimal calculate(CartModel model); 53 | } 54 | 55 | public class PaymentService : IPaymentService 56 | { 57 | public decimal calculate(CartModel model) 58 | { 59 | decimal result = model.Items.Sum(x => x.Price); 60 | 61 | if (result > 400m) 62 | result *= 0.8m; 63 | 64 | return result; 65 | } 66 | } 67 | 68 | public class NullPayment : IPaymentService 69 | { 70 | public decimal calculate(CartModel model) 71 | { 72 | return 0m; 73 | } 74 | } 75 | ``` 76 | 77 | 在使用時我們就可統一判斷是否為null來給予相對應物件 78 | 79 | > 這邊有點像是策略者模式(`Strategy pattern`),判斷要使用哪個邏輯,邏輯統一封裝到類別中. 80 | 81 | ```csharp 82 | class Program 83 | { 84 | static void Main(string[] args) 85 | { 86 | CartModel model = null; 87 | Console.WriteLine(Calculate(model)); 88 | Console.ReadKey(); 89 | } 90 | 91 | static decimal Calculate(CartModel model) 92 | { 93 | var paymentService = model == null 94 | ? (IPaymentService) 95 | new NullPayment() 96 | : new PaymentService(); 97 | return paymentService.calculate(model); 98 | } 99 | } 100 | ``` 101 | 102 | ## NullObject Pattern缺點: 103 | 104 | 如果團隊工程師不知道目前程式碼已經存在NullObject實作,會寫出多餘的null測試. 105 | 如果目前系統只是需要少量對於null做判斷,這時導入NullObject會導致程式碼變得複雜. 106 | 107 | ## 小結: 108 | 109 | 假如系統中有許多地方需要判斷null並處理相對應的動作就很適合使用`NullObject` Pattern,但如果判斷null地方不是很多還是判斷就好了 110 | 111 | [程式碼範例](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/NullObjectPattern) -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/IObserveable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace ObserverPattern 7 | { 8 | /// 9 | /// 被觀察介面 10 | /// 11 | public interface IObserveable 12 | { 13 | void AddsubScription(IObservea observea); 14 | void Remove(IObservea observea); 15 | void Notify(string message); 16 | } 17 | 18 | /// 19 | /// 更新訊息 20 | /// 21 | public interface IObservea 22 | { 23 | void Update(string message); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/ObserverPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D3D657F1-A949-4BF4-B8A5-280C8024C398} 8 | Exe 9 | Properties 10 | ObserverPattern 11 | ObserverPattern 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 | 57 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using System.Configuration; 6 | using System.Reflection; 7 | 8 | namespace ObserverPattern 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | 15 | Youtuber youtuber = new Youtuber(); 16 | youtuber.AddsubScription(new Taiwanese(youtuber)); 17 | 18 | youtuber.Notify("頻道開啟"); 19 | 20 | Console.ReadKey(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("ObserverPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ObserverPattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("d3d657f1-a949-4bf4-b8a5-280c8024c398")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/Taiwanese.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace ObserverPattern 8 | { 9 | public class Taiwanese : IObservea 10 | { 11 | private Youtuber _youtuber; 12 | public Taiwanese(Youtuber youtuber) 13 | { 14 | _youtuber = youtuber; 15 | } 16 | 17 | public void Update(string message) 18 | { 19 | Console.WriteLine($"{this.GetType().Name}收到訊息:{message}"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DesignPattern/ObserverPattern/Youtuber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace ObserverPattern 7 | { 8 | public class Youtuber : IObserveable 9 | { 10 | List _observeaList = new List(); 11 | 12 | /// 13 | /// 訂閱 14 | /// 15 | /// 16 | public void AddsubScription(IObservea observea) 17 | { 18 | _observeaList.Add(observea); 19 | } 20 | 21 | /// 22 | /// 移除訂閱 23 | /// 24 | /// 25 | public void Remove(IObservea observea) 26 | { 27 | _observeaList.Remove(observea); 28 | } 29 | 30 | public void Notify(string notifyMessage) 31 | { 32 | foreach (var observea in _observeaList) 33 | { 34 | observea.Update(notifyMessage); 35 | } 36 | } 37 | 38 | public int GetSubScriptCount() 39 | { 40 | return _observeaList.Count; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/DynamicProxy/DynamicProxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Runtime.Remoting.Messaging; 6 | using System.Runtime.Remoting.Proxies; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ProxyPattern.DynamicProxy 11 | { 12 | public class DynamicProxy : RealProxy 13 | where T : MarshalByRefObject 14 | { 15 | private MarshalByRefObject _target; 16 | 17 | public DynamicProxy(T target) : base(typeof(T)) 18 | { 19 | _target = target; 20 | } 21 | 22 | /// 23 | /// 動態攔截方法實作的瞬間 24 | /// 25 | /// 26 | /// 27 | public override IMessage Invoke(IMessage msg) 28 | { 29 | IMethodCallMessage callMethod = msg as IMethodCallMessage; 30 | MethodInfo targetMethod = callMethod.MethodBase as MethodInfo; 31 | IMethodReturnMessage returnMethod = null; 32 | //得到方法上面的標籤 攔截要執行非核心邏輯的動作 33 | var attrs = Attribute.GetCustomAttributes(targetMethod, typeof(AopBaseAttribute)) as AopBaseAttribute[]; 34 | try 35 | { 36 | foreach (var attr in attrs) 37 | { 38 | //執行方法前的動作 39 | attr.Excuting(callMethod.Args); 40 | } 41 | //執行方法 42 | var result = targetMethod.Invoke(_target, callMethod.Args); 43 | returnMethod = new ReturnMessage(result, 44 | callMethod.Args, 45 | callMethod.Args.Length, 46 | callMethod.LogicalCallContext, 47 | callMethod); 48 | foreach (var attr in attrs) 49 | { 50 | //執行方法後動作 51 | attr.Excuted(result); 52 | } 53 | } 54 | catch (Exception ex) 55 | { 56 | returnMethod = new ReturnMessage(ex, callMethod); 57 | } 58 | return returnMethod; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/DynamicProxy/IInterception.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern.DynamicProxy 8 | { 9 | public interface IInterception 10 | { 11 | void Excuted(object result); 12 | 13 | void Excuting(object[] args); 14 | } 15 | } -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/DynamicProxy/LogAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern.DynamicProxy 8 | { 9 | public class LogAttribute : AopBaseAttribute 10 | { 11 | public override void Excuting(object[] args) 12 | { 13 | var user = args.FirstOrDefault() as UserModel; 14 | if (user != null) 15 | { 16 | Console.WriteLine($"DynamicProxy 使用者登入:帳號={user.UserName} 密碼={user.Password}"); 17 | } 18 | Console.WriteLine(); 19 | } 20 | } 21 | 22 | public abstract class AopBaseAttribute : Attribute, IInterception 23 | { 24 | public virtual void Excuted(object result) 25 | { 26 | } 27 | 28 | public virtual void Excuting(object[] args) 29 | { 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/DynamicProxy/Logicservice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern.DynamicProxy 8 | { 9 | public class DLogicservice : MarshalByRefObject 10 | { 11 | private MockUserData userList = new MockUserData(); 12 | 13 | [Log] 14 | public bool IsAuth(UserModel user) 15 | { 16 | Console.WriteLine("IsAuth"); 17 | return userList.GetAllUser() 18 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/MockUserData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern 8 | { 9 | public class MockUserData 10 | { 11 | List _userList = new List(); 12 | 13 | public MockUserData() 14 | { 15 | _userList.Add(new UserModel() { RowID = 1, Password = "123456", UserName = "test123" }); 16 | 17 | } 18 | 19 | public List GetAllUser() 20 | { 21 | return _userList; 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/Normal/LoginService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern 8 | { 9 | public class LoginService 10 | { 11 | MockUserData userList = new MockUserData(); 12 | /// 13 | /// 檢查用戶是否合法 14 | /// 15 | /// 16 | public bool IsUserAuth(UserModel user) 17 | { 18 | Console.WriteLine($"使用者登入:帳號={user.UserName} 密碼={user.Password}"); 19 | //檢驗 20 | return userList.GetAllUser() 21 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 22 | //真正邏輯 23 | 24 | //日誌 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using ProxyPattern; 2 | using ProxyPattern.DynamicProxy; 3 | using ProxyPattern.StaticProxy; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ProxyPattern 11 | { 12 | internal class Program 13 | { 14 | private static void Main(string[] args) 15 | { 16 | #region StaticProxy 17 | 18 | var testUser = new UserModel() { Password = "1234", RowID = 1, UserName = "test" }; 19 | //LogicProxyService staticProxy = new LogicProxyService(new Logicservice()); 20 | //staticProxy.IsAuth(testUser); 21 | 22 | #endregion StaticProxy 23 | 24 | #region DynamicProxy 25 | 26 | //產生代理類別 27 | var proxy = new DynamicProxy(new DLogicservice()); 28 | //取得代理類別實體 29 | var obj = proxy.GetTransparentProxy() as DLogicservice; 30 | //呼叫方法 31 | obj.IsAuth(testUser); 32 | 33 | #endregion DynamicProxy 34 | 35 | Console.ReadKey(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("ProxyPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ProxyPattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("41a8afd7-9699-44f2-a992-5340e717bfcd")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/ProxyPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {41A8AFD7-9699-44F2-A992-5340E717BFCD} 8 | Exe 9 | Properties 10 | ProxyPattern 11 | ProxyPattern 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 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/Readme.md: -------------------------------------------------------------------------------- 1 | # 代理模式(ProxyPattern) 2 | 3 | 前言: 4 | 5 | 1. [什麼是代理模式,為什麼要用他](#什麼是代理模式,為什麼要用他) 6 | 2. [利用.NET實現靜態代理](#利用.NET實現靜態代理) 7 | 3. [利用.NET實現動態代理](#利用.NET實現動態代理) 8 | 9 | ---- 10 | 11 | ## 什麼是代理模式,為什麼要用他 12 | 13 | 大家在寫程式時一定常常遇到要寫日誌,權限驗證....等等和主要邏輯不相干的事情 14 | 15 | 如果把上述這些動作寫在核心邏輯,會讓原有的程式碼變得雜亂 16 | 17 | AOP(面向切面编程)可以有效的幫助我們解決上面問題,降低模塊間耦合度,理念來自於代理模式... 18 | 19 | Asp dot net MVC的`ActionFilterAttribute`就是Aop一個很好的例子 20 | 21 | 只要在Action上加一個自己做的Filter 就可在方法執行前後做事情,且不更動原來程式碼 22 | 23 | 因為不改動原有程式碼,可以降低Bug的發生機會,很經典的實現了OCP(開放封閉原則) 24 | 25 | 我會用已現實生活中常常遇到的 **[登入系統]** 來跟大家介紹代理模式的奧妙 26 | 27 | ---- 28 | 29 | ## 初版程式碼 30 | 31 | 假如我們要寫一個登入程式,在第一版時我們將他的核心邏輯寫完[檢查使用者是否合法] 32 | 33 | ```c# 34 | /// 35 | /// 檢查用戶是否合法 36 | /// 37 | /// 38 | public bool IsUserAuth(UserModel user) 39 | { 40 | return userList.GetAllUser() 41 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 42 | } 43 | ``` 44 | 45 | > 如果沒使用動態代理會怎麼來寫Log呢? 46 | 47 | ```c# 48 | /// 49 | /// 檢查用戶是否合法 50 | /// 51 | /// 52 | public bool IsUserAuth(UserModel user) 53 | { 54 | Console.WriteLine($"使用者登入:帳號={user.UserName} 密碼={user.Password}"); 55 | return userList.GetAllUser() 56 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 57 | } 58 | ``` 59 | 60 | (已Console.WriteLine來代替寫log的程式碼) 61 | 在執行前後寫上Log,但這樣讓程式碼可讀性變差了點,因為Log和檢查使用者是否登入完全沒關係! 62 | 63 | 那我們要怎麼做才可讓程式碼Clear一點呢? 64 | 在下面我會介紹靜態代理模式,來解決上面的問題 65 | 66 | ---- 67 | 68 | ## 利用.NET實現靜態代理 69 | 70 | 我們先理解業務在哪邊,業務在下面紅框的部分 `Console.log` 只是記錄此次驗證的資料 71 | 72 | > 我們可以主要邏輯提取動作來做一個簽章 73 | 74 | ![img](https://az787680.vo.msecnd.net/user/%E4%B9%9D%E6%A1%83/17bcea05-79ca-46d6-8893-d1c4ae124d4f/1507791353_49889.png) 75 | 76 | > 在我心中**介面代表能力,抽象類別代表這一類事物** 77 | 78 | 因為在此次需求驗證是一種能力,所以我提出來成一個介面 79 | 80 | ```c# 81 | public interface ISubject 82 | { 83 | bool IsAuth(UserModel user); 84 | } 85 | ``` 86 | 87 | 有兩個類別 `LogicProxyService`和`Logicservice`都實現 `ISubject` 88 | 因為不管是代理類別和被代理類別都擁有檢核能力 89 | 90 | 我們就可將主要邏輯寫在`Logicservice ` 91 | 92 | ```c# 93 | public class Logicservice : ISubject 94 | { 95 | MockUserData userList = new MockUserData(); 96 | 97 | public bool IsAuth(UserModel user) 98 | { 99 | return userList.GetAllUser() 100 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 101 | } 102 | } 103 | ``` 104 | 105 | 這邊我使用依賴注入的建構子注入,讓外界決定要注入哪個類別(需繼承ISubject) 106 | 可增加未來擴展性和移植性 107 | 撰寫日誌寫在 `LogicProxyService` 108 | 109 | ```c# 110 | public class LogicProxyService : ISubject 111 | { 112 | private ISubject _realSubjcet; 113 | public LogicProxyService(ISubject sub) 114 | { 115 | _realSubjcet = sub; 116 | } 117 | 118 | public bool IsAuth(UserModel user) 119 | { 120 | Console.WriteLine($"使用者登入:帳號={user.UserName} 密碼={user.Password}"); 121 | return _realSubjcet.IsAuth(user); 122 | } 123 | } 124 | ``` 125 | 126 | 在外界只需這樣使用 127 | 128 | 傳入被代理物件 129 | 使用代理物件呼叫方法 130 | 131 | ```c# 132 | #region StaticProxy 133 | var testUser = new UserModel() { Password = "1234", RowID = 1, UserName = "test" }; 134 | LogicProxyService staticProxy = new LogicProxyService(new Logicservice()); 135 | staticProxy.IsAuth(testUser); 136 | #endregion 137 | ``` 138 | 139 | 這樣程式碼就比上一篇乾淨許多了! 寫日誌的程式碼和主要邏輯分離開來 140 | 141 | 靜態代理最主要是將核心邏輯和非核心邏輯分割開來,讓程式碼保持乾淨 142 | 143 | 144 | 但靜態代理還是有個缺點,如我們需要擴充100個代理方法 我需要撰寫100代理類別 145 | 146 | 實在有夠累.... 147 | 148 | 但別擔心在下面會介紹**[動態代理模式]**來解決此問題 149 | 150 | ---- 151 | 152 | ## 利用.NET實現動態代理 153 | 154 | 靜態代理可以將執行邏輯和寫日誌這兩個動作分離乾淨 155 | 156 | Q:但又衍生一個問題是我們有一大堆代理類別要寫,這樣好不方便 157 | 158 | A:如果可以攔截或獲取方法實行的瞬間並在執行前後加上我們寫日誌的動作該有多好 159 | 160 | 聰明的.Net框架 已經幫我們處理上面問題了(不然我們要動態產生一堆程式碼和動態編譯他們...這會累屎人QQ) 161 | 162 | > 何謂動態代理? 163 | 164 | 簡單來說就是 165 | 166 | > 這個代理類別在Runtime期間由程式動態幫我們生產 167 | 168 | 我簡單來使用 [.Net RealProxy](https://docs.microsoft.com/zh-tw/dotnet/api/system.runtime.remoting.proxies.realproxy?redirectedfrom=MSDN&view=netframework-4.7.2) 類別來實作,[透明動態代理] 169 | 170 | 要被RealProxy代理類別要符合以下一種情況 171 | 172 | 1. 介面 173 | 2. 繼承於`MarshalByRefObject` 174 | 175 | 廢話不多說先附上程式碼 176 | 177 | ```c# 178 | public class DynamicProxy : RealProxy 179 | where T : MarshalByRefObject 180 | { 181 | private MarshalByRefObject _target; 182 | 183 | public DynamicProxy(T target) : base(typeof(T)) 184 | { 185 | } 186 | 187 | /// 188 | /// 動態攔截方法實作的瞬間 189 | /// 190 | /// 191 | /// 192 | public override IMessage Invoke(IMessage msg) 193 | { 194 | IMethodCallMessage callMethod = msg as IMethodCallMessage; 195 | MethodInfo targetMethod = callMethod.MethodBase as MethodInfo; 196 | IMethodReturnMessage returnMethod = null; 197 | //得到方法上面的標籤 攔截要執行非核心邏輯的動作 198 | var attrs = Attribute.GetCustomAttributes(targetMethod, typeof(AopBaseAttribute)) as AopBaseAttribute[]; 199 | try 200 | { 201 | foreach (var attr in attrs) 202 | { 203 | //執行方法前的動作 204 | attr.Excuting(callMethod.Args); 205 | } 206 | //執行方法 207 | var result = targetMethod.Invoke(_target, callMethod.Args); 208 | returnMethod = new ReturnMessage(result, 209 | callMethod.Args, 210 | callMethod.Args.Length, 211 | callMethod.LogicalCallContext, 212 | callMethod); 213 | foreach (var attr in attrs) 214 | { 215 | //執行方法後動作 216 | attr.Excuted(result); 217 | } 218 | } 219 | catch (Exception ex) 220 | { 221 | returnMethod = new ReturnMessage(ex, callMethod); 222 | } 223 | return returnMethod; 224 | } 225 | } 226 | ``` 227 | 228 | 這是動態代理最核心的程式碼 229 | 230 | 繼承`RealProxy`類別並實作`IMessage`方法 231 | 232 | ```c# 233 | public override IMessage Invoke(IMessage msg) 234 | ``` 235 | 236 | 我們把上篇的靜態代理改成動態代理 237 | 238 | 首先我們為動態代理新增攔截點製作 `AopBaseAttribute` 239 | 為日後切面擴展程式的基礎 240 | 241 | ```c# 242 | public abstract class AopBaseAttribute : Attribute, IInterception 243 | { 244 | public virtual void Excuted(object result) 245 | { 246 | } 247 | 248 | public virtual void Excuting(object[] args) 249 | { 250 | } 251 | } 252 | ``` 253 | 254 | 新增`LogAttribute` 作為寫日誌的切入點 255 | 256 | ```c# 257 | public class LogAttribute : AopBaseAttribute 258 | { 259 | public override void Excuting(object[] args) 260 | { 261 | var user = args.FirstOrDefault() as UserModel; 262 | if (user != null) 263 | { 264 | Console.WriteLine($"DynamicProxy 使用者登入:帳號={user.UserName} 密碼={user.Password}"); 265 | } 266 | Console.WriteLine(); 267 | } 268 | } 269 | ``` 270 | 271 | 邏輯類別那邊繼承 `MarshalByRefObject` 並將剛剛做的 Log標籤(`Attirbute`) 放在方法上 272 | 273 | ```c# 274 | public class DLogicservice : MarshalByRefObject 275 | { 276 | private MockUserData userList = new MockUserData(); 277 | 278 | [Log] 279 | public bool IsAuth(UserModel user) 280 | { 281 | return userList.GetAllUser() 282 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 283 | } 284 | } 285 | ``` 286 | 287 | 調用時只需要這樣 288 | 289 | ```c# 290 | //產生代理類別 291 | var proxy = new DynamicProxy(new DLogicservice()); 292 | //取得代理類別實體 293 | var obj = proxy.GetTransparentProxy() as DLogicservice; 294 | //呼叫方法 295 | obj.IsAuth(testUser); 296 | ``` 297 | 298 | 另外小弟有參考ASP.Net原始碼來製作動態的攔截器框架 [AwesomeProxy.Net](https://github.com/isdaniel/AwesomeProxy.Net) ,放在github上面歡迎大家討論 -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/StaticProxy/ISubject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern.StaticProxy 8 | { 9 | public interface ISubject 10 | { 11 | bool IsAuth(UserModel user); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/StaticProxy/LogicProxyService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern.StaticProxy 8 | { 9 | public class LogicProxyService : ISubject 10 | { 11 | private ISubject _realSubjcet; 12 | public LogicProxyService(ISubject sub) 13 | { 14 | _realSubjcet = sub; 15 | } 16 | 17 | public bool IsAuth(UserModel user) 18 | { 19 | Console.WriteLine($"使用者登入:帳號={user.UserName} 密碼={user.Password}"); 20 | return _realSubjcet.IsAuth(user); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/StaticProxy/Logicservice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern.StaticProxy 8 | { 9 | public class Logicservice : ISubject 10 | { 11 | MockUserData userList = new MockUserData(); 12 | 13 | public bool IsAuth(UserModel user) 14 | { 15 | return userList.GetAllUser() 16 | .Any(o => user.UserName == o.UserName && user.Password == o.Password); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DesignPattern/ProxyPattern/UserModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ProxyPattern 8 | { 9 | public class UserModel 10 | { 11 | public long RowID { get; set; } 12 | public string UserName { get; set; } 13 | 14 | public string Password { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/ConnectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleFactory 7 | { 8 | public class ConnectionFactory 9 | { 10 | 11 | public static IDbConcrete GetConnection(SimpleFactory.DBType type) 12 | { 13 | IDbConcrete db = null; 14 | switch (type) 15 | { 16 | case DBType.MySQL: 17 | db=new MySQL(); 18 | break; 19 | case DBType.MSSQL: 20 | db = new MSSQL(); 21 | break; 22 | case DBType.Oracle: 23 | db = new Oracle(); 24 | break; 25 | default: 26 | db = new MSSQL(); 27 | break; 28 | } 29 | return db; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/DBType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleFactory 7 | { 8 | public enum DBType 9 | { 10 | MySQL, 11 | MSSQL, 12 | Oracle 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/IDbConcrete.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleFactory 7 | { 8 | public interface IDbConcrete 9 | { 10 | void GetDBConcrete(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/MSSQL.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleFactory 7 | { 8 | public class MSSQL : IDbConcrete 9 | { 10 | public void GetDBConcrete() 11 | { 12 | Console.WriteLine("執行MYSQL"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/MySQL.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleFactory 7 | { 8 | public class MySQL : IDbConcrete 9 | { 10 | public void GetDBConcrete() 11 | { 12 | Console.WriteLine("執行MYSQL"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/Oracle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using System.Configuration; 6 | namespace SimpleFactory 7 | { 8 | public class Oracle : IDbConcrete 9 | { 10 | public void GetDBConcrete() 11 | { 12 | Console.WriteLine("執行Oracle"); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleFactory 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | IDbConcrete dataConner = ConnectionFactory.GetConnection(DBType.MySQL); 13 | dataConner.GetDBConcrete(); 14 | Console.ReadKey(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("SimpleFactory")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SimpleFactory")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("35a3a267-4ecc-411d-a163-e718a17aed30")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/Readme.md: -------------------------------------------------------------------------------- 1 | Simple Factory,Factory,簡單工廠模式 2 | 3 | 今天和大家介紹另一個常用且簡單的模式 4 | 5 | 在.net中`MSSQL`和`MYSQL` 都是連接資料庫 但只是插在連接使用的類別不一樣 6 | 7 | 那我們要怎麼封裝到一個類上呢? 8 | 9 | 這時候可以使用工廠模式 10 | 11 | UML圖: 12 | 13 | ![Alt text](https://raw.githubusercontent.com/isdaniel/DesignPattern/master/DesignPattern/img/simpleFactory/simpleFatory.png) 14 | 15 | 定義一個 介面`IDbConcrete` 裡面提供 連接資料庫之動作 16 | 17 | public interface IDbConcrete 18 | { 19 | void GetDBConcrete(); 20 | } 21 | 22 | 分別定義`MSSQL,MYSQL,ORACLE` 三個連接資料庫 並實現 IDbConcrete實作 連接方式 23 | 24 | public class MSSQL : IDbConcrete 25 | { 26 | public void GetDBConcrete() 27 | { 28 | Console.WriteLine("執行MYSQL"); 29 | } 30 | } 31 | 32 | 33 | public class MySQL:IDbConcrete 34 | { 35 | public void GetDBConcrete() 36 | { 37 | Console.WriteLine("執行MYSQL"); 38 | } 39 | } 40 | 41 | 42 | public class Oracle : IDbConcrete 43 | { 44 | public void GetDBConcrete() 45 | { 46 | Console.WriteLine("執行Oracle"); 47 | } 48 | } 49 | 50 | 最重要工廠實體類 ConnectionFactory 51 | 52 | public class ConnectionFactory 53 | { 54 | public static IDbConcrete GetConnection(DBType type) { 55 | IDbConcrete db = null; 56 | switch (type) 57 | { 58 | case DBType.MySQL: 59 | db=new MySQL(); 60 | break; 61 | case DBType.MSSQL: 62 | db = new MSSQL(); 63 | break; 64 | case DBType.Oracle: 65 | db = new Oracle(); 66 | break; 67 | default: 68 | db = new MSSQL(); 69 | break; 70 | } 71 | return db; 72 | } 73 | } 74 | 75 | 我們在外面呼叫就很簡單 給一個參數就會由工廠提供給我們一個相對應的實體 76 | 77 | class Program 78 | { 79 | static void Main(string[] args) 80 | { 81 | IDbConcrete dataConner = ConnectionFactory.GetConnection(DBType.MySQL); 82 | dataConner.GetDBConcrete(); 83 | Console.ReadKey(); 84 | } 85 | } 86 | 87 | 88 | 但簡單工廠有個不足的地方,日後有追加實體須在工廠類中的switch新增 ex:新增DB2連接方式 89 | 違反開放封閉原則(OCP) -------------------------------------------------------------------------------- /DesignPattern/SimpleFactory/SimpleFactory.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {35A3A267-4ECC-411D-A163-E718A17AED30} 8 | Exe 9 | Properties 10 | SimpleFactory 11 | SimpleFactory 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 | 51 | 52 | 53 | 60 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/Normal/PaymentContext.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern.Normal 2 | { 3 | public class PaymentContext 4 | { 5 | Product _Item { get; set; } 6 | 7 | PayStatus _status { get; set; } 8 | 9 | public PaymentContext(Product p) 10 | { 11 | _Item = p; 12 | _status = PayStatus.Init; 13 | } 14 | 15 | /// 16 | /// 設置狀態 17 | /// 18 | /// 19 | public string SetStatus(PayStatus status) { 20 | string result = $"修改成功{status.ToString()}"; 21 | switch (_status) 22 | { 23 | case PayStatus.Init: 24 | if (status == PayStatus.Init) 25 | result = "請勿重新建立訂單"; 26 | else 27 | _status = status; 28 | break; 29 | case PayStatus.Success: 30 | result = "訂單成功請勿修改"; 31 | break; 32 | case PayStatus.Cancel: 33 | result = "訂單取消請勿修改"; 34 | break; 35 | case PayStatus.Processing: 36 | if (status == PayStatus.Init) 37 | result = "請勿重新建立訂單"; 38 | else 39 | _status = status; 40 | break; 41 | } 42 | 43 | 44 | return result; 45 | } 46 | 47 | /// 48 | /// 跑流程 49 | /// 50 | /// 51 | public string RunProcess() { 52 | 53 | switch (_status) 54 | { 55 | case PayStatus.Init: 56 | _status = PayStatus.Processing; 57 | return "交易建立中..."; 58 | case PayStatus.Success: 59 | return "交易完成"; 60 | case PayStatus.Cancel: 61 | return "交易取消完成"; 62 | case PayStatus.Processing: 63 | if (_Item.Price > 300) 64 | { 65 | _status = PayStatus.Cancel; 66 | return "物件超過300元 交易取消中"; 67 | } 68 | _status = PayStatus.Success; 69 | return "交易中請稍後"; 70 | } 71 | return "不在狀態內"; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/Program.cs: -------------------------------------------------------------------------------- 1 | using StatePattern.Normal; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace StatePattern 8 | { 9 | public class Product { 10 | public decimal Price { get; set; } 11 | 12 | public string Name { get; set; } 13 | 14 | } 15 | 16 | public enum PayStatus { 17 | Init, 18 | Success, 19 | Cancel, 20 | Processing 21 | } 22 | 23 | class Program 24 | { 25 | static void Main(string[] args) 26 | { 27 | Product p = new Product(); 28 | p.Name = "電腦"; 29 | p.Price = 300000; 30 | 31 | PaymentGate context = new PaymentGate(p); 32 | Console.WriteLine(context.RunProcess()); 33 | Console.WriteLine(context.RunProcess()); 34 | Console.WriteLine(context.RunProcess()); 35 | context.SetStatus(PayStatus.Init); 36 | Console.WriteLine(context.RunProcess()); 37 | Console.ReadKey(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("StatePattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("StatePattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("10ec9e65-1d6f-4b0d-a06c-9f5bf5306505")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/Readme.md: -------------------------------------------------------------------------------- 1 | # 狀態者模式 2 | 3 | 優勢在可將複雜的物件狀態條件,以物件方式來減少條件式的判斷程式 4 | 5 | 可由物件自身的狀態,決定之後的動作行為. 6 | 7 | 需求簡易流程如下 8 | 9 | 這是一個簡單的訂單流程圖 10 | 11 | ![Alt text](../img/Status/1.png "Optional title") 12 | 13 | 我們可看到從建立訂單開始->最後判斷成功或取消訂單 看似簡單但需要寫一定程度的判斷條件式,而且也要做一定程度的逆向流程防呆. 14 | 15 | 這裡先貼上 未使用狀態者模式的程式碼: `PaymentContext.cs` 16 | 17 | ```c# 18 | public class PaymentContext 19 | { 20 | Product _Item { get; set; } 21 | 22 | PayStatus _status { get; set; } 23 | 24 | public PaymentContext(Product p) 25 | { 26 | _Item = p; 27 | _status = PayStatus.Init; 28 | } 29 | 30 | /// 31 | /// 設置狀態 32 | /// 33 | /// 34 | public string SetStatus(PayStatus status) { 35 | string result = $"修改成功{status.ToString()}"; 36 | switch (_status) 37 | { 38 | case PayStatus.Init: 39 | if (status == PayStatus.Init) 40 | result = "請勿重新建立訂單"; 41 | else 42 | _status = status; 43 | break; 44 | case PayStatus.Success: 45 | result = "訂單成功請勿修改"; 46 | break; 47 | case PayStatus.Cancel: 48 | result = "訂單取消請勿修改"; 49 | break; 50 | case PayStatus.Processing: 51 | if (status == PayStatus.Init) 52 | result = "請勿重新建立訂單"; 53 | else 54 | _status = status; 55 | break; 56 | } 57 | 58 | 59 | return result; 60 | } 61 | 62 | /// 63 | /// 跑流程 64 | /// 65 | /// 66 | public string RunProcess() { 67 | 68 | switch (_status) 69 | { 70 | case PayStatus.Init: 71 | _status = PayStatus.Processing; 72 | return "交易建立中..."; 73 | case PayStatus.Success: 74 | return "交易完成"; 75 | case PayStatus.Cancel: 76 | return "交易取消完成"; 77 | case PayStatus.Processing: 78 | if (_Item.Price > 300) 79 | { 80 | _status = PayStatus.Cancel; 81 | return "物件超過300元 交易取消中"; 82 | } 83 | _status = PayStatus.Success; 84 | return "交易中請稍後"; 85 | } 86 | return "不在狀態內"; 87 | } 88 | } 89 | ``` 90 | 91 | 裡面有`SetStatus` 和 `RunProcess` 方法 92 | 93 | `RunProcess` 方法 就是將商品一個往下一個流程推進 94 | `SetStatus` 方法 可以改變商品狀態 95 | 上面類別中的程式碼 目前有點小複雜但還算簡單,但等日後需求越來越多 後人一直把程式碼寫入`Switch case` 或`if ... else` 中就會導致程式碼越來越複雜 96 | 97 | 這個情境我們可以嘗試使用**State Pattern(狀態者模式)** 98 | 99 | 幫助我們將每個自身狀態封裝到物件裡面,由每個狀態來決定後面動作 100 | 我們可發現 每個流程都可以使用 `RunningProcee` 和 `SetSatus` 這兩個動作 101 | 102 | 就可開出一個抽象類別,裡面有這兩個抽象方法,給之後的狀態子類去實現. 103 | 104 | ```c# 105 | public abstract class PaymentSatusBase 106 | { 107 | protected PaymentGate _gate; 108 | public abstract string Running(Product p); 109 | 110 | public abstract string SetSatus(PayStatus s); 111 | } 112 | ``` 113 | 114 | `PaymentGate` 是給外部呼叫端使用的類別,我們可比較上面之前`PaymentContext`類別可看到`if....else` 全部不見了, 115 | 116 | 因為狀態封裝到各個類別中了 117 | 118 | ```c# 119 | public class PaymentGate 120 | { 121 | Product _product; 122 | 123 | internal PaymentSatusBase CurrnetProceess { get; set; } // 這裡擁有下個流程的引用 124 | 125 | public PaymentGate(Product p) 126 | { 127 | _product = p; 128 | CurrnetProceess = new InitSatus(this); 129 | } 130 | 131 | internal PayStatus CurrnetStatus { get; set; } 132 | 133 | /// 134 | /// 設置狀態 135 | /// 136 | /// 137 | public string SetStatus(PayStatus status) 138 | { 139 | return CurrnetProceess.SetSatus(status); 140 | } 141 | 142 | /// 143 | /// 跑流程 144 | /// 145 | /// 146 | public string RunProcess() 147 | { 148 | return CurrnetProceess.Running(_product); 149 | } 150 | } 151 | ``` 152 | 153 | 如何新建一個流程物件? 154 | 首先我們需要先取得當前使用者使用的 `PaymentGate` 引用並傳入建構子當作參數 155 | 實現`Running`和`SetStatus`方法,並將此狀態的邏輯寫上 156 | 執行完後需要更改下個流程,可以將值賦予給`CurrnetProceess` 屬性 157 | 158 | ```c# 159 | public class ProcessSatus : PaymentSatusBase 160 | { 161 | public ProcessSatus(PaymentGate g) 162 | { 163 | _gate = g; 164 | } 165 | public override string Running(Product p) 166 | { 167 | string result = "交易中請稍後"; 168 | 169 | if (p.Price > 300) 170 | { 171 | result = "物件超過300元 交易取消中"; 172 | _gate.CurrnetProceess = new CancelSatus(_gate); 173 | } 174 | else 175 | _gate.CurrnetProceess = new SuccessSatus(_gate); 176 | 177 | return result; 178 | } 179 | 180 | public override string SetSatus(PayStatus s) 181 | { 182 | string result = string.Empty; 183 | if (s == PayStatus.Init) 184 | result = "請勿重新建立訂單"; 185 | return result; 186 | } 187 | } 188 | ``` 189 | 190 | 說明: 191 | 192 | 以流程進行中為例子. 193 | 194 | 他會判斷商品使用超過300元,來決定下個流程 所以我們就把這個邏輯寫在此類中. 195 | 196 | 另外後面幾個流程比照辦理全部搬入類別中 197 | 198 | ```c# 199 | public class CancelSatus : PaymentSatusBase 200 | { 201 | public CancelSatus(PaymentGate g) 202 | { 203 | _gate = g; 204 | } 205 | public override string Running(Product p) 206 | { 207 | return "交易取消完成"; 208 | } 209 | 210 | public override string SetSatus(PayStatus s) 211 | { 212 | string result = string.Empty; 213 | if (s == PayStatus.Init) 214 | result = "訂單取消請勿修改"; 215 | return result; 216 | } 217 | } 218 | 219 | 220 | public class SuccessSatus : PaymentSatusBase 221 | { 222 | public SuccessSatus(PaymentGate g) 223 | { 224 | _gate = g; 225 | } 226 | 227 | public override string Running(Product p) 228 | { 229 | return "交易完成"; 230 | } 231 | 232 | public override string SetSatus(PayStatus s) 233 | { 234 | string result = string.Empty; 235 | if (s == PayStatus.Init) 236 | result = "訂單成功請勿修改"; 237 | return result; 238 | } 239 | } 240 | ``` 241 | 242 | 最後外部程式使用如下 243 | 244 | ```c# 245 | Product p = new Product(); 246 | p.Name = "電腦"; 247 | p.Price = 300000; 248 | 249 | PaymentGate context = new PaymentGate(p); 250 | Console.WriteLine(context.RunProcess()); 251 | Console.WriteLine(context.RunProcess()); 252 | Console.WriteLine(context.RunProcess()); 253 | context.SetStatus(PayStatus.Init); 254 | Console.WriteLine(context.RunProcess()); 255 | ``` -------------------------------------------------------------------------------- /DesignPattern/StatePattern/State/CancelStatus.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern 2 | { 3 | public class CancelStatus : PaymentStatusBase 4 | { 5 | public CancelStatus(PaymentGate g) 6 | { 7 | _gate = g; 8 | } 9 | public override string Running(Product p) 10 | { 11 | return "交易取消完成"; 12 | } 13 | 14 | public override string SetStatus(PayStatus s) 15 | { 16 | string result = string.Empty; 17 | if (s == PayStatus.Init) 18 | result = "訂單取消請勿修改"; 19 | return result; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /DesignPattern/StatePattern/State/InitStatus.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern 2 | { 3 | public class InitStatus : PaymentStatusBase 4 | { 5 | 6 | public InitStatus(PaymentGate g) 7 | { 8 | _gate = g; 9 | } 10 | 11 | public override string Running(Product p) 12 | { 13 | _gate.CurrentProcess = new ProcessStatus(_gate); 14 | return "交易建立中..."; 15 | } 16 | 17 | public override string SetStatus(PayStatus status) 18 | { 19 | 20 | string result = ""; 21 | if (status == PayStatus.Init) 22 | result = "請勿重新建立訂單"; 23 | else 24 | _gate.CurrentStatus = status; 25 | 26 | return result; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /DesignPattern/StatePattern/State/PaymentGate.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern 2 | { 3 | public class PaymentGate 4 | { 5 | private readonly Product _product; 6 | 7 | internal PaymentStatusBase CurrentProcess { get; set; } 8 | 9 | public PaymentGate(Product p) 10 | { 11 | _product = p; 12 | CurrentProcess = new InitStatus(this); 13 | } 14 | 15 | internal PayStatus CurrentStatus { get; set; } 16 | 17 | /// 18 | /// 設置狀態 19 | /// 20 | /// 21 | public string SetStatus(PayStatus status) 22 | { 23 | return CurrentProcess.SetStatus(status); 24 | } 25 | 26 | /// 27 | /// 跑流程 28 | /// 29 | /// 30 | public string RunProcess() 31 | { 32 | return CurrentProcess.Running(_product); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/State/PaymentStatusBase.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern 2 | { 3 | public abstract class PaymentStatusBase 4 | { 5 | protected PaymentGate _gate; 6 | public abstract string Running(Product p); 7 | 8 | public abstract string SetStatus(PayStatus s); 9 | } 10 | } -------------------------------------------------------------------------------- /DesignPattern/StatePattern/State/ProcessStatus.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern 2 | { 3 | public class ProcessStatus : PaymentStatusBase 4 | { 5 | public ProcessStatus(PaymentGate g) 6 | { 7 | _gate = g; 8 | } 9 | public override string Running(Product p) 10 | { 11 | string result = "交易中請稍後"; 12 | 13 | if (p.Price > 300) 14 | { 15 | result = "物件超過300元 交易取消中"; 16 | _gate.CurrentProcess = new CancelStatus(_gate); 17 | } 18 | else 19 | _gate.CurrentProcess = new SuccessStatus(_gate); 20 | 21 | return result; 22 | } 23 | 24 | public override string SetStatus(PayStatus s) 25 | { 26 | string result = string.Empty; 27 | if (s == PayStatus.Init) 28 | result = "請勿重新建立訂單"; 29 | return result; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /DesignPattern/StatePattern/State/SuccessStatus.cs: -------------------------------------------------------------------------------- 1 | namespace StatePattern 2 | { 3 | public class SuccessStatus : PaymentStatusBase 4 | { 5 | public SuccessStatus(PaymentGate g) 6 | { 7 | _gate = g; 8 | } 9 | 10 | public override string Running(Product p) 11 | { 12 | return "交易完成"; 13 | } 14 | 15 | public override string SetStatus(PayStatus s) 16 | { 17 | string result = string.Empty; 18 | if (s == PayStatus.Init) 19 | result = "訂單成功請勿修改"; 20 | return result; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /DesignPattern/StatePattern/StatePattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {10EC9E65-1D6F-4B0D-A06C-9F5BF5306505} 8 | Exe 9 | Properties 10 | StatePattern 11 | StatePattern 12 | v4.5 13 | 512 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 | 50 | 51 | Designer 52 | 53 | 54 | 55 | 62 | -------------------------------------------------------------------------------- /DesignPattern/StatePattern/StatePattern.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /DesignPattern/StatePatternTests/Normal/PaymentContextTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using StatePattern; 3 | 4 | namespace StatePatternTests.Normal 5 | { 6 | [TestClass()] 7 | public class PaymentGateTests 8 | { 9 | [TestMethod()] 10 | public void Normal_Item() 11 | { 12 | Product p = new Product() { Name = "蘋果", Price = 30 }; 13 | PaymentGate context = new PaymentGate(p); 14 | 15 | Assert.AreEqual("交易建立中...", context.RunProcess()); 16 | Assert.AreEqual("交易中請稍後", context.RunProcess()); 17 | Assert.AreEqual("交易完成", context.RunProcess()); 18 | } 19 | 20 | [TestMethod()] 21 | public void Normal_OverPriceItem() 22 | { 23 | Product p = new Product() { Name = "蘋果", Price = 5555 }; 24 | PaymentGate context = new PaymentGate(p); 25 | 26 | Assert.AreEqual("交易建立中...", context.RunProcess()); 27 | Assert.AreEqual("物件超過300元 交易取消中", context.RunProcess()); 28 | Assert.AreEqual("交易取消完成", context.RunProcess()); 29 | } 30 | 31 | [TestMethod()] 32 | public void SetProcess_Cancel_AlterDontResetAgain() 33 | { 34 | Product p = new Product() { Name = "蘋果", Price = 3000 }; 35 | PaymentGate context = new PaymentGate(p); 36 | 37 | Assert.AreEqual("請勿重新建立訂單", context.SetStatus(PayStatus.Init)); 38 | Assert.AreEqual("交易建立中...", context.RunProcess()); 39 | Assert.AreEqual("請勿重新建立訂單", context.SetStatus(PayStatus.Init)); 40 | Assert.AreEqual("物件超過300元 交易取消中", context.RunProcess()); 41 | Assert.AreEqual("交易取消完成", context.RunProcess()); 42 | Assert.AreEqual("訂單取消請勿修改", context.SetStatus(PayStatus.Init)); 43 | } 44 | 45 | [TestMethod()] 46 | public void SetProcess_Success_AlterDontResetAgain() 47 | { 48 | Product p = new Product() { Name = "蘋果", Price = 30 }; 49 | PaymentGate context = new PaymentGate(p); 50 | 51 | Assert.AreEqual("請勿重新建立訂單", context.SetStatus(PayStatus.Init)); 52 | Assert.AreEqual("交易建立中...", context.RunProcess()); 53 | Assert.AreEqual("請勿重新建立訂單", context.SetStatus(PayStatus.Init)); 54 | Assert.AreEqual("交易中請稍後", context.RunProcess()); 55 | Assert.AreEqual("交易完成", context.RunProcess()); 56 | Assert.AreEqual("訂單成功請勿修改", context.SetStatus(PayStatus.Init)); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /DesignPattern/StatePatternTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("StatePatternTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("StatePatternTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("5d69cc35-d38f-47af-9bf3-2f81d69442ce")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/StatePatternTests/StatePatternTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {5D69CC35-D38F-47AF-9BF3-2F81D69442CE} 7 | Library 8 | Properties 9 | StatePatternTests 10 | StatePatternTests 11 | v4.5 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {10EC9E65-1D6F-4B0D-A06C-9F5BF5306505} 59 | StatePattern 60 | 61 | 62 | 63 | 64 | 65 | 66 | False 67 | 68 | 69 | False 70 | 71 | 72 | False 73 | 74 | 75 | False 76 | 77 | 78 | 79 | 80 | 81 | 82 | 89 | -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/Person.cs: -------------------------------------------------------------------------------- 1 | namespace StrategyPattern 2 | { 3 | public class Person 4 | { 5 | public int Age { get; set; } 6 | 7 | public string Name { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Threading.Tasks; 4 | using StrategyPattern.Strategy; 5 | 6 | namespace StrategyPattern 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | int[] arr = new[] {5, 3, 2, 4,1,10}; 13 | foreach (var item in arr.SortByStrategy(new CompareInt())) 14 | { 15 | Console.WriteLine(item); 16 | } 17 | Console.ReadKey(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("StrategyPattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("HP Inc.")] 12 | [assembly: AssemblyProduct("StrategyPattern")] 13 | [assembly: AssemblyCopyright("Copyright © HP Inc. 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("1bf8c0b1-23f7-497c-94ee-ea239936e730")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/SortExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using StrategyPattern.Strategy; 5 | 6 | namespace StrategyPattern 7 | { 8 | public static class SortExtension 9 | { 10 | public static Person[] SortByStrategy(this Person[] list) 11 | { 12 | if (list == null) 13 | throw new ArgumentException("list can't be null"); 14 | 15 | for (int i = 1; i < list.Count(); i++) 16 | { 17 | for (int j = i; j < list.Count(); j++) 18 | { 19 | //這邊需要寫死比較方式 20 | if (list[i - 1].Age > list[j].Age) 21 | { 22 | Swap(list, j, i); 23 | } 24 | } 25 | } 26 | 27 | return list; 28 | } 29 | 30 | 31 | public static T[] SortByStrategy(this T[] list, ICompareStrategy compare) 32 | { 33 | if (list == null || compare == null) 34 | throw new ArgumentException("list can't be null"); 35 | 36 | for (int i = 1; i < list.Count(); i++) 37 | { 38 | for (int j = i; j < list.Count(); j++) 39 | { 40 | //自訂一個規則介面,比較方式由外部提供 由外部注入!! 41 | if (compare.Compare(list[i - 1], list[j]) > 0) 42 | { 43 | Swap(list, j, i); 44 | } 45 | } 46 | } 47 | 48 | return list; 49 | } 50 | 51 | private static void Swap(T[] list, int j, int i) 52 | { 53 | T temp = list[j]; 54 | list[j] = list[i - 1]; 55 | list[i - 1] = temp; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/Strategy/CompareInt.cs: -------------------------------------------------------------------------------- 1 | namespace StrategyPattern.Strategy 2 | { 3 | public class CompareInt : ICompareStrategy 4 | { 5 | public int Compare(int obj1, int obj2) 6 | { 7 | if (obj1 > obj2) 8 | return 1; 9 | 10 | return -1; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/Strategy/ComparePerson.cs: -------------------------------------------------------------------------------- 1 | namespace StrategyPattern.Strategy 2 | { 3 | public class ComparePerson : ICompareStrategy 4 | { 5 | public int Compare(Person obj1, Person obj2) 6 | { 7 | if (obj1.Age > obj2.Age) 8 | return 1; 9 | 10 | return -1; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/Strategy/ICompareStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace StrategyPattern.Strategy 2 | { 3 | public interface ICompareStrategy 4 | { 5 | int Compare(T obj1, T obj2); 6 | } 7 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPattern/StrategyPattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1BF8C0B1-23F7-497C-94EE-EA239936E730} 8 | Exe 9 | Properties 10 | StrategyPattern 11 | StrategyPattern 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 | 51 | 52 | 53 | 54 | 55 | 62 | -------------------------------------------------------------------------------- /DesignPattern/StrategyPatternTests/CompareIntTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using StrategyPattern; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using StrategyPattern.Strategy; 9 | 10 | namespace StrategyPattern.Tests 11 | { 12 | [TestClass()] 13 | public class CompareIntTests 14 | { 15 | [TestMethod()] 16 | public void CompareTest() 17 | { 18 | int[] arrange = new[] { 5, 3, 2, 4, 1, 10 }; 19 | 20 | int[] expect = new[] {1, 2, 3, 4, 5, 10}; 21 | 22 | int[] act = arrange.SortByStrategy(new CompareInt()).ToArray(); 23 | 24 | CollectionAssert.AreEqual(expect, act); 25 | } 26 | 27 | [TestMethod()] 28 | public void CompareTest1() 29 | { 30 | int[] arrange = new[] {1,2,3,4,5 }; 31 | 32 | int[] expect = new[] { 1, 2, 3, 4, 5 }; 33 | 34 | int[] act = arrange.SortByStrategy(new CompareInt()).ToArray(); 35 | 36 | CollectionAssert.AreEqual(expect, act); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPatternTests/ComparePersonTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using StrategyPattern; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using StrategyPattern.Strategy; 10 | 11 | namespace StrategyPattern.Tests 12 | { 13 | [TestClass()] 14 | public class ComparePersonTests 15 | { 16 | [TestMethod()] 17 | public void CompareTest() 18 | { 19 | var p1 = new Person() {Age = 10, Name = "Daniel"}; 20 | var p2 = new Person() { Age = 1, Name = "Daniel1" }; 21 | 22 | IEnumerable persons = new List() 23 | { 24 | p1, 25 | p2 26 | }; 27 | 28 | ICollection expect = new List() {p2, p1}; 29 | 30 | ICollection act = persons.ToArray() 31 | .SortByStrategy(new ComparePerson()).ToList(); 32 | 33 | CollectionAssert.AreEqual(expect, act); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /DesignPattern/StrategyPatternTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("StrategyPatternTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("HP Inc.")] 12 | [assembly: AssemblyProduct("StrategyPatternTests")] 13 | [assembly: AssemblyCopyright("Copyright © HP Inc. 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設定為 false 會使得這個組件中的類型 18 | // 對 COM 元件而言為不可見。如果您需要從 COM 存取這個組件中 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("9858dfff-fc73-491f-ae59-e91e588e90a8")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,也可以依照以下的方式,使用 '*' 將組建和修訂編號 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DesignPattern/StrategyPatternTests/StrategyPatternTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {9858DFFF-FC73-491F-AE59-E91E588E90A8} 7 | Library 8 | Properties 9 | StrategyPatternTests 10 | StrategyPatternTests 11 | v4.5.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {1BF8C0B1-23F7-497C-94EE-EA239936E730} 61 | StrategyPattern 62 | 63 | 64 | 65 | 66 | 67 | 68 | False 69 | 70 | 71 | False 72 | 73 | 74 | False 75 | 76 | 77 | False 78 | 79 | 80 | 81 | 82 | 83 | 84 | 91 | -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace TemplatePattern 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | 14 | UnitCounter unitCounter = new UnitCounter(); 15 | unitCounter.UnitTest(new List>() 16 | { 17 | ()=>true, 18 | ()=>false, 19 | ()=>false, 20 | ()=>true 21 | }); 22 | 23 | Console.ReadKey(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/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("TemplatePattern")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TemplatePattern")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 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("10392cbe-21ff-45da-a1b1-5f71e356740f")] 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 | -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/Readme.md: -------------------------------------------------------------------------------- 1 | # 樣板模式(TemplatePattern) 2 | 3 | 如果目前場景遇到一定流程階段,但流程內容依照邏輯或情境不同也有所不一樣. 4 | 這時可以考慮使用**樣板模式(TemplatePattern)** 5 | 6 | ----- 7 | 8 | ## 生活舉例: 9 | 10 | 因為十二年國教,所以基本上每個人都有上學的經驗 11 | 12 | 每天上學最少要經歷下面過程(我做一些簡化) 13 | 14 | > 到學校=>上午上課=>吃午餐=>下午上課=>放學回家 15 | 16 | 可以看到不管是國小、國中、高中 至少都有上述的過程 17 | 18 | 但每個過程內容可能會依照年級階段不同,也有所不一樣 19 | 20 | 例如: 21 | * 吃中餐:高中可能是吃便當,但國小是吃營養午餐,雖然都是吃飯但內容不一樣。 22 | * 上午上課:都是教數學,但高中教微積分,國小教加減乘除。 23 | 24 | > 重點:流程雖一樣但細部邏輯交由學校去實施實現 25 | 26 | ----- 27 | 28 | ## 常見例子: 29 | 30 | 我們常見的測試框架 `MSTest,NUnit.....` 都有樣板模式的思想。 31 | 32 | 一般來說測試框架都有**生命週期**,只是每個框架命名不一樣但核心原理差不多 33 | 34 | 1. SetUpClass (每個測試類別只都執行一次) 35 | 2. SetUpUnitTest (每次執行測試方法時都執行一次) 36 | 3. UnitTest (執行測試方法) 37 | 38 | 39 | **如下圖** 40 | 41 | ![Alt text](https://www.codeproject.com/KB/cs/autp1/testSuiteFlow.jpg "Optional title") 42 | 43 | (圖片來自網路上) 44 | 45 | ----- 46 | 47 | 範例: 48 | 49 | 此範例使用Console來模擬單元測試框架流程: 50 | 51 | 建立一個 `UnitFlowBase` 抽像類別,裡面有三個方法 52 | 53 | 1. SetUpClass (每個測試類別只都執行一次) 54 | 2. SetUpUnitTest (每次執行測試方法時都執行一次) 55 | 3. UnitTest (執行測試方法) 56 | 57 | 此抽象類別提供3個Hock讓子類實做細節。 58 | `UnitFlowBase`只提供框架 59 | 60 | ```c# 61 | public abstract class UnitFlowBase 62 | { 63 | protected UnitFlowBase() 64 | { 65 | SetUpClass(); 66 | } 67 | 68 | protected virtual void SetUpClass() 69 | { 70 | } 71 | 72 | protected virtual void SetUpUnitTest() 73 | { 74 | } 75 | 76 | protected abstract bool Execute(); 77 | 78 | public void UnitTest() 79 | { 80 | SetUpUnitTest(); 81 | Console.WriteLine(Execute() ? "Assert Successful." : "Assert Fail."); 82 | } 83 | } 84 | ``` 85 | 86 | 建立另一個類別`UnitCounter` 實現那三個方法 87 | 特別是`Execute`方法 我顯示目前 `ClassCount` 跟 `MethodCount` 執行次數 88 | 89 | ```C# 90 | public class UnitCounter : UnitFlowBase 91 | { 92 | private int _classCounter = 0; 93 | 94 | private int _methodCounter = 0; 95 | 96 | protected override void SetUpClass() 97 | { 98 | _classCounter++; 99 | } 100 | 101 | protected override void SetUpUnitTest() 102 | { 103 | _methodCounter++; 104 | } 105 | 106 | protected override bool Execute() 107 | { 108 | Console.WriteLine($"ClassCounter : {_classCounter}"); 109 | Console.WriteLine($"MethodCounter: { _methodCounter}"); 110 | 111 | return true; 112 | } 113 | } 114 | ``` 115 | 116 | 呼叫實我們建立一個`UnitCounter`類別,但執行三次`UnitTest`方法 117 | 118 | ```C# 119 | class Program 120 | { 121 | static void Main(string[] args) 122 | { 123 | UnitCounter unitMock = new UnitCounter(); 124 | unitMock.UnitTest(); 125 | unitMock.UnitTest(); 126 | unitMock.UnitTest(); 127 | 128 | Console.ReadKey(); 129 | } 130 | } 131 | ``` 132 | 133 | 執行結果如下圖: 134 | 135 | ![img](../img/TemplateMethod/TemplateMethod.PNG) 136 | 137 | 雖然執行3次 `UnitTest` 方法 但 `ClassCounter` 值卻一直是1而 `MethodCounter` 會依照執行幾次就加幾次. 138 | 139 | ------ 140 | 141 | # 小結: 142 | 143 | 日後測試程式只需關注我們需要如何實現邏輯細解(重寫三個方法),核心流程順序就交由`UnitFlowBase`決定。 144 | -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/TemplatePattern.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {10392CBE-21FF-45DA-A1B1-5F71E356740F} 8 | Exe 9 | Properties 10 | TemplatePattern 11 | TemplatePattern 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 57 | -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/UnitCounter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TemplatePattern 4 | { 5 | public class UnitCounter : UnitFlowBase 6 | { 7 | protected override void SetUp() 8 | { 9 | Console.WriteLine("Set up UnitCounter thing."); 10 | } 11 | 12 | protected override void OneTimeSetUp() 13 | { 14 | Console.WriteLine("OneTimeSetUp!!"); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /DesignPattern/TemplatePattern/UnitFlowBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace TemplatePattern 5 | { 6 | public abstract class UnitFlowBase 7 | { 8 | protected virtual void OneTimeSetUp() 9 | { 10 | } 11 | 12 | protected virtual void Dispose() 13 | { 14 | } 15 | 16 | protected virtual void SetUp() 17 | { 18 | } 19 | 20 | protected virtual void TearDown() 21 | { 22 | } 23 | 24 | public void UnitTest(IEnumerable> testCases) 25 | { 26 | OneTimeSetUp(); 27 | foreach (var testCase in testCases) 28 | { 29 | SetUp(); 30 | Console.WriteLine(testCase() ? "Assert Successful." : "Assert Fail."); 31 | TearDown(); 32 | } 33 | Dispose(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /DesignPattern/img/Adpter/Adaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Adpter/Adaper.jpg -------------------------------------------------------------------------------- /DesignPattern/img/Adpter/Plugin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Adpter/Plugin.jpg -------------------------------------------------------------------------------- /DesignPattern/img/Bridge/BridgePattern1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Bridge/BridgePattern1.PNG -------------------------------------------------------------------------------- /DesignPattern/img/Bridge/brigdeUML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Bridge/brigdeUML.png -------------------------------------------------------------------------------- /DesignPattern/img/Decorator/0c8920b50c8eea2da95c25a033f19872.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Decorator/0c8920b50c8eea2da95c25a033f19872.jpg -------------------------------------------------------------------------------- /DesignPattern/img/Decorator/688215012311271.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Decorator/688215012311271.jpg -------------------------------------------------------------------------------- /DesignPattern/img/Decorator/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Decorator/Thumbs.db -------------------------------------------------------------------------------- /DesignPattern/img/Decorator/decorator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Decorator/decorator.png -------------------------------------------------------------------------------- /DesignPattern/img/Status/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/Status/1.png -------------------------------------------------------------------------------- /DesignPattern/img/TemplateMethod/TemplateMethod.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/TemplateMethod/TemplateMethod.PNG -------------------------------------------------------------------------------- /DesignPattern/img/simpleFactory/simpleFatory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isdaniel/DesignPattern/55a6ddbaf221cb55cce9f9e27d61164264831bc3/DesignPattern/img/simpleFactory/simpleFatory.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SHIH,BING-SIOU 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 | 2 | # **目錄:** 3 | 4 | * [裝飾者模式(DecoratePattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/DecoratePattern) 5 | 6 | * [簡單工廠模式(SimpleFactoryPattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/SimpleFactory) 7 | 8 | * [轉接器模式(AdapterPattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/AdpterPattern) 9 | 10 | * [中介者模式(MediatorPattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/MediatorPattern) 11 | 12 | * [狀態者模式(State Pattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/StatePattern) 13 | 14 | * [樣板模式(TemplatePattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/TemplatePattern) 15 | 16 | * [代理模式(ProxyPattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/ProxyPattern) 17 | 18 | * [橋接模式(BridgePattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/BridgePattern) 19 | 20 | * [Null Object Pattern)](https://github.com/isdaniel/DesignPattern/tree/master/DesignPattern/NullObjectPattern) --------------------------------------------------------------------------------