OOP

Bốn tính chất OOP

Encapsulation, Abstraction, Inheritance, Polymorphism — định nghĩa, ví dụ song song C# / TypeScript, biến thể nâng cao.

Bốn tính chất OOP — overview

1. Encapsulation
Đóng gói
Che giấu state, expose qua API có kiểm soát (method/property).
2. Abstraction
Trừu tượng
Tách "cái gì làm" khỏi "làm như thế nào". Dùng interface / abstract class.
3. Inheritance
Kế thừa
Class con dùng lại + chuyên biệt hoá code class cha. Quan hệ "is-a".
4. Polymorphism
Đa hình
Cùng interface, nhiều cách hiện thực — runtime quyết định.
Câu PV gần như 100%:"Kể 4 tính chất OOP và cho ví dụ."Đừng học thuộc định nghĩa — kể được kèm ví dụ code cụ thể mới được điểm. Phần dưới có pattern để bạn nhớ lâu.

1. Encapsulation — đóng gói

State private + API public có validation = encapsulation.

public class BankAccount {
    // State được giấu kín
    private decimal _balance;
    private readonly string _owner;
    
    public BankAccount(string owner, decimal initial) {
        _owner = owner;
        _balance = initial >= 0 ? initial : 0;
    }
    
    // API expose có kiểm soát
    public decimal Balance => _balance;
    public string Owner => _owner;
    
    public void Deposit(decimal amount) {
        if (amount <= 0) throw new ArgumentException("Must be positive");
        _balance += amount;
    }
    
    public bool TryWithdraw(decimal amount) {
        if (amount <= 0 || amount > _balance) return false;
        _balance -= amount;
        return true;
    }
}
Khác biệt C# vs TS:
  • C# private enforce ở compile + runtime IL.
  • TS private chỉ check compile-time — runtime vẫn truy cập được. Dùng # để truly private runtime (JS native).

Vì sao quan trọng?

// ❌ Nếu không encapsulate
public class BankAccount {
    public decimal Balance;
}
account.Balance = -1000000;       // Negative balance? Bug!
account.Balance += 1.0/3;         // Floating point chia số → mất tiền

→ Encapsulation = invariant (bất biến của class) được bảo vệ. Balance không bao giờ âm. Validation luôn chạy.

2. Abstraction — trừu tượng

Định nghĩa "cái gì" mà không nói "làm sao".

// Abstraction qua interface
public interface IPaymentGateway {
    Task<PaymentResult> ChargeAsync(decimal amount, string currency);
    Task<bool> RefundAsync(string transactionId);
}

// Implementation cụ thể — Caller không cần biết
public class StripeGateway : IPaymentGateway {
    public Task<PaymentResult> ChargeAsync(decimal amount, string currency) {
        // gọi Stripe API
    }
    public Task<bool> RefundAsync(string transactionId) { ... }
}

public class VnPayGateway : IPaymentGateway {
    public Task<PaymentResult> ChargeAsync(decimal amount, string currency) {
        // gọi VnPay API
    }
    public Task<bool> RefundAsync(string transactionId) { ... }
}

// Service chỉ phụ thuộc abstraction
public class CheckoutService {
    private readonly IPaymentGateway _gateway;
    public CheckoutService(IPaymentGateway gateway) => _gateway = gateway;
    
    public async Task Checkout(Order order) {
        var result = await _gateway.ChargeAsync(order.Total, "VND");
        // ...
    }
}
Câu PV cốt lõi:"Abstraction khác Encapsulation chỗ nào?"

"Encapsulation là mechanism (cách che data — private). Abstraction là concept (che complexity — chỉ expose charge() không expose chi tiết gọi HTTP, parse JSON, retry, etc.).

Hai khái niệm bổ trợ: encapsulation phục vụ abstraction. Khi gộp lại — bạn cho user 1 API đơn giản và an toàn."

3. Inheritance — kế thừa

Class con tái sử dụng + chuyên biệt class cha. Quan hệ "is-a".

public abstract class Animal {
    public string Name { get; }
    
    protected Animal(string name) => Name = name;
    
    // Hành vi chung
    public void Sleep() => Console.WriteLine($"{Name} is sleeping");
    
    // Hành vi con phải define
    public abstract string Speak();
}

public class Dog : Animal {
    public Dog(string name) : base(name) {}
    public override string Speak() => "Woof!";
    public void Fetch() => Console.WriteLine($"{Name} fetches the ball");
}

public class Cat : Animal {
    public Cat(string name) : base(name) {}
    public override string Speak() => "Meow!";
    public void Scratch() => Console.WriteLine($"{Name} scratches");
}

Nhiều cấp kế thừa — nên dừng ở 2-3 cấp

Animal
 ├─ Mammal
 │   ├─ Dog
 │   └─ Cat
 └─ Bird
     └─ Penguin
