Single responsibility là gì

Single responsibility Principle (SRP) được đưa ra bởi Robert Martin như sau:

A class or module should have one, and only one, reason to be changed

Mỗi module hoặc class, function chỉ có một lý do để thay đổi. Hay nói cách khác, chúng chỉ thực hiện một nhiệm vụ.

Nghe có vẻ dễ hiểu phải không ? Tuy nhiên Single Responsibility Principle là nguyên tắc dễ bị vi phạm nhất bởi cả các lập trình viên giàu kinh nghiệm.

Để hiểu rõ hơn về SRP, ta có thể xét một ví dụ sau.

Ví dụ 1:

Ta có một module Report thực hiện hai nhiệm vụ, đọc dữ liệu và hiển thị report.

Một module thực hiện hai nhiệm vụ

Một module thực hiện hai nhiệm vụ

Khi khách hàng muốn thay đổi nội dung và cách thức hiển thị report thì bạn sẽ thấy module này sẽ bị thay đổi bởi hai lý do. Vì thế nó vi phạm nguyên tắc Single Responsibility.

SRP cho ta biết, đây là hai vấn đề riêng biệt. Do vậy chúng nên được tách thành 2 phần khác nhau. Đó là ReportContent sẽ thực hiện chức năng lấy dữ liệu, và ReportViewer sẽ thực hiện chức năng hiển thị dữ liệu.

Bạn có thể thấy điều này trong mô hình MVC. Model sẽ đọc dữ liệu, View sẽ hiển thị dữ liệu từ Model.

Ví dụ 2:

class Customer
{
   public void Add()
   {
       try
       {
           //Database code goes here 
       }
       catch (Exception ex)
       {
           System.IO.File.WriteAllText(@"c:\Error.txt", ex.ToString());
       }
   }
}

Hàm này đang thực hiện một lúc hai việc, do đó nó vi phạm nguyên tắc Single responsibility.Lớp Customer có hàm Add() thực hiện việc thêm customer vào database. Tuy nhiên trong câu lệnh catch, ta có thể thấy nó thực hiện cả việc lưu exception vào file txt.

Nó vẫn chạy đúng, vậy vấn đề là gì?

Hàm này khi chạy vẫn cho ra kết quả chính xác, tuy nhiên khi muốn thay đổi cách ghi log, save vào database thay vì save vào file txt, bạn phải làm như thế nào? Tìm lại tất cả catch block và sửa? Như vậy vừa tốn thời gian, vừa dễ gây ra bug.

Giải quyết vấn đề!

Để thực hiện nguyên tắc Single responsibility, bạn phải tạo một lớp Logger chuyên dành cho việc ghi log. Như vậy, khi thay đổi hệ thống ghi log bạn chỉ việc thay đổi một lần ở lớp Logger, vừa tiện, vừa dễ bảo trì.

class FileLogger
{
   public void Handle(string error)
   {
       System.IO.File.WriteAllText(@"c:\Error.txt", error);
   }
}
class Customer
{
   private FileLogger logger = new FileLogger();
   public virtual void Add()
   {
       try
       {
           // Database code goes here
       }
       catch (Exception ex)
       {
           logger.Handle(ex.ToString());
       }
   }
}

Khi bắt tay vào viết một lớp hoặc một hàm, hãy suy nghĩ thấu đáo, liệu hàm này lớp này chỉ có một chức năng hay không?

Ích lợi của Single Responsibility

Các class, các function sẽ dễ hiểu hơn.
Khi các class, các function chỉ thực hiện một nhiệm vụ, việc đọc code sẽ trở nên dễ dàng hơn.

Bảo trì dễ dàng hơn.

Khi có sự thay đổi, ban chỉ cần thay đổi tại một nơi, không còn lo lắng quá nhiều đền các nơi khác.

Dễ tái sử dụng:

Nếu các class, module thực hiện đa chức năng, thì việc tái sử dụng chúng sẽ trở nên khó khăn hơn nhiều vì ta phải quan tâm đến nhiều biến số đầu vào.

Tôi nhấn mạnh lại, Single Responsibility là nguyên tắc rất dễ bị vi phạm. Do vậy hãy suy nghĩ thật kỹ trước khi viết hàm. Dần dần bạn sẽ tạo thói quen viết ra được các code sạch (clean code)

Source code:

https://github.com/mt26691/learning-solid/blob/master/SOLID/SOLID.SingleResponsibility/Program.cs

Các môn học khác

Khóa học này cung cấp cho ta kiến thức nền tảng về công nghệ Blockchain, Bitcoin. Vì sao nó được gọi là công nghệ của tương lai, vì sao giá Bitcoin lại cao đến vậy. Làm sao để mua Bitcoin, ETH.

SQL là ngôn ngữ truy vấn mang tính cấu trúc, nó cho phép bạn truy cập và sử dụng database.

Khoa học về dinh dưỡng, giáo trình giảm cân cho mọi người.