OCP — Mở rộng mà không sửa code 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
Cửa hàng có giảm giá cho khách thường và khách thân thiết. Mỗi lần thêm loại
khách mới, bạn lại mở method tính giảm giá ra thêm một nhánh if, và mỗi lần
sửa code đang chạy là một lần có thể làm hỏng. OCP chỉ cách thêm tính năng
mà không đụng vào code cũ.
Khái niệm
🔓 OCP (Open/Closed Principle): class nên mở cho việc mở rộng nhưng đóng với việc sửa đổi.
Nghĩa là thêm tính năng bằng cách viết code mới thay vì sửa code đang chạy. Cách làm thường gặp: đưa phần hay thay đổi ra sau một interface. Mỗi biến thể mới là một class mới implement interface đó.
Ví dụ
var checkout = new Checkout();
Console.WriteLine(
checkout.Pay(100000m, new RegularDiscount()));
Console.WriteLine(
checkout.Pay(100000m, new LoyalDiscount()));
interface IDiscount
{
decimal Apply(decimal amount);
}
class RegularDiscount : IDiscount
{
public decimal Apply(decimal amount) => amount;
}
class LoyalDiscount : IDiscount
{
public decimal Apply(decimal amount) =>
amount - amount * 10 / 100;
}
class Checkout
{
public decimal Pay(
decimal amount, IDiscount discount) =>
discount.Apply(amount);
}100000
90000Checkoutchỉ biếtIDiscount, không biết có bao nhiêu loại giảm giá.- Thêm loại giảm giá mới là thêm class mới.
Checkoutkhông phải sửa. - Đây chính là đa hình và interface đã học ở các chương trước.
Thử ngay
Chép ví dụ trên vào Program.cs. Thêm class dưới đây vào cuối file, rồi thêm
Console.WriteLine(checkout.Pay(100000m, new VipDiscount())); ngay sau hai
lệnh in ở đầu file:
class VipDiscount : IDiscount
{
public decimal Apply(decimal amount) =>
amount - amount * 20 / 100;
}Đoán trước khi chạy: dòng thứ ba in ra số nào?
Xem kết quả
100000
90000
80000Dòng thứ ba là 80000, tức 100000 giảm 20%. Checkout không sửa dòng nào,
tính năng mới nằm gọn trong class VipDiscount.
Lỗi hay gặp
Chuỗi if phình ra theo thời gian. Mỗi loại khách mới là một lần sửa
method cũ.
// SAI — thêm loại khách là phải sửa method này
decimal Pay(decimal amount, string type)
{
if (type == "regular")
{
return amount;
}
else if (type == "loyal")
{
return amount - amount * 10 / 100;
}
return amount;
}// ĐÚNG — loại khách mới là một class IDiscount mới
decimal Pay(decimal amount, IDiscount discount)
{
return discount.Apply(amount);
}Tóm tắt
- OCP: thêm tính năng bằng code mới, không sửa code đang chạy.
- Đưa phần hay thay đổi ra sau interface, mỗi biến thể là một class.
- Chuỗi
if/switchtheo loại, phình ra mỗi lần có loại mới, là dấu hiệu nên dùng OCP. - Chỉ áp dụng cho phần thật sự hay thay đổi.
Bình luận
Đang tải bình luận…