1. Trang chủ
  2. » Công Nghệ Thông Tin

Nguyên tắc solid c

17 0 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Nguyên tắc SOLID và ví dụ trong C# Giới thiệu Nếu bạn tìm kiếm Google với từ khóa ‘SOLID’, bạn sẽ thấy hàng tấn kết quả cả bài viết, video hay hướng dẫn về vấn đề này Vậy nên mục đích của bài viết này[.]

Nguyên tắc SOLID ví dụ C# Giới thiệu Nếu bạn tìm kiếm Google với từ khóa ‘SOLID’, bạn thấy hàng kết viết, video hay hướng dẫn vấn đề Vậy nên mục đích viết hướng dẫn cách đơn giản đưa ví dụ đơn giản hiệu Các ví dụ viết C# Nhưng bạn đừng lo, ngơn ngữ đại có cách viết gần tương tự Tổng quan SOLID SOLID nguyên tắc bản, giúp xây dựng kiến trúc phần mềm tốt Bạn thấy tất design pattern dựa nguyên tắc SOLID ghép lại từ chữ viết tắt nguyên tắc này: S is single responsibility principle (SRP) O stands for open closed principle (OCP) L Liskov substitution principle (LSP) I interface segregation principle (ISP) D Dependency injection principle (DIP) Single responsibility principle (SRP) Mỗi class nên đảm nhận trọng trách, nên có lý để thay đổi Để giải thích kỹ xin lấy ví dụ Bạn có cơng cụ kết hợp nhiều công cụ nhỏ khác dao, cắt móng tay, tuốc nơ vít….Bạn có muốn mua này? Tơi khơng nghĩ muốn mua Bởi có vấn đề với nó, bạn muốn thêm công cụ vào nó, bạn cần phải thay đổi tồn cấu tạo nó, điều khơng ổn Đây kiến trúc tồi với hệ thống Tốt hết bấm móng tay nên sử dụng để bấm móng tay, dao nên sử dụng để thái rau Sau ví dụ cho nguyên tắc này: namespace SRP { public class Employee { public int Employee_Id { get; set; } public string Employee_Name { get; set; } /// /// This method used to insert into employee table /// /// Employee object /// Successfully inserted or not public bool InsertIntoEmployeeTable(Employee em) { // Insert into employee table return true; } /// /// Method to generate report /// /// public void GenerateReport(Employee em) { // Report generation with employee data using crystal report } } } Class ‘Employee’ có trách nhiệm, trách nhiệm thao tác với sở liệu tạo báo cáo Lớp Employee không nên đảm nhận việc tạo báo cáo giả sử đến ngày khách hàng yêu cầu phải tạo báo cáo Excel định dạng khác, class lại phải thay đổi cho phù hợp Điều khơng tốt Vì để tn theo SRP, class nên đảm nhận trách nhiệm, nên viết sang class khác cho việc tạo báo cáo, có thay đổi với việc tạo báo cáo, không ảnh hưởng đến class Employee public class ReportGeneration { /// /// Method to generate report /// /// public void GenerateReport(Employee em) { // Report reneration with employee data } } Open closed principle (OCP) Giờ xem xét class ‘ReportGeneration’ ví dụ cho nguyên tắc thứ Bạn có đốn vấn đề class không? public class ReportGeneration { /// /// Report type /// public string ReportType { get; set; } /// /// Method to generate report /// /// public void GenerateReport(Employee em) { if (ReportType == "CRS") { // Report generation with employee data in Crystal Report } if (ReportType == "PDF") { // Report generation with employee data in PDF } } } Tuyệt!!! Bạn đúng, nhiều mệnh đề IF bạn muốn thêm loại report khác ví dụ Excel, bạn cần viết thêm lần if Class nên khuyến khích mở rộng phải tránh việc chỉnh sửa Làm để làm điều này? public class IReportGeneration { /// /// Method to generate report /// /// public virtual void GenerateReport(Employee em) { // From base } } /// /// Class to generate Crystal report /// public class CrystalReportGeneraion : IReportGeneration { public override void GenerateReport(Employee em) { // Generate crystal report } } /// /// Class to generate PDF report /// public class PDFReportGeneraion : IReportGeneration { public override void GenerateReport(Employee em) { // Generate PDF report } } Nếu bạn muốn đưa định dạng báo cáo khác, bạn cần kế thừa từ interface IReportGeneration Vì IReportGeneration interface nên chưa triển khai chi tiết method, giúp bạn giải việc Liskov substitution principle (LSP) Nguyên tắc đơn giản khó để hiểu Class khơng nên phá vỡ định nghĩa hành vi class cha Điều có nghĩa gì? Chúng ta lại lấy ví dụ với Employee để giúp bạn hiểu nguyên tắc Bạn xem hình bên Employee lớp cha Casual Contractual Hai class kết thừa từ Employee Bạn xem code: public abstract class Employee { public virtual string GetProjectDetails(int employeeId) { return "Base Project"; } public virtual string GetEmployeeDetails(int employeeId) { return "Base Employee"; } } public class CasualEmployee : Employee { public override string GetProjectDetails(int employeeId) { return "Child Project"; } // May be for contractual employee we not need to store the details into database public override string GetEmployeeDetails(int employeeId) { return "Child Employee"; } } public class ContractualEmployee : Employee { public override string GetProjectDetails(int employeeId) { return "Child Project"; } // May be for contractual employee we not need to store the details into datab ase public override string GetEmployeeDetails(int employeeId) { throw new NotImplementedException(); } } Có ổn khơng? Hãy xem đoạn có vi phạm nguyên tắc này: List employeeList = new List(); employeeList.Add(new ContractualEmployee()); employeeList.Add(new CasualEmployee()); foreach (Employee e in employeeList) { e.GetEmployeeDetails(1245); } Giờ Tơi đốn bạn hiểu vấn đề Vâng, với Contractual employee, bạn ăn exception method GetEmployeeDetails(int employeeId) chưa triển khai, điều vày vi phạm LSP Vậy giải pháp gì? Tách chúng thành interface khác Một Iproject, hai Iemployee triển khai theo type khác nhau: public interface IEmployee { string GetEmployeeDetails(int employeeId); } public interface IProject { string GetProjectDetails(int employeeId); } Giờ contractual employee triển khai IEmployee khơng có IProject Điều giúp tuân theo nguyên tắc LSP Interface segregation principle (ISP) Nguyên tắc nói client không nên triển khai interface không phù hợp với Điều có nghĩa, giả sử có CSDL để lưu trữ tất loại nhân viên (cố định, tạm thời), cách tiếp cận tốt gì? public interface IEmployee { bool AddEmployeeDetails(); } Tất class Employee kế thừa từ interface để lưu liệu? Điều ổn không? Bây bạn giả sử công ty nào nói cho bạn họ muốn lấy nhân viên cố định Bạn làm gì? Thêm phương thức vào interface? public interface IEmployeeDatabase { bool AddEmployeeDetails(); bool ShowEmployeeDetails(int employeeId); } Nhưng phá vỡ số thứ Chúng ta tập trung vào class nhân viên không cố định để hiển thị chi tiết họ từ CSDL Vậy giải pháp đưa đưa chúng interface khác public interface IAddOperation { bool AddEmployeeDetails(); } public interface IGetOperation { bool ShowEmployeeDetails(int employeeId); } Và nhân viên không cố định triển khai interface IAddOperation nhân viên cố định triển khai interface Dependency inversion principle (DIP) Nguyên tắc nói cho bạn bạn không nên viết code gắn chặt với ác mộng cho việc bảo trì ứn dụng trở lên lớn dần Nếu class phụ thuộc class khác, bạn cần phải thay đổi class class phụ thuộc phải thay đổi Chúng ta nên cố gắng viết class phụ thuộc Giả sử có hệ thống thơng báo sau lưu vài thông tin vào DB public class Email { public void SendEmail() { // code to send mail } } public class Notification { private Email _email; public Notification() { _email = new Email(); } public void PromotionalNotification() { _email.SendEmail(); } Giờ class Notification hoàn toàn phụ thuộc vào class Email, gửi loại thông báo Nếu bạn muốn thêm cách thông báo SMS chẳng hạn? Chúng ta phải thay đổi hệ thống thơng báo? Đó gọi liên kết chặt (tightly coupled) Bạn làm để giúp giảm phụ thuộc vào OK, bạn xem ví dụ sau đây: public interface IMessenger{ void SendMessage(); } public class Email : IMessenger{ public void SendMessage() { // code to send email } } public class SMS : IMessenger{ public void SendMessage(){ // code to send SMS } } public class Notification{ private IMessenger _iMessenger; public Notification(){ _ iMessenger = new Email(); } public void DoNotify(){ _ iMessenger.SendMessage(); } } Class Notification phụ thuộc vào Email class Nhưng sử dụng depedency Injection để làm cho chúng giảm phụ thuộc Có loại DI, Contructor Injection, Property Injection Method Injection Constructor Injection public class Notification{ private IMessenger _iMessenger; public Notification(Imessenger pMessenger){ _ iMessenger = pMessenger; } public void DoNotify(){ _ iMessenger.SendMessage(); } } Property Injection public class Notification{ private IMessenger _iMessenger; public Notification(){ } public IMessenger MessageService{ private get; set { _ iMessenger = value; } } public void DoNotify(){ _ iMessenger.SendMessage(); } } Method Injection public class Notification{ public void DoNotify(IMessenger pMessenger){ pMessenger.SendMessage(); } } Vậy SOLID giúp viết code độc lập giảm phụ thuộc module, giúp nâng cao hiệu việc bảo trì, tránh nhiều rủi ro Nguồn: https://tedu.com.vn/design-pattern/nguyen-tac-solid-va-vi-du-trong-c49.html

Ngày đăng: 09/04/2023, 06:29

Xem thêm:

w