Brian的雜記
  • Introduction
  • Brian's 雜記
    • My Awesome API
    • FB 大頭貼
    • 硬體雜記
    • PHP
    • project
      • 模擬器
      • WAMP
    • WinMerge
    • 雜記
      • LINQ
      • 方法
      • Grid View
      • namespace
      • global
      • 物件導向
      • Excel
      • VS2017
      • single sign on
      • Master
      • Https
      • 憑證
      • 略過憑證不符
      • NLog
      • 團隊開發
      • .NET Core
      • 共用網路上的芳鄰
      • 爬蟲
      • NPOI
      • RSS
      • 多執行緒
      • 記憶體回收
      • 密碼學
        • BCrypt
        • AES
      • 主機環境建置
      • Session
      • Error
      • IIS 相關
      • 無障礙相關
      • 介面
        • 影像地圖
      • telnet
        • smtp
      • nslookup
      • 協助客戶解決問題
      • 驗證欄位
      • 網站管理
      • 工具整理
    • 正規表示法
    • 影像處理
    • IntelliJ Idea
    • 觀念
      • Clean Code
        • 命名
        • 函式
        • 註解
        • 編排
        • 物件及資料結構
        • 錯誤處理
        • 邊界
        • 單元測試
        • 類別
      • Java 程式風格
      • Design Pattern
        • 單例模式
      • 同步
      • 畫圖
        • ER-Model
        • 類別圖
        • Use Case
        • 有限狀態機
      • 資料 API 文件 分析
      • CORS & SSL
      • 利用DISC幫助溝通
      • OAS
    • 檔案上傳
      • FileStore
      • App Engine
      • Google Storage
    • OAuth vs Open ID
    • MIME
    • 虛擬桌面
    • 待看資料
    • Selenium
    • CDN
    • HTTP
    • 編碼
    • 2nd-ML100Days
      • jupyter
    • 微服務
      • 設計
        • 1 ~ 5
        • 6
        • 7
        • 8
        • 9
    • Gradle
    • Maven
    • Error
    • 批次檔 BAT
    • Kurento
    • WebSocket & WebRTC
  • 需求面能力
    • User Story
  • Google Cloud Platform
    • Compute Engine
  • Python
    • 基本語法
    • Pandas
    • 套件
    • Matplotlib
    • Encoder
    • jupyter
  • Java
    • Java
      • File
      • Exception
      • 物件導向觀念
      • 加密
      • HTTP
      • 集合
      • Stream()
      • Web
      • ResultSet
      • JDK6
      • JDK8
    • 讀取、複寫MP3 Tag
    • Log4j2
    • Servlet
      • 容器
    • JSP
    • JBOSS
    • JWT
    • PreparedStatement
    • Error
    • Spring
      • Spring Boot
        • @Value
        • Build
      • RequestParameter
      • Error
      • Autowired
      • JPA
      • FeignClient
      • WebSocket
      • thymeleaf
      • Security
      • Test
      • Scheduled
      • Redirect
    • IntelliJ
  • Linux
    • Linux
    • Shell Script
    • Cygwin(在Windows執行Linux指令)
  • 前端
    • HTML
      • Link
    • CSS
      • Position
      • padding color
      • display
    • JS
      • jQuery
        • Select2
      • fancybox
      • ES6
      • 效能
      • GoogleMap API
        • Marker
        • InfoWindow
      • 事件
      • CKEditor
      • TGOS
      • JSON
      • QRcode
      • 核心概念
        • 物件 變數 型別
          • number
          • String
          • boolean
          • null & undefined
          • Symbol
        • JS 物件概念
        • 深入理解JS 函式物件
        • 更多ES2015/ES6 全新語言特性
      • Promise
    • 效果應用
  • 資料庫
    • 注意事項
    • MariaDB
    • MySQL
      • inner join 和 join
      • 字串比對
      • 倒數資料
    • SQL
      • DDL 資料定義語言
      • DML 資料操縱語言
      • DCL 資料控制語言
      • TCL 交易控制語言
      • T-SQL
      • CTE
      • JOIN
    • Oracle
    • MSSQL 操作
      • 新增使用者
      • SQL 指令
      • Sequence
    • 差異比較
    • MyBatis
    • Workbench 操作
    • SQL Injection
  • 版本控制
    • Gitlab
      • sign up
      • sign in
      • add project
      • add members
    • SourceGit
      • install
    • SmartGit
      • install
      • operate
      • git 操作雜記
    • TortoiseGit
    • Git
    • TFS
    • SVN
  • Test
    • 軟體測試原則
    • 演算法
    • XMind
      • install
    • Jenkins
      • 建置
    • HTTPie
    • Postman
    • 測試驅動開發
    • 撰寫測試的觀念
    • 測試框架
    • IoC & DI
    • 隔絕相依性的方式
    • JUnit
    • NUnit
    • 習慣
    • 虛設常式
  • Angular
    • hello world
    • ng-options
    • ES6
    • Build & Conponect
    • HttpClient
    • 部署
  • ASP.NET Web Form
    • Chapter 2
      • 2-1
        • 小東西
    • 略過請求驗證
  • Go
