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ếInterface và composition
Bài 7/12
5 phút

Composition

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

Đơn hàng có hai kiểu giao (thường, nhanh) và hai kiểu gói (thường, gói quà). Dùng kế thừa thì phải có FastOrder, GiftOrder, FastGiftOrder… Mỗi lựa chọn mới lại nhân số class lên. Composition giải quyết việc này bằng cách ghép các phần lại với nhau.

Khái niệm

🧱 Composition: class chứa object của class khác làm property và giao việc cho object đó, thay vì kế thừa.

Đơn hàng không phải là một cách giao hàng, mà có một cách giao hàng, như Customer có Address ở bài Kế thừa.

Ví dụ

var order = new Order
{
    Subtotal = 200000m,
    Shipping = new StandardShipping(),
};
Console.WriteLine(order.Total());   // 230000

interface IShipping
{
    decimal Fee(decimal subtotal);
}

class StandardShipping : IShipping
{
    public decimal Fee(decimal subtotal) => 30000m;
}

class FastShipping : IShipping
{
    public decimal Fee(decimal subtotal) => 60000m;
}

class Order
{
    public decimal Subtotal { get; set; }
    public IShipping Shipping { get; set; }
        = new StandardShipping();

    public decimal Total() =>
        Subtotal + Shipping.Fee(Subtotal);
}
  • Order có một IShipping, và giao việc tính phí ship cho nó.
  • Muốn đổi cách giao chỉ cần gán object khác cho Shipping. Không cần tạo class con của Order.
  • Thêm kiểu giao mới chỉ cần thêm một class implement IShipping.
Order Subtotal Shipping Total() <<interface>> IShipping Fee() StandardShipping FastShipping
Order có một IShipping, gán object nào cũng được

Thử ngay

Chép ví dụ trên vào Program.cs, thay các dòng gọi ở đầu file bằng:

var order = new Order { Subtotal = 200000m };
Console.WriteLine(order.Total());

order.Shipping = new FastShipping();
Console.WriteLine(order.Total());

Đoán trước khi chạy: cùng một object order, đổi Shipping rồi gọi lại Total(). Hai dòng in ra có khác nhau không?

Xem kết quả
230000
260000

Khác nhau. Object order vẫn là object cũ, chỉ phần giao hàng bên trong được thay. Kế thừa không làm được việc này: một object đã tạo từ FastOrder thì không thể đổi thành StandardOrder.

Lỗi hay gặp

Dùng kế thừa cho mọi tổ hợp lựa chọn. Số class bằng tích số các lựa chọn.

// SAI — 2 kiểu giao × 2 kiểu gói = 4 class con
class BaseOrder { }
class StandardOrder : BaseOrder { }
class FastOrder : BaseOrder { }
class StandardGiftOrder : StandardOrder { }
class FastGiftOrder : FastOrder { }
// ĐÚNG — một class, ghép các phần lại
class Order
{
    public IShipping Shipping { get; set; }
        = new StandardShipping();
    public bool GiftWrap { get; set; }
}

Thêm kiểu giao thứ ba thì cách kế thừa cần 6 class con. Cách composition chỉ thêm một class implement IShipping.

Tóm tắt

  • Composition: class có object khác làm property và giao việc cho nó.
  • Kế thừa là "là một", composition là "có một".
  • Composition đổi được hành vi ngay lúc chạy bằng cách gán object khác.
  • Khi phân vân giữa hai cách, ưu tiên composition.
Interface hay abstract classSRP — Một class, một trách nhiệm

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