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
DatabaseConnection
theo 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
,Triangle
thì 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
ShapeFactory
có 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:
Circle
với phương thứcdraw()
in ra "Vẽ hình tròn"Square
với phương thứcdraw()
in ra "Vẽ hình vuông"Triangle
vớ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:
DrinkFactory
có 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