🎨 Abstract Classes - Khung Xương Cho Code
Mục tiêu: Hiểu và sử dụng Abstract Classes để tạo ra template chuẩn cho các class khác! 🎯
🤔 Abstract Class Là Gì?
Abstract Class (Lớp trừu tượng) giống như một bản thiết kế hoặc khung xương - định nghĩa cấu trúc chung nhưng không thể tạo object trực tiếp.
🏗️ Ví Dụ Cuộc Sống
Hãy tưởng tượng bản thiết kế "Xe":
- 📐 Bản thiết kế chung: Có bánh xe, động cơ, tay lái
- 🚫 Không thể chế tạo: Không thể tạo ra một chiếc "Xe" chung chung
- ✅ Phải cụ thể hóa: Xe máy, xe hơi, xe tải...
📚 Cách Tạo Abstract Class trong Python
Python sử dụng module abc
(Abstract Base Classes):
from abc import ABC, abstractmethod
# Cách 1: Kế thừa từ ABC
class Shape(ABC):
"""Abstract class cho các hình học"""
@abstractmethod
def calculate_area(self):
"""Phương thức trừu tượng - bắt buộc phải implement"""
pass
@abstractmethod
def calculate_perimeter(self):
"""Phương thức trừu tượng khác"""
pass
def display_info(self):
"""Phương thức cụ thể - có thể dùng trực tiếp"""
print(f"🔷 Đây là hình {self.__class__.__name__}")
print(f"📐 Diện tích: {self.calculate_area()}")
print(f"📏 Chu vi: {self.calculate_perimeter()}")
# Thử tạo object từ abstract class
try:
shape = Shape() # ❌ Sẽ báo lỗi!
except TypeError as error:
print(f"🚫 Lỗi: {error}")
🔺 Concrete Classes - Thực Hiện Abstract
import math
class Circle(Shape):
"""Class cụ thể kế thừa từ Abstract Shape"""
def __init__(self, radius):
self.radius = radius
def calculate_area(self):
"""Bắt buộc implement - từ abstract method"""
return math.pi * self.radius ** 2
def calculate_perimeter(self):
"""Bắt buộc implement - từ abstract method"""
return 2 * math.pi * self.radius
def __str__(self):
return f"🔵 Hình tròn bán kính {self.radius}"
class Square(Shape):
"""Class hình vuông"""
def __init__(self, side):
self.side = side
def calculate_area(self):
return self.side ** 2
def calculate_perimeter(self):
return 4 * self.side
def __str__(self):
return f"🟦 Hình vuông cạnh {self.side}"
class Rectangle(Shape):
"""Class hình chữ nhật"""
def __init__(self, length, width):
self.length = length
self.width = width
def calculate_area(self):
return self.length * self.width
def calculate_perimeter(self):
return 2 * (self.length + self.width)
def __str__(self):
return f"🟨 Hình chữ nhật {self.length}x{self.width}"
# Test các concrete classes
print("🎨 DEMO ABSTRACT CLASSES")
print("=" * 40)
shape_list = [
Circle(5),
Square(4),
Rectangle(6, 3)
]
for shape in shape_list:
print(f"\n{shape}")
shape.display_info()
print("-" * 25)
🎮 Ví Dụ Game: Abstract Character System
from abc import ABC, abstractmethod
from enum import Enum
import random
class CharacterType(Enum):
WARRIOR = "Chiến Binh"
MAGE = "Pháp Sư"
ARCHER = "Cung Thủ"
HEALER = "Th ầy Thuốc"
class GameCharacter(ABC):
"""Abstract class cho tất cả nhân vật game"""
def __init__(self, name, character_type):
self.name = name
self.character_type = character_type
self.level = 1
self.exp = 0
self.is_alive = True
# Stats sẽ được set bởi subclass
self.hp = 0
self.mp = 0
self.hp_max = 0
self.mp_max = 0
self.attack = 0
self.defense = 0
@abstractmethod
def setup_base_stats(self):
"""Abstract method - mỗi class phải có stats riêng"""
pass
@abstractmethod
def special_attack(self, target):
"""Abstract method - kỹ năng đặc biệt của từng class"""
pass
@abstractmethod
def get_class_description(self):
"""Abstract method - mô tả class"""
pass
# Concrete methods - có thể dùng trực tiếp
def basic_attack(self, target):
"""Tấn công cơ bản - chung cho tất cả"""
if not self.is_alive:
print(f"💀 {self.name} đã chết, không thể tấn công!")
return 0
damage = self.attack + random.randint(-5, 10)
actual_damage = max(1, damage - target.defense)
target.take_damage(actual_damage)
print(f"⚔️ {self.name} tấn công {target.name} gây {actual_damage} sát thương!")
return actual_damage
def take_damage(self, damage):
"""Nhận sát thương"""
self.hp = max(0, self.hp - damage)
if self.hp == 0:
self.is_alive = False
print(f"💀 {self.name} đã bị hạ gục!")
else:
print(f"🩹 {self.name} còn {self.hp}/{self.hp_max} HP")
def heal(self, amount):
"""Hồi máu"""
old_hp = self.hp
self.hp = min(self.hp_max, self.hp + amount)
healed = self.hp - old_hp
if healed > 0:
print(f"💚 {self.name} hồi phục {healed} HP! ({self.hp}/{self.hp_max})")
else:
print(f"💚 {self.name} đã đầy máu!")
def level_up(self):
"""Tăng cấp"""
self.level += 1
self.exp = 0
# Tăng stats theo level
hp_bonus = 20
mp_bonus = 10
self.hp_max += hp_bonus
self.mp_max += mp_bonus
self.hp = self.hp_max # Full HP khi lên cấp
self.mp = self.mp_max # Full MP khi lên cấp
self.attack += 3
self.defense += 2
print(f"🎉 {self.name} lên cấp {self.level}!")
print(f" 📈 HP: +{hp_bonus}, MP: +{mp_bonus}, ATK: +3, DEF: +2")
def show_status(self):
"""Hiển thị trạng thái nhân vật"""
status_icon = "