├── .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 | 
10 |
11 | (圖片來源:網路截圖)
12 |
13 | 所幸導遊有給我們插頭的轉接器,讓我們用可以幫我解決
14 |
15 | 
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 | 
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 | 
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 | 
33 |
34 | > 將物件有效的往上附加職責,不動到內部的程式碼, 在原來職責上附加額外的職責
35 |
36 | 裝飾者模式運作就像 俄羅斯娃娃一樣 一層包一層
37 |
38 | 
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 | 
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 | 
10 |
11 |
12 | 如果有一個人或組織負責幫大家協助溝通,就可解決上面複雜問題
13 |
14 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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)
--------------------------------------------------------------------------------