Cảnh báo deep inheritance: > 3 cấp → khó maintain, "fragile base class" (sửa cha vỡ con). Nguyên tắc: "Favor composition over inheritance" — sẽ giải thích kỹ ở SOLID.

Multiple inheritance?

  • C#: chỉ 1 base class, nhiều interface.
  • TypeScript: chỉ 1 base class, nhiều interface. Có mixin để mô phỏng multiple inheritance.
// TS mixin pattern
type Constructor<T = {}> = new (...args: any[]) => T;

function Timestamped<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        createdAt = new Date();
    };
}

function Tagged<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        tags: string[] = [];
    };
}

class User { constructor(public name: string) {} }
class TaggedTimestampedUser extends Timestamped(Tagged(User)) {}

const u = new TaggedTimestampedUser("Alice");
u.tags.push("vip");
u.createdAt;     // có sẵn

4. Polymorphism — đa hình

Cùng API, nhiều behavior — runtime quyết.

2 loại chính

Compile-time
Overloading
Cùng tên, khác signature. C# hỗ trợ, TS hỗ trợ qua signature overload (declaration only).
Runtime
Overriding
virtual/abstract ở cha, override ở con. Runtime quyết qua vtable.
Animal[] zoo = { new Dog("Rex"), new Cat("Tom") };
foreach (var a in zoo) {
    Console.WriteLine($"{a.Name}: {a.Speak()}");
    // Runtime gọi Dog.Speak() hoặc Cat.Speak() đúng,
    // dù biến a kiểu Animal
}
Câu PV kinh điển:"Đa hình runtime hoạt động ra sao?"

"Runtime polymorphism qua vtable (virtual method table). Mỗi class có 1 vtable lưu pointer tới method virtual. Khi gọi a.Speak():

  1. Runtime lookup vtable của object thực (Dog/Cat) qua type tag.
  2. Tìm slot tương ứng method Speak.
  3. Gọi function pointer trong slot đó.

Đó là vì sao virtual method chậm hơn rất ít static — phải qua 1 cấp indirection."

Ad-hoc polymorphism (overloading) vs Subtype polymorphism (overriding)

  • Ad-hoc: cùng tên, signature khác, compile chọn.
  • Subtype: cùng signature, type khác, runtime chọn.

(Còn 1 loại nữa — Parametric polymorphism = generic. Xem section Generic.)

Bonus — Composition vs Inheritance

"Favor composition over inheritance" — quy tắc thực dụng cực mạnh.
  • Inheritance "is-a": Dog IS-A Animal.
  • Composition "has-a": Car HAS-A Engine.
// ❌ Lạm dụng inheritance — hierarchy phình to
public class Vehicle { ... }
public class Car : Vehicle { ... }
public class ElectricCar : Car { ... }
public class TeslaCar : ElectricCar { ... }
// 4 cấp → fragile, khó test, khó thay đổi

// ✅ Composition — Car HAS-A IEngine
public interface IEngine { void Start(); }
public class GasEngine : IEngine { public void Start() {} }
public class ElectricEngine : IEngine { public void Start() {} }

public class Car {
    private readonly IEngine _engine;
    public Car(IEngine engine) => _engine = engine;
    public void Drive() => _engine.Start();
}

// Đổi Car điện = inject ElectricEngine, không sửa Car

Bốn tính chất trong 1 ví dụ

Đây là code minh hoạ đủ 4 tính chất trong cùng 1 mini-app:

// Abstraction
public interface IShape {
    double Area();
    double Perimeter();
}

// Abstract + Inheritance + Encapsulation
public abstract class ShapeBase : IShape {
    public string Name { get; }                    // encapsulation
    protected ShapeBase(string name) => Name = name;
    public abstract double Area();
    public abstract double Perimeter();
    public override string ToString() =>
        $"{Name}: area={Area():F2}, perimeter={Perimeter():F2}";
}

// Inheritance + Polymorphism
public class Circle : ShapeBase {
    private readonly double _r;
    public Circle(double r) : base("Circle") => _r = r;
    public override double Area() => Math.PI * _r * _r;
    public override double Perimeter() => 2 * Math.PI * _r;
}

public class Rectangle : ShapeBase {
    private readonly double _w, _h;
    public Rectangle(double w, double h) : base("Rectangle") { _w = w; _h = h; }
    public override double Area() => _w * _h;
    public override double Perimeter() => 2 * (_w + _h);
}

// Polymorphism in action
IShape[] shapes = { new Circle(5), new Rectangle(3, 4) };
foreach (var s in shapes) Console.WriteLine(s);

© 2026 .NET Fresher Guide. All rights reserved.

Về Trang Web

Hướng dẫn toàn diện để chuẩn bị phỏng vấn vị trí .NET Fresher với nội dung từ lý thuyết đến thực hành.