Powered by GitBook
On this page
  • 建構式(constructor)
  • 好處:
  • 顧慮點:
  • 公開屬性(public setter property)
  • 好處:
  • 顧慮點:
  • 呼叫方法時傳入參數(function parameter)
  • 好處:
  • 顧慮點:
  • 可覆寫的保護方法(protected virtual function)
  • 好處:
  • 顧慮點:

Was this helpful?

  1. Test

隔絕相依性的方式

PreviousIoC & DINextJUnit

Last updated 4 years ago

Was this helpful?

參考資料:()

建構式(constructor)

將物件相依的介面,拉到建構式供外部物件使用,可自行組合目標物件的相依實體。屬性為private。

好處:

有許多現成套件、框架可以用。

有許多DI framework 支援 Autowiring.

Autowiring is an automatic detection of dependency injection points.

這邊的 dependency injection points 在這例子,指的就是建構式。

由建構式傳入相依介面的實體物件,是一個很通用的方式。因此在結合許多常見的 DI framework,不需要再額外處理。

(以 Unity 為例,在 UnityContainer 取得目標物件時,會自動尋找目標物件參數最多的建構式。並針對每一個參數的型別,繼續在 UnityContainer 中尋找對應的實體物件,直到目標物件組合完畢,回傳一個完整的目標物件。)

顧慮點:

物件太多、參數不同 容易搞混,若方法中沒有防呆,容易出現錯誤。

當物件越來越複雜時,建構式也會趨於複雜。倘若沒有 DI framework 的輔助,則使用物件上,面對許多 overload 的建構式,或是一個建構式參數有好幾個,會造成使用目標物件上的困難與疑惑。若沒有好好進行 refactoring,也可能因此而埋藏許多 bad smell。

另外,倘若是許多建構式,也可能造成要呼叫 A 方法時,應選用 A 對應的建構式,但在使用物件上,可能會用錯建構式而不自知,若方法中沒有正確的防呆,則可能出現錯誤。(請搭配單元測試的測試案例來輔助)

最後,與原本直接相依的程式碼相比較,目標物件的相依物件因此暴露出來,交由外部決定,而喪失了一點封裝的意味。而使用端也不一定知道,要取用此物件時,應該要注入哪些相依物件。(請使用 Repository Pattern 或 DI framework 來輔助)

公開屬性(public setter property)

一樣用 interface當型別,setter 設 public,getter 設 private。

其實公開屬性與公開建構式非常類似,透過 public 的 property(property 型別仍為 interface),讓外部在使用目標物件時,可先 setting 目標物件的相依物件,接著才呼叫其方法。

而公開屬性通常只會將 setter 公開給外部設定,getter 則設定為 private。原因很簡單,外部只需設定,而不需取用。就像公開建構式,在使用物件之前先傳入初始化物件必備的資訊,但目標物件可能將這些資訊,存放在 private 的 filed 或 property 中,而不需再提供給外部使用。

好處:

也有許多DI framework,不需要改建構式。

同樣的,public property 也是常見的 dependency injection points,所以也有許多 DI framework 支援。另外則是不需要對建構式進行改變,或增加新的建構式。對過去已經存在的 legacy code 的影響,會比建構式的方式小一點點(但幾乎沒有太大差異)。

