Mẫu Singleton
Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 45 trên 64.
Mẫu Singleton đảm bảo một lớp chỉ có một đối tượng và cung cấp một điểm truy cập toàn cục đến đối tượng đó. Mẫu này hữu ích với các tài nguyên như kết nối cơ sở dữ liệu hoặc các thiết lập cấu hình.
Đây là cách triển khai Singleton cơ bản:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instancePhương thức __new__ kiểm soát việc tạo đối tượng. Phương thức này kiểm tra xem đã có instance nào tồn tại chưa trước khi tạo instance mới.
Tạo hai đối tượng Singleton:
singleton1 = Singleton()
singleton2 = Singleton()Kiểm tra xem cả hai biến có tham chiếu đến cùng một đối tượng không:
print(singleton1 is singleton2) # True
print(id(singleton1)) # Cùng địa chỉ bộ nhớ
print(id(singleton2)) # Cùng địa chỉ bộ nhớĐây là một ví dụ thực tế hơn về kết nối cơ sở dữ liệu:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
print("Creating new database connection")
return cls._instance
def query(self, sql):
return f"Executing: {sql}"
# Lần truy cập đầu tiên tạo kết nối
db1 = DatabaseConnection()
print(db1.connection)
# Lần truy cập thứ hai dùng lại kết nối đó
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)Tạo trình quản lý cấu hình bằng Singleton:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
def set_setting(self, key, value):
self.settings[key] = value
def get_setting(self, key):
return self.settings.get(key)
config1 = Config()
config1.set_setting("debug", True)
config2 = Config()
print(config2.get_setting("debug")) # True, cùng các thiết lậpĐầu ra:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
TrueĐiểm chính: Mẫu Singleton dùng __new__ để kiểm soát việc tạo đối tượng, bảo đảm chỉ có một instance tồn tại. Hãy dùng mẫu này cho các tài nguyên chỉ nên có một bản trong toàn bộ ứng dụng, như kết nối cơ sở dữ liệu, bộ ghi nhật ký hoặc trình quản lý cấu hình. Hãy nhớ rằng mọi biến trỏ đến Singleton đều tham chiếu đến cùng một đối tượng trong bộ nhớ.
Thử thách
DễTrong thử thách này, bạn sẽ triển khai mẫu thiết kế Singleton cho một lớp kết nối cơ sở dữ liệu.
- Chỉnh sửa
databaseconnection.pyđể triển khai mẫu Singleton theo các chú thích TODO - Tệp
driver.pychứa nhiều tình huống kiểm thử và không nên được chỉnh sửa
Tự làm thử
from databaseconnection import DatabaseConnection
# Phần xử lý toàn diện các test case
test_case = input()
if test_case == "identity_check":
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # Sẽ in ra True
elif test_case == "connect_state":
db = DatabaseConnection()
print(f"Initial connected state: {db.connected}") # Sẽ in ra False
db.connect()
print(f"After connect: {db.connected}") # Sẽ in ra True
elif test_case == "disconnect_state":
db = DatabaseConnection()
db.connect()
db.disconnect()
print(f"After disconnect: {db.connected}") # Sẽ in ra False
elif test_case == "multiple_instances_same_state":
db1 = DatabaseConnection()
db1.connect()
db2 = DatabaseConnection()
print(f"db2 connected state: {db2.connected}") # Sẽ in ra True
elif test_case == "host_value":
db = DatabaseConnection()
print(f"Default host: {db.host}") # Sẽ in ra "localhost"
db.host = "new-server"
db2 = DatabaseConnection()
print(f"New instance host: {db2.host}") # Sẽ in ra "new-server"
elif test_case == "init_once":
db1 = DatabaseConnection()
db1.host = "custom-host"
db2 = DatabaseConnection()
print(f"Both instances have same host: {db1.host == db2.host}") # Sẽ in ra True
print(f"Host value: {db1.host}") # Sẽ in ra "custom-host"
elif test_case == "connect_message":
db = DatabaseConnection()
db.connect() # Sẽ in ra "Connected to database at localhost"
elif test_case == "disconnect_message":
db = DatabaseConnection()
db.connect()
db.disconnect() # Sẽ in ra "Disconnected from database"
elif test_case == "attribute_modification":
db1 = DatabaseConnection()
db1.port = 3306
db2 = DatabaseConnection()
print(f"db2 has port attribute: {hasattr(db2, 'port')}") # Sẽ in ra True
print(f"db2 port value: {db2.port}") # Sẽ in ra 3306
elif test_case == "reset_connection":
db1 = DatabaseConnection()
db1.connect()
print(f"Connected state: {db1.connected}") # Sẽ in ra True
db2 = DatabaseConnection()
print(f"New instance connected state: {db2.connected}") # Sẽ in ra True
db2.disconnect()
db3 = DatabaseConnection()
print(f"After disconnect, new instance state: {db3.connected}") # Sẽ in ra False
elif test_case == "multiple_connects":
db = DatabaseConnection()
db.connect()
db.connect()
db.connect()
print(f"Connected state after multiple connects: {db.connected}") # Sẽ in ra True
db.disconnect()
print(f"Connected state after disconnect: {db.connected}") # Sẽ in ra False
elif test_case == "host_change_affects_message":
db = DatabaseConnection()
db.host = "custom-server"
db.connect() # Vẫn sẽ in ra "Connected to database at localhost"
# Phương thức connect có thông báo được viết cố định, không dùng thuộc tính host
print("Message still shows localhost: True")Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnhTự luyện tập: Trình biên dịch Python online