Bài 10: SINGLETON VÀ FACTORY METHOD PATTERN
1. Singleton Pattern
1.1. Ý tưởng
- Singleton là mẫu thiết kế đảm bảo chỉ có một đối tượng duy nhất của một class trong suốt chương trình.
- Các nơi trong chương trình muốn dùng thì đều trỏ về cùng một object đó, không tạo mới nữa.
1.2. Ví dụ ngoài đời
- Hiệu trưởng trong một trường học → chỉ có một người.
- Tổng thống một quốc gia → chỉ có một.
- Trong phần mềm: kết nối Database thường dùng Singleton để tránh mở nhiều kết nối gây tốn tài nguyên.
1.3. Code Python minh họa
class Singleton:
_instance = None # biến class lưu instance duy nhất
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
# ----- Client -----
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True, vì chỉ có 1 instance
1.4. Bài tập cho học viên
- Viết một class
DatabaseConnectiontheo Singleton pattern. - In ra id của object khi tạo 2 biến khác nhau, xem có giống nhau không.
2. Factory Method Pattern
2.1. Ý tưởng
- Factory Method là mẫu thiết kế để tạo đối tượng mà không cần chỉ rõ class cụ thể.
- Client chỉ gọi factory (nhà máy), factory sẽ quyết định tạo ra object nào.
- Giúp code dễ mở rộng, không cần sửa chỗ client.
2.2. Ví dụ ngoài đời
- Nhà máy sản xuất phương tiện: chỉ cần gọi "sản xuất xe máy" hoặc "sản xuất ô tô", ta không cần quan tâm chi tiết quy trình lắp ráp.
- Trong lập trình: bạn muốn tạo
Circle,Square,Trianglethì chỉ cần gọiShapeFactory.create("circle").
2.3. Code Python minh họa
from abc import ABC, abstractmethod
# ----- Product -----
class Vehicle(ABC):
@abstractmethod
def drive(self):
pass
class Bike(Vehicle):
def drive(self):
return "Đi bằng xe máy"
class Car(Vehicle):
def drive(self):
return "Đi bằng ô tô"
# ----- Factory -----
class VehicleFactory:
def create_vehicle(self, vehicle_type):
if vehicle_type == "bike":
return Bike()
elif vehicle_type == "car":
return Car()
else:
raise ValueError("Loại phương tiện không hợp lệ!")
# ----- Client -----
factory = VehicleFactory()
v1 = factory.create_vehicle("bike")
v2 = factory.create_vehicle("car")
print(v1.drive()) # Đi bằng xe máy
print(v2.drive()) # Đi bằng ô tô
2.4. Bài tập cho học viên
- Viết một
ShapeFactorycó thể tạoCircle,Square,Triangle. - Mỗi shape có phương thức
draw()in ra tên hình. - Test bằng cách gọi
ShapeFactory.create("circle")và gọidraw().
3. So sánh và Ứng dụng
- Singleton: quản lý tài nguyên chung, khi chỉ cần 1 object duy nhất (ví dụ: logger, config, kết nối DB).
- Factory Method: tách việc tạo object ra khỏi client, giúp dễ mở rộng khi có nhiều loại sản phẩm khác nhau.
Bài tập thực hành
Bài 1: Singleton - Kết nối Database
Viết class DatabaseConnection theo Singleton Pattern.
- Mỗi lần gọi
DatabaseConnection(), chỉ được tạo duy nhất 1 instance. - In ra
id(object)để kiểm tra, nếu tạo nhiều lần thì id phải giống nhau.
Gợi ý kiểm tra:
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True
Bài 2: Singleton - Logger
Viết class Logger theo Singleton Pattern.
- Có phương thức
log(message)in ra tin nhắn. - Khi gọi logger ở nhiều nơi trong code, phải dùng chung một instance.
Ví dụ:
log1 = Logger()
log2 = Logger()
log1.log("Chương trình bắt đầu")
log2.log("Lỗi: Không tìm thấy file")
Bài 3: Factory - Hình học
Viết ShapeFactory có thể tạo ra:
Circlevới phương thứcdraw()in ra "Vẽ hình tròn"Squarevới phương thứcdraw()in ra "Vẽ hình vuông"Trianglevới phương thứcdraw()in ra "Vẽ hình tam giác"
Ví dụ:
factory = ShapeFactory()
shape = factory.create_shape("circle")
shape.draw()
Bài 4: Factory - Phương tiện giao thông
Viết TransportFactory có thể tạo ra:
Bike→ phương thứcmove()in ra "Đi bằng xe máy"Car→ phương thứcmove()in ra "Đi bằng ô tô"Bus→ phương thứcmove()in ra "Đi bằng xe buýt"
Viết đoạn code cho phép nhập từ bàn phím "bike", "car", "bus" và tạo object tương ứng.
Bài 5: Kết hợp Singleton + Factory
Tạo một hệ thống đặt đồ uống:
DrinkFactorycó thể tạoCoffee,Tea.- Có class
OrderManager(theo Singleton pattern) quản lý danh sách order. - Khi gọi
OrderManager.add_order(drink), order sẽ được lưu trong danh sách chung.
Ví dụ:
factory = DrinkFactory()
coffee = factory.create_drink("coffee")
tea = factory.create_drink("tea")
order_manager = OrderManager()
order_manager.add_order(coffee)
order_manager.add_order(tea)
order_manager.show_orders()
# Output: Coffee, Tea