顧慮點:

使用前應檢查該屬性是否為null,並進行 error handing,避免發生錯誤仍執行不應執行的程式碼。

最常見的情況,就是使用目標物件時,相依介面應有其對應執行個體,但卻因為使用端沒有設定 public property,導致使用方法時出現 NullReferenceException,這種情況也怪不了使用端,因為使用端極有可能本就不瞭解這個方法中,有哪些相依物件。

解決方式與建構式的建議雷同,首先當然要有測試程式來說明(測試程式就是物件使用說明書),另外取得目標物件,仍可透過 Repository Pattern,讓使用端無須瞭解目標物件的相依關係。

並且在方法中使用相依介面前,應檢查其是否為 null,若為 null,則代表參數設定錯誤,進行 error handling,避免已經發生錯誤仍執行許多不應執行的程式碼。或是在 property 的 getter 時,檢查是否為 null 或當為 null 時,給予一預設值,以避免方法無法正常執行。(視實際需求而定)

另外,公開屬性的方式,也如同公開建構式一般,破壞了一點點物件封裝的用意。但這兩者,都是 IoC 設計會帶來的影響。

呼叫方法時傳入參數(function parameter)

將方法相依的物件丟到參數,相對其他方法 不容易出錯。

既然前面兩種方式,都可能造成使用方法時,可能沒有設定好相依介面的執行個體,導致發生錯誤。或是使用目標物件時,不知道該呼叫哪一個建構式或初始化哪些屬性。那很簡單的方式,就是把方法相依介面的部分,拉到方法的參數上。方法中,需要使用到哪些介面,強迫由呼叫端必須給定參數。目標物件的方法內容則僅相依於參數上的介面。

好處:

不必再擔心要先初始化哪些 property,或呼叫哪一個建構式。當要呼叫某一個方法,其相依的物件,就是得透過參數來給定。基本上也不太需要擔心使用上造成困擾或迷惑。

顧慮點:

方法簽章不穩定,當需求異動時,影響範圍較大,DI framework支援較低。適合用在非常明確、穩固的方法,避免前面提到的問題。但這個方式可以與其他方式,可以衡量狀況適度使用。

最大的問題,在於方法簽章上的不穩定性。當需求異動,該方法需要額外相依於其他物件時,方法簽章可能會被迫改變。而方法簽章是物件導向設計上,最需要穩定的條件之一。以物件導向、介面導向設計來說,當多型物件方法簽章不一致時,向來是個大問題。

另外,方法的參數過多,在使用上也會造成困擾。而且會影響到 legacy code 的呼叫端,需要全面跟著異動,才能編譯成功。

而且透過參數的方式,DI framework 支援度較低。

但這不代表,就不能在方法參數中,傳入相依物件。在 .net framework 還是有許多這樣的設計,例如:List.Sort 方法 (IComparer)。這樣的設計方式,通常要確保該方法相依相當明確、穩固,避免上述問題。

by the way, 這個方式是可以與其他方式共存的,所以在設計物件時,可衡量搭配使用。

可覆寫的保護方法(protected virtual function)

利用 protected virtual 去繼承欲測試的類別

好處:

這個方式最大的好處,是完全不影響外部使用物件的方式。僅透過 protected 與 virtual 來對繼承鏈開放擴充的功能,並且透過這樣的方式,就使得原本直接相依而導致無法測試的問題,獲得解套。

顧慮點:

這是為了測試,且面對 legacy code 所使用的方式,而不是良好的物件導向設計的方式。IoC 的用意在於介面導向與擴充點的彈性,所以當可測試之後,倘若重構影響範圍不大,建議讀者朋友還是要將物件改相依於介面,透過 IoC 的方式來設計物件。

by the way, 同樣為了解決直接相依物件,甚至相依於 static 方法、.net framework 本身的物件(如 DateTime.Now)而導致無法測試的問題,還有另外一個方式,稱為 fake object。這在後面的文章,會再進行較為詳盡的介紹。

https://dotblogs.com.tw/hatelove/archive/2012/11/27/learning-tdd-in-30-days-day6-several-ways-to-isolate-object-dependency-and-easy-for-testing.aspx