Mẫu Singleton
Thuộc phần Lập trình hướng đối tượng trong hành trình GDScript của Coddy. Bài học 46 trên 65.
Mẫu Singleton đảm bảo một lớp chỉ có đúng một đối tượng và cung cấp cho mọi tập lệnh một cách để truy cập đối tượng đó. Hãy dùng mẫu này cho những thứ mà trò chơi chỉ có một, chẳng hạn như phần cài đặt, hệ thống lưu và bộ quản lý điểm.
Trong GDScript, một static var giữ đối tượng duy nhất, còn static func tạo đối tượng đó vào lần đầu tiên có người yêu cầu:
# game_settings.gd
class_name GameSettings
extends RefCounted
static var _instance: GameSettings = null
var volume := 50
static func get_instance() -> GameSettings:
if _instance == null:
_instance = GameSettings.new()
print("Creating settings")
return _instance_instance thuộc về lớp, không phải đối tượng, nên mọi script đều thấy cùng một biến. Lần gọi đầu tiên thấy biến này đang trống và tạo đối tượng; mọi lần gọi sau đều trả về chính đối tượng đó.
# main.gd
var a := GameSettings.get_instance()
var b := GameSettings.get_instance()
a.volume = 80
print(b.volume)
print(a == b)Creating settings
80
truea và b là hai biến cùng tham chiếu đến một đối tượng, vì vậy thay đổi thực hiện thông qua a cũng thể hiện qua b. Với các đối tượng, == chỉ là true khi cả hai vế đều là cùng một đối tượng.
GDScript không thể đặt _init() ở chế độ riêng tư, nên không có gì ngăn một script gọi GameSettings.new() và tạo ra đối tượng thứ hai. Dấu gạch dưới trong _instance và phương thức get_instance() thể hiện quy ước: các script yêu cầu lấy đối tượng, chứ không tự tạo đối tượng.
Trong một dự án Godot, cách thông thường để dùng chung một đối tượng là tạo autoload: một tập lệnh mà bạn đăng ký trong Project Settings. Godot tạo đối tượng này một lần khi trò chơi bắt đầu và cho phép mọi tập lệnh truy cập đối tượng đó bằng tên. Đây là Singleton do Godot quản lý thay bạn. Bạn thiết lập autoload trong trình chỉnh sửa, vì vậy các thử thách ở đây sẽ xây dựng mẫu này bằng code với static var.
Thử thách
DễMỗi đồng xu trong trò chơi đều cộng vào cùng một điểm số. Hãy tạo ScoreManager theo mẫu Singleton:
- Một
static varlưu đối tượng duy nhất. static func get_instance()trả về đối tượng đó, tạo đối tượng khi được gọi lần đầu. Ngay sau khi tạo, hàm in raScore manager created.add_points(points)cộng điểm vàoscore.
Trong coin.gd, collect() cộng value của đồng xu vào điểm số thông qua ScoreManager.get_instance().
Code được cung cấp đọc số lượng sự kiện tiếp theo, rồi đọc từng sự kiện trên một dòng: coin VALUE thu thập một đồng xu mới, bonus POINTS cộng điểm trực tiếp. Sau mỗi sự kiện, code in ra điểm số, và cuối cùng cho biết hai lần gọi get_instance() có trả về cùng một đối tượng hay không. Với coin 5 và bonus 20, đầu ra là:
Score manager created
Score: 5
Score: 25
Same object: truePhần code của bạn nằm trong score_manager.gd và coin.gd. main.gd chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
extends Node
func _ready():
# Đoạn code đầu vào/đầu ra đã cho: giữ nguyên
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "coin":
Coin.new(int(parts[1])).collect()
elif parts[0] == "bonus":
ScoreManager.get_instance().add_points(int(parts[1]))
print("Score: %d" % ScoreManager.get_instance().score)
print("Same object: %s" % (ScoreManager.get_instance() == ScoreManager.get_instance()))
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ề OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa selfPhương thứcThuộc tínhHàm khởi tạo (_init)Ôn tập: máy tính đơn giản4Tính đa hình
Xem lại cách ghi đè phương thứcĐịnh kiểu vịtLớp và phương thức trừu tượngThiết kế interfaceÔn tập: máy tính hình học7Tín hiệu
Tín hiệu là gì?Khai báo và phát tín hiệuKết nối với tín hiệuTín hiệu có đối sốÔn tập: hệ thống sức khỏe10Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổng hợp2Thuộc tính của lớp
Biến instance và biến staticHàm staticPhương thức thiết lập thuộc tínhPhương thức lấy thuộc tínhQuy ước về tính riêng tưÔn tập: trình quản lý tài khoản ngân hàng5Tính đóng gói
Thành viên công khai và riêng tưXác thực bằng phương thức setterẨn thông tinThuộc tính chỉ đọcÔn tập: hệ thống hồ sơ học sinh8Khái niệm OOP nâng cao
Kết hợp và kế thừaLớp bên trongNode dưới dạng thành phầnRefCounted và NodeEnum trong lớpTự luyện tập: Trình biên dịch GDScript online