VieTopikKhoá học
  • Games
  • Cá nhân
Tải app
© 2026 VieTopikChính sách bảo mậtĐiều khoản sử dụngCài appEnglish
  • Trang chủ
  • Học
  • Luyện thi
  • Cẩm nang
  • Games
  • Cá nhân
OOP và thiết kếSOLID
Bài 9/12
5 phút

OCP — Mở rộng mà không sửa code cũ

Bình luận
Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 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
90000
  • Checkout chỉ biết IDiscount, 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. Checkout khô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
80000

Dò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/switch theo 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.
SRP — Một class, một trách nhiệmLSP — Class con phải thay được class cha

Bình luận

Đang tải bình luận…

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt