Single Responsibility Principle là một trong các khái niệm cốt lỗi vận dụng module hoá trong lập trình hướng đối tượng.
Phát biểu: Mỗi lớp chỉ nên chịu trách nhiệm về một nhiệm vụ cụ thể nào đó.
Giả sử chúng ta có một class đại diện cho con dao như hình trên. Vì nó có nhiều lưỡi dao nên có thể dùng trong nhiều tình huống khác nhau, rất thuận tiện. Thế nhưng khi một lưỡi dao trong nó bị hư thì bắt buộc phải tháo hết các lưỡi dao còn lại ra chỉ để sữa cái bị hư. Như vậy có khả năng sau khi chúng ta sữa xong cái bị hư thì sẽ ảnh hưởng đến những cái khác. Kiểu các dev hay nói fix bug này lòi bug kia ấy =).
Vậy nếu một class có quá nhiều chức năng thì nó sẽ trở nên cồng kềnh và phức tạp. Việc sửa đổi chúng là cực kỳ khó khăn và tốn nhiều thời gian mà đôi khi còn gây ra nhiều bug hơn sau khi fix bug. Mà các bạn cũng biết rồi đấy, trong quá trình xây dựng ứng dụng thì việc thay đổi yêu cầu là cực kỳ nhiều, nếu các bạn thiết kế không tốt thì sẽ gây khó khăn trong việc sữa đổi code và có khi phải đâp xây lại nữa.
Áp dụng Single responsibility
Áp dụng single responsibility thì chúng ta sẽ tách con dao trên thành nhiều con thứ khác nhau như là kéo, dao, mở nút chai etc. Cái nào hư thì sữa cái đó không cần phải tháo cả đám ra để sữa. Để làm được vậy chúng ta cần gom nhóm các chức năng và chia thành từng module khác nhau, mỗi module chỉ có một tính năng duy nhất.
Ví dụ cho đoạn code sau
public class UserService { public void registerUser() { createUser(); sendEmail(); } private void createUser(){ // Write code at here } private void sendEmail() { // Write code at here } }
Mình có một class UserService, có hàm registerUser() trong này đơn giản là mình khởi tạo một user sau đó gửi email confirm là xong. Nếu application của bạn chỉ làm như vậy thì đến đây nó vẫn là một good design.
Sau đó một thời gian, ứng dụng của bạn mở rộng, lúc đó chẳng hạn như AdminService cũng cần gửi mail, ReportService cũng cần gửi mail… Thì các bạn sẽ phải làm sao ạ? Tất nhiên là mỗi class AdminService, ReportService.. bạn sẽ phải implement lại hàm gửi mail, và lúc này code của bạn sẽ bị dulicate code rất nhiều.
Chưa hết =)) khi bạn cần sữa logic gửi mail đi, thì bạn phải đi từng class AdminService, ReportService.. để sửa. Như vậy nó sẽ làm cho code của bạn rất khó mở rộng và bảo trì.
Bây giờ mình thử apply cái Single responsibility principle vào xem thử nó có giải quyết được gì không ha!!!
public class UserService { private EmailService emailService = new EmailService(); public void registerUser() { createUser(); emailService.sendEmail(); } private void createUser() { // Write code at here } } class EmailService { public void sendEmail() { // Write code at here } }
Bạn thấy thằng EmailService được tách ra để làm riêng một nhiệm vụ gửi mail. UserService chỉ cần sài những method mà EmailService cung cấp. Sau này những class khác AdminService có sài cũng chỉ cần gọi EmailService ra mà dùng thôi. Đên lúc có sửa logic gửi mail thì ta chỉ cần vào đúng class gửi EmailService để sửa mà không quan tâm những class khác, nó giúp cho mình dễ mở rộng và bảo trì code.
Kết luận
Trong đa số trường hợp nếu apply thằng Single responsibility principle này sẽ giúp code dễ mở rộng và bảo trì hơn, trừ trường hợp ứng dụng bạn quá nhỏ thì tách ra chỉ thêm phiền phức thêm mà thôi.