SOLID原則:依賴反轉原則(Dependency Inversion Principle)
依賴反轉原則類別之間的依賴盡量以Interface的方式進行溝通,應該減少類別的直接依賴。這樣可以減少修改幅度。依賴反轉原則(Dependency inversionprinciple,DIP)是指一種特定的解耦(傳統的依賴關係建立在高層次上,而具體的策略設定則應用在低層次的模組上)形式,使得高層次的模組不依賴於低層次的模組的實現細節,依賴關係被顛倒(反轉),從而使得低層次模組依賴於高層次模組的需求抽象。
該原則規定:
高層次的模組不應該依賴於低層次的模組,兩者都應該依賴於抽象介面。
抽象介面不應該依賴於具體實現。而具體實現則應該依賴於抽象介面。
穩定的介面介面的改變會影響到實作,反之,對於修改實作不一定會去修改介面。甚至都不要去修改介面,因此介面比實作穩定。
舉例如下:
1234567891011121314151617181920public class OrderService{ private OrderRepository _orderRepository; public OrderService() { _ ...
SOLID原則:介面隔離原則(Interface Segregation Principle)
介面隔離原則介面隔離原則是這樣被描述的:
不應該強制客戶端依賴於它們不用的介面
介面隔離原則主要解決介面過於擁擠的問題。建立介面保持簡潔、最低限度的功能。
舉掃描介面來說:
IScan.cs
12345678public interface IScan{ void Scan(); void SendEmail();}
IScan介面可以分離成兩個類別:
IScan.cs
1234public interface IScan{ void Scan();}
IEmailClient.cs
1234public interface IEmailClient{ void SendEmail();}
客戶端程式需要掃描功能只需要依賴IScan.cs裡面的Scan方法,不應該也依賴SendEmail方法。
總結在類別層次上,符合介面隔離原則的設計需要將介面拆分成多個小型的、具體的介面,每個介面只提供一個特定的功能,並且避免將不相關的方法放在同一個介面中。這樣可以讓客戶端程式碼只依賴於需要的介面 ...
SOLID原則:里氏替換原則(Liskov Substitution Principle)
里氏替換原則里式替換原則描述:
子類別應該可以替換父類並且行為不會受到影響。
在原本的里式替換原則之中,如果子類別無法替換父類別,就會出現程式上的錯誤。子類別必須完全替代父類別,並不會影響原有的程式邏輯。里氏替換原則適用於繼承和介面的應用,藉此實現程式碼的可擴展性和重用性。
最常見的例子是長方形與正方形:
Rectangle.cs
12345678910111213141516171819public class Rectangle{ public int Width { get; set; } public int Height { get; set; } public Rectangle(int width, int height) { Width = width; Height = height; } public int CalculateArea() { return Width * Height; ...
SOLID原則:開放封閉原則(Open Close Principle)
開放封閉原則開放封閉原則在 Clean Architecture 一書中是這樣被敘述的
一個軟體製品應該對於擴充是開放的,但對於修改是封閉的。
一個簡單的擴充需求,對於軟體開發上是巨大的改變。這是軟體架構的失敗。一個好的軟體架構可以將修改的程式碼減少到最低程度。在理想情形下這個值是0。
擴展系統功能比較好的方式應該是新增程式碼,並不是去修改既有的程式碼來擴充系統功能。因為修改一個行之有年的系統內部邏輯,可能會發生改A 壞 B ,如果有自動化測試來驗證既有的程式碼可以在第一時間找出來。但是在實務上有自動化測試專案真的是少之又少(ps.可能祖上積德才會遇到吧…),如果當初在設計系統的時候能避免的這種改 A 壞 B的情形,那軟體系統將更容易修改需求及擴充功能。舉例來說,這是一個手機介面。
1234567891011public interface IMobilePhone{ void TurnOn(); void TurnOff(); void Call(string phoneNumber);}
接下來,我們可以定義不 ...
SOLID原則:單一職責原則(Single Responsibility Principle)
單一職責原則(Single Responsibility Principle)
一個模組應該只對唯一的一個角色負責
一個類別或模塊只應該負責一個功能或職責。這個原則有助於降低代碼的複雜度,使代碼更容易維護和擴展。這避免了一個類別出現了上帝類別(GodClass)。
舉例來說,這是一個員工類別。
12345678910111213141516171819202122232425262728293031323334353637public class Employee{ public int Id { get; set; } public string Name { get; set; } public decimal Salary { get; set; } public decimal CommissionRate { get; set; } public decimal BonusRate { get; set; } public v ...
更高效 Logging - LoggerMessage
Logging - LoggerMessage原先在記錄Log都會使用微軟提供LoggingExtensions方法,最近朋友聊天分享給我LoggerMessage.cs與LoggerMessageAttribute.cs。於是研究一下並記錄一下。
這方式把寫Log的方式更好的管理及使用強型別方式。
下面提供兩種方式去改寫 Logging 也可以提升效能,官方文件提到以下原因。
相較於記錄器擴充方法,LoggerMessage 提供下列效能優勢:記錄器擴充方法需要 “boxing” (轉換) 實值型別,例如將 int 轉換為 object。 LoggerMessage 模式可使用靜態 Action欄位和擴充方法搭配強型別參數來避免 boxing。記錄器擴充方法在每次寫入記錄訊息時,都必須剖析訊息範本 (具名格式字串)。 LoggerMessage 只需在定義訊息時剖析範本一次。
這是原本使用 LoggingExtensions.cs去寫 Logging,這邊要注意的是 EventId 是自定的數字。
1234567891011 [HttpGet(Name = "Ge ...
MockServer 整合測試
Mock Server由於要針對API 服務進行壓力測試,並假設其他服務有回應延遲,需要使用一套簡單使用的MockServer,原本想使用Postman,但礙於環境限制,於是找一套可以運行在Docker上的MockServer。如圖這是運行之後的視窗。
Docker Install首先執行 Docker 指令下載 Docker Image,並執行。
1docker run -d --name mockserver -p 1080:1080 mockserver/mockserver
MockServer UIGET http://localhost:1080/mockserver/dashboard,在瀏覽器輸入這個網址便能看到 MockServer 的畫面。
從這邊可以看到以下的畫面。
Create or Update Expectation12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 ...
關於 HttpClient 使用方式
關於 HttpClient因為許多企業大量採用微服務,導致使用 HTTP 連線非常頻繁。在CSharp中最常使用的類別庫就是HttpClient.cs,但是HttpClient.cs使用方式也是需要注意,一不小心就會造成Connection資源耗盡的問題。
官方不建議使用方式
直接使用using HttpClient123456789101112131415161718192021222324252627static async Task Main(){ var url = "http://localhost:5259/WeatherForecast"; int requestCount = 10000; // 設定請求的次數 for (int i = 0; i < requestCount; i++) { using (var client = new HttpClient()) { try { var response = await client.GetAsync(url); ...
Dependency Injection (二) Mircosoft.Extensions.DependencyInjection 介紹
Microsoft.Extensions.DependencyInjection在ASP.NET Core中,Dependency Injection Container 是一個核心功能,用於管理應用程序中的依賴關係。ASP.NET Core 的Dependency Injection Container系統提供了一個建立基於依賴注入的應用程序的機制,並支持以下功能:
提供應用程序組件之間的依賴注入。
可以在Controller、Filter、View等多個組件中使用。
提供了生命週期管理功能,可以在需要時建立、和釋放物件。
支持對服務的多個實現進行注入,並可根據需要在運行時選擇實現。
.NetCore DI 預設只支援建構子注入,但是Middleware支援方法注入。
IServiceCollection 是什麼?當查詢原始碼時,會看到下列的介面
12345public interface IServiceCollection : IList<ServiceDescriptor>{}
ServiceDescriptor.cs
...
Dependency Injection (一) 簡介
簡介
Dependency Injection (DI) 是一種設計模式,用於降低物件之間的耦合度,從而提高代碼的可重用性、可測試性和可維護性。在DependencyInjection中,物件之間的依賴關係不由物件本身建立,而是由Dependency Injection 容器負責建立。
What is Dependency ?程式上的依賴是指一個物件對象需要另一個Assembly或Class,才能完成自己的功能。具體來說,當一個物件對象使用了另一個Assembly或Class的功能時,就可以說這個組件或對象對另一個Assembly或Class存在依賴關係。
在這範例中可以說OrderController.cs依賴了OrderDataAccess.cs,OrderController.cs必須透過OrderDataAccess.cs才能完成取得所有訂單清單功能。
12345678910111213141516171819[ApiController][Route("api/[controller]")]public class OrderControlle ...
