bài viết ngẫu nhiên
Trong lập trình hướng đối tượng, có một nguyên tắc nghe tên hơi dài dòng: Interface Segregation Principle (ISP).
Nghe thì học thuật, nhưng ý tưởng rất đơn giản: “Đừng bắt người khác dùng những thứ họ không cần”.
Interface Segregation Principle (ISP) là chữ I trong bộ nguyên tắc SOLID. Nó nói rằng:
👉 Client (class) không nên phụ thuộc vào những method mà nó không sử dụng.
Nói cách khác, thay vì một interface khổng lồ ôm đủ loại chức năng, ta nên chia nhỏ thành nhiều interface gọn gàng, đúng nhu cầu.
Hãy tưởng tượng bạn thuê một thợ điện nước đến sửa nhà.
Bạn chỉ muốn họ thay bóng đèn và sửa vòi nước.
Nhưng hợp đồng họ đưa dài cả trang A4: bao gồm sửa thang máy, lắp camera, cài WiFi, thậm chí… huấn luyện chó 🐶.
Bạn sẽ thấy sao? Vừa buồn cười vừa khó chịu.
Trong code, một interface quá to cũng tạo cảm giác y như vậy.
Giả sử ta đang làm một hệ thống máy in văn phòng.
Bạn định nghĩa một interface “đa năng” thế này:
interface Machine {
print(content: string): void;
scan(): string;
fax(content: string): void;
}
Nghe có vẻ hợp lý… cho đến khi có một chiếc máy in đời cũ, chỉ biết in thôi, không scan, không fax.
class OldPrinter implements Machine {
print(content: string) {
console.log("Printing:", content);
}
scan(): string {
throw new Error("Not supported");
}
fax(content: string): void {
throw new Error("Not supported");
}
}
👉 Rõ ràng OldPrinter không muốn (và không thể) implement scan hay fax. Nhưng vì interface Machine ép buộc, nó đành phải khai báo thừa.
Đây chính là mùi code (code smell) – dấu hiệu thiết kế chưa ổn.
Thay vì một interface khổng lồ, ta tách nhỏ chúng thành nhiều interface riêng biệt:
interface Printer {
print(content: string): void;
}
interface Scanner {
scan(): string;
}
interface Fax {
fax(content: string): void;
}
Bây giờ, class nào cần gì thì implement cái đó:
class SimplePrinter implements Printer {
print(content: string) {
console.log("Printing:", content);
}
}
class MultiFunctionPrinter implements Printer, Scanner, Fax {
print(content: string) {
console.log("Printing:", content);
}
scan(): string {
return "Scanned content";
}
fax(content: string) {
console.log("Faxing:", content);
}
}
👉 SimplePrinter chỉ in.
👉 MultiFunctionPrinter thì đủ cả ba chức năng.
Không còn chuyện ép buộc, code trở nên rõ ràng và dễ bảo trì hơn.
Thực tế, trong TypeScript và NestJS mà nhiều dev backend hay dùng:
Nhờ vậy, khi bạn test hoặc thay đổi implementation (ví dụ chuyển từ Twilio sang AWS SNS), bạn không phải sửa một mớ method không liên quan.
👉 Đừng tạo ra “hợp đồng” quá phức tạp. Hãy chia nhỏ để ai cũng chỉ làm đúng phần việc của mình.