Định kiểu vịt
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 22 trên 65.
Duck typing tập trung vào những gì một đối tượng có thể làm, chứ không phải nó thuộc lớp nào. Nếu đối tượng có phương thức bạn gọi, lệnh gọi đó sẽ hoạt động. Tên gọi này bắt nguồn từ câu nói “nếu nó bơi như vịt và kêu như vịt thì nó là vịt”.
Hai lớp này không có lớp cha chung, nhưng cả hai đều có swim() và quack():
# duck.gd
class_name Duck
extends RefCounted
func swim() -> String:
return "Duck swimming"
func quack() -> String:
return "Quack!"# robot.gd
class_name Robot
extends RefCounted
func swim() -> String:
return "Robot swimming with propellers"
func quack() -> String:
return "Robot sound: BEEP BEEP!"Tham số không có kiểu dữ liệu sẽ chấp nhận mọi đối tượng. Hàm gọi các phương thức, và mỗi đối tượng tự chạy phương thức của mình:
func make_it_swim_and_quack(thing) -> void:
print(thing.swim())
print(thing.quack())make_it_swim_and_quack(Duck.new())
make_it_swim_and_quack(Robot.new())Duck swimming
Quack!
Robot swimming with propellers
Robot sound: BEEP BEEP!Ghi đè cần có lớp cha chung, còn duck typing thì không. Với tham số có kiểu thing: Duck, truyền một Robot vào sẽ gây lỗi phân tích cú pháp.
Khi một đối tượng không có phương thức đó, lời gọi sẽ dừng hàm và báo lỗi như Invalid call. Nonexistent function 'quack'. Trước tiên, hãy kiểm tra bằng has_method(), tham số của hàm này là tên phương thức dưới dạng String:
var things := [Duck.new(), Rock.new()]
for thing in things:
if thing.has_method("quack"):
print(thing.quack())
else:
print("This one cannot quack")Quack!
This one cannot quackCái giá phải trả: khi có kiểu dữ liệu, Godot phát hiện tên phương thức sai trước khi chương trình chạy; với kiểu gõ vịt, bạn chỉ phát hiện ra khi dòng lệnh chạy. Hãy dùng cách này cho các đối tượng thuộc những lớp không liên quan nhưng có chung một vài phương thức.
Thử thách
DễMột vụ nổ gây sát thương cho mọi thứ ở gần có thể nhận sát thương. Các đối tượng không có lớp cha chung. player.gd và rock.gd đã hoàn tất: Player có take_damage(amount) và status(), còn Rock chỉ có status().
- Trong
crate.gd, hãy thêm choCratemột biếnbrokenban đầu làfalse, một phương thứctake_damage(amount)làm hỏng thùng khi lượng sát thương là10trở lên, vàstatus()trả vềCrate: brokenhoặcCrate: intact. - Trong
explosion.gd, hãy viết phương thức tĩnhhit_all(things, amount). Phương thức này gọitake_damage(amount)trên mọi đối tượng trong mảng có phương thức đó, rồi trả về số đối tượng bị đánh trúng.
Code được cung cấp đọc một dòng tên đối tượng (player, crate hoặc rock), sau đó đọc số vụ nổ và lượng sát thương của mỗi vụ. Code in ra số đối tượng bị mỗi vụ nổ đánh trúng, rồi in trạng thái của từng đối tượng. Với player crate rock và các vụ nổ gây sát thương 5 và 20, kết quả in ra là:
Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solidCode của bạn đặt trong crate.gd và explosion.gd. main.gd chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.
Tự làm thử
extends Node
func _ready():
# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
var things := []
for word in OS.read_string_from_stdin().split(" "):
if word == "player":
things.append(Player.new())
elif word == "crate":
things.append(Crate.new())
else:
things.append(Rock.new())
var count := int(OS.read_string_from_stdin())
for i in count:
var hits := Explosion.hit_all(things, int(OS.read_string_from_stdin()))
print("Explosion %d hit %d objects" % [i + 1, hits])
for thing in things:
print(thing.status())
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