ISP — Interface nhỏ, đúng việc
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
Interface IOrderStore có ba method: đọc, lưu, xoá. Trang báo cáo chỉ cần
đọc nhưng vẫn phải implement đủ ba method, hai method thừa chỉ ném
NotImplementedException (exception có sẵn báo method chưa viết). ISP tránh
việc ép class nhận những thứ nó không dùng.
Khái niệm
✂️ ISP (Interface Segregation Principle): không bắt class phụ thuộc vào những method nó không dùng, nên chia interface lớn thành nhiều interface nhỏ theo từng việc.
Ví dụ
var repo = new OrderRepository();
var page = new ReportPage(repo);
page.Show();
interface IOrderReader
{
string Get(int id);
}
interface IOrderWriter
{
void Save(string order);
}
class OrderRepository : IOrderReader, IOrderWriter
{
public string Get(int id) => $"Đơn #{id}";
public void Save(string order) =>
Console.WriteLine($"Lưu {order}");
}
class ReportPage
{
private readonly IOrderReader _reader;
public ReportPage(IOrderReader reader)
{
_reader = reader;
}
public void Show() =>
Console.WriteLine(_reader.Get(1));
}IOrderReaderchỉ đọc,IOrderWriterchỉ ghi. Mỗi interface một việc.OrderRepositorylàm được cả hai nên implement cả hai.ReportPagechỉ cần đọc nên chỉ nhậnIOrderReader. Sửa phần ghi không ảnh hưởng tới nó.
Thử ngay
Chép ví dụ trên vào Program.cs, thêm hai dòng sau ngay dưới page.Show();:
IOrderWriter writer = repo;
writer.Save("Đơn #2");Đoán trước khi chạy: cùng một object repo, vừa truyền cho
ReportPage như một IOrderReader, vừa gán vào biến IOrderWriter. Có
được không?
Xem kết quả
Đơn #1
Lưu Đơn #2Được. Object implement nhiều interface thì đóng được vai của từng interface đó. Mỗi nơi chỉ thấy đúng phần nó cần.
Lỗi hay gặp
Interface quá to, class phải implement cho có. NotImplementedException là
dấu hiệu rõ nhất.
// SAI — trang báo cáo bị ép implement cả ghi và xoá
interface IOrderStore
{
string Get(int id);
void Save(string order);
void Delete(int id);
}
class ReportSource : IOrderStore
{
public string Get(int id) => $"Đơn #{id}";
public void Save(string order)
{
throw new NotImplementedException();
}
public void Delete(int id)
{
throw new NotImplementedException();
}
}// ĐÚNG — trang báo cáo chỉ implement phần đọc
class ReportSource : IOrderReader
{
public string Get(int id) => $"Đơn #{id}";
}Tóm tắt
- ISP: không bắt class phụ thuộc vào method nó không dùng.
- Chia interface lớn thành nhiều interface nhỏ theo từng việc.
- Một class implement được nhiều interface nhỏ khi nó làm được nhiều việc.
NotImplementedExceptiontrong class implement là dấu hiệu interface quá to.
Tự kiểm tra
0/3 câuIPrinter có Print(), Scan(), Fax(). Máy in rẻ chỉ in được, nên Scan và Fax ném NotImplementedException. Theo ISP nên làm gì?
Class Dashboard chỉ đọc dữ liệu đơn hàng. Constructor của nó nên nhận kiểu nào?
IAccountService có Login(), Logout(), ChangePassword() và được năm class implement. Team thêm ResetPassword() vào interface này. Class nào phải sửa?