Bài 5 · Nâng cao · 18 phút· Cập nhật 11/06/2026
I - Interface Segregation
Biên soạn bởi Nguyễn Anh Tuấn
Interface Segregation Principle (ISP): ưu tiên tạo ra các interface nhỏ, chuyên biệt thay vì một interface lớn, để các lớp chỉ cần triển khai những gì chúng thực sự cần
Interface Segregation Principle (ISP): đừng ép một lớp phụ thuộc vào những method nó không dùng. Thà nhiều interface nhỏ, chuyên biệt, còn hơn một interface to ôm đồm. Xem một interface "béo":
❌ Vi phạm ISP - Robot bị ép ăn & ngủ
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
class Person implements Worker {
work() {}
eat() {}
sleep() {}
}
class Robot implements Worker {
work() {}
// Robot khong an, khong ngu - nhung van bi ep implement:
eat() { throw new Error("Robot khong an!"); } // hoac de trong (no-op)
sleep() { throw new Error("Robot khong ngu!"); }
} - ▸Robot buộc implement eat()/sleep() dù không bao giờ dùng.
- ▸Để trống (no-op) = nói dối kiểu; ném lỗi = bom nổ chậm lúc chạy.
- ▸Người gọi tin "mọi Worker đều eat()" và có thể gọi nhầm.
Chẻ interface béo thành các interface nhỏ; mỗi lớp implement đúng cái nó cần:
✅ Tuân thủ ISP - nhiều interface nhỏ
interface Workable { work(): void; }
interface Eatable { eat(): void; }
interface Sleepable { sleep(): void; }
class Person implements Workable, Eatable, Sleepable {
work() {}
eat() {}
sleep() {}
}
class Robot implements Workable { // chi nhung gi Robot thuc su lam
work() {}
} - ▸Robot chỉ implement Workable - không còn method thừa.
- ▸Person ghép nhiều interface khi nó thực sự có các khả năng đó.
- ▸Hợp đồng giờ phản ánh ĐÚNG khả năng - không lừa người gọi.
Lợi ích lớn nhất: hàm/lớp chỉ khai báo phụ thuộc tối thiểu, nhờ vậy linh hoạt và dễ test:
Khai báo đúng khả năng tối thiểu
// Ca lam chi can Workable - nhan duoc ca Person lan Robot
function vanHanhCa(workers: Workable[]) {
workers.forEach((w) => w.work());
}
// Khi can nhieu kha nang, ghep kieu lai:
function nghiTrua(x: Eatable & Sleepable) {
x.eat();
x.sleep();
} - ▸Client phụ thuộc interface nhỏ → ít lý do phải đổi theo, ít coupling.
- ▸Mock trong test chỉ cần implement đúng method cần → test gọn.
- ▸TypeScript cho ghép kiểu (A & B) khi cần nhiều khả năng cùng lúc.
- ▸Dấu hiệu vi phạm: lớp implement method rỗng hoặc "throw not supported".
- ▸ISP và LSP đi cùng: interface vừa khít giúp lớp con luôn giữ trọn hợp đồng.
- ▸Đừng chẻ vụn vô nghĩa - gom các method THƯỜNG ĐI CÙNG NHAU vào một interface gắn kết.
ISP là SRP cho interface
Câu hỏi thường gặp
SRP nói về LỚP (một lớp một trách nhiệm - nhìn từ phía người viết lớp). ISP nói về INTERFACE/hợp đồng (đừng bắt client phụ thuộc thứ nó không cần - nhìn từ phía người DÙNG interface). Một interface béo thường ép cả lớp implement gánh thêm trách nhiệm thừa, nên hai nguyên tắc hay đi cùng nhau.
Vì nó nói dối: kiểu (type) bảo "Robot biết eat()", nhưng thực tế không. Người gọi tin vào hợp đồng và có thể gọi nhầm, gây bug âm thầm hoặc phải ném lỗi lúc chạy. Đây cũng là cửa ngõ vi phạm LSP (lớp con không giữ được hợp đồng).
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Interface Segregation Principle khuyên điều gì?
- 1
Soi method thừa
Lấy ví dụ
interface Worker(work/eat/sleep). Với mỗi lớp (Person,Robot), đánh dấu method nào là thừa.✅ Hoàn thành khi: Chỉ ra
Robotbị épeat()/sleep(); nêu hậu quả của việc để no-op hoặc ném lỗi. - 2
Tách interface
Refactor
Workerthành các interface nhỏ (Workable,Eatable,Sleepable) và choPerson/Robotimplement đúng nhu cầu.✅ Hoàn thành khi: Không lớp nào còn method thừa;
Robotchỉ implementWorkable. - 3
Tự tìm trong thực tế
Tìm một interface "béo" trong thư viện/SDK em hay dùng (vd interface có cả đọc lẫn ghi mà client chỉ cần đọc). Đề xuất cách tách.
✅ Hoàn thành khi: Chỉ ra interface cụ thể; đề xuất ≥2 interface nhỏ hợp lý.
- 4
Ghép khi cần
Viết một hàm chỉ nhận đúng khả năng nó cần (vd
function caLamCaAn(x: Workable & Eatable)).✅ Hoàn thành khi: Tham số khai báo đúng khả năng tối thiểu; không yêu cầu thừa.