小朱
C# 深耕系列 (2) – Part 1
 物件導向不是只有封裝、繼承與多型
 SOLID
 DI
 其他你可能聽過的…
大家都知道,但兩個都懂的人卻不
一定寫得出相同結構品質的程式碼。
 高內聚 (High Cohesion)
 低耦合 (Low Couple)
 不重覆程式 (Don’t Repeat Yourself) – DRY
 二進位層次的擴充性
 封裝 (Encapsulation)
◦ 最小知識原則 (Principles of Least Knowledge)。
 繼承 (Inheritance)
◦ 複製被繼承 (父物件) 的行為,達到可重覆使用。
 多型 (Polymorphism)
◦ API 獨立,但實作 API 的物件可隨時抽換。
 將物件的細節包裝起來。
 外面不需要了解它怎麼做,
就能用它開放的方法來得
到預期的結果。
 排序演算法或搜尋演算法。
 集合物件 (Collections)。
 由程式碼層次取得被繼承
(父) 物件的絕大多數能力
或特徵。
 繼承 (子) 物件可視需求重
寫以變更原本的行為。
 Stream 物件。
 對外界而言介面相同,但是外
界呼叫介面時,其反應由實作
該介面的物件決定。
 抽象化的重要概念。
 雜湊演算法、加解密演算法。
 多型是 Design Patterns 的基
石。
看起來很好啊,
有什麼問題嗎?
物件導向的使用不難,但怎麼用對,
其實比你想像中難。
 一個類別應有一個,也有一個修改它的理由。
 職責劃分。
 也可應用於屬性與方法的設計。
+ CalcPay
+ ReportHours
+ WriteEmployee
EmployeePayroll
+ CalcPay
Employee
Payroll
Report
Writer
Employee
Repository
 軟體的實體應該對擴充開放,但對修改封閉。
 擴充是添加新程式,而非修改舊程式。
 抽象化程度的考驗。
 API 的穩定度。
Client Server
Client
Abstract
Server
Concrete
Server
 子類別與必須能夠平順無問題的以父類別替代。
 外界不應該也不需要知道兩者的差異。
 抽象類別與介面的使用。
 不可以違反開放封閉原則。
◦ 程式內不能以判斷型別的方式決定父或子類別。
Square
Rectangle
+SetHeight()
+SetWidth()
-height : real
-width : real
 用戶端不應該直接相依於它不會用到的介面。
Client 3Client 2Client 1
Server
+ C1Function()
+ C2Function()
+ C3Function()
Client 3Client 2Client 1
Client 3InterfaceClient 2InterfaceClient 1Interface
«interface» «interface»«interface»
Server
+ C1Function()
+ C2Function()
+ C3Function
+ C1Function() + C2Function() + C3Function()
 高階模組不應相依於低階的模組,兩者應同時相依
於抽象。
 抽象不應相依於細節,細節應該相依於抽象。
 多型的基石,Design Patterns 的入門磚。
Copy
Reader Writer
KeyboardReader PrinterWriter
ReadKeyboard
Copy
WritePRinter
V.
你知道用程式碼擴充,但未來的世
界是二進位擴充。
(其實現在已經是了…)
 服務指的是提供特定功能的軟體元件 (software
component)。
 特定功能的規格由介面定義。
 物件可使用不同的服務聚合 (composite),來擴充
自己的功能。
 現代軟體架構上多採用這種作法。
 在執行期 (runtime) 以二進位執行碼的方式,於物
件需要時將服務 (service) 注射 (injection) 到物件
內,讓物件能存取其功能。
 幫助你落實 DIP 原則的重要工具。
 DI 的核心元件,負責管理物件
的生成與生命週期。
1. 服務向 DI 容器註冊可用的服務
(介面) 及其對應的實作。
2. 物件向 DI 容器 “要求” 服務。
3. DI 容器生成服務或回傳現有服務
給物件。
4. DI 容器會處理生命週期的工作。
 建構式注入 (Constructor Injection)
 屬性注入 (Property Injection)
 介面注入 (Interface Injection)
 使用介面內宣告服務的方式來注入。
 通常是用於建立 contract,要求物件一定要使用特
定服務。
 實際運作多半還是採用建構式注入或屬性注入法。
 類似於 DI 的作法,但它不
會管理物件的生命週期,
而是將物件的要求丟給已
存在的服務個體。
 適用於網路上的服務 (ex:
WCF)
 Autofac
 StructureMap
 Castle Windsor
 Unity
 Ninject
 Spring.NET
如果你想DIY的話… 
Building an IoC container in 15
lines of code
 SOLID 是物件導向必須內化的重要心法。
◦ 有了它才寫得出夠 qualify 的程式碼。
◦ 減少被 WTF 的次數 
 DI 是發展現代化軟體架構與框架的核心概念。
◦ ASP.NET Core, Xamarin 都用它了。
◦ 別再逃避它了 
 https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
 https://en.wikipedia.org/wiki/Dependency_injection
 http://martinfowler.com/articles/injection.html
 Book: 軟體構築美學 (Brownfield Application Development in .NET)
 Book: 敏捷軟體開發:原則、樣式及實務 (Agile Software Development: Principles,
Patterns, and Practices)
 Book: 重構-改善既有程式的設計 (Refactoring: Improving the design of existing code)
 eBook: .NET相依性注入 (https://leanpub.com/dinet)
物件導向設計原則:SOLID + DI

物件導向設計原則:SOLID + DI