Menu
CoddyTech

接口设计

本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 24 课,共 65 课。

接口是一个方法列表,表示类承诺会实现这些方法,但不提供具体代码。Java 和 C# 有 interface 关键字,GDScript 没有。你可以通过抽象类来构建相同的结构,其中所有方法都是抽象的:

# drawable.gd
@abstract
class_name Drawable
extends RefCounted

@abstract func draw() -> String
@abstract func resize(factor: int) -> void

它没有变量,也没有方法体。它描述了可绘制对象可以做什么,而每个类会决定具体如何实现:

# banner.gd
class_name Banner
extends Drawable

var text: String
var size := 1

func _init(t: String) -> void:
	text = t

func draw() -> String:
	return "Banner '%s' at size %d" % [text, size]

func resize(factor: int) -> void:
	size *= factor

Circle 也可以扩展 Drawable,并拥有 radius 以及自己的 draw() 和 resize()。使用该接口的代码只依赖这个接口,因此可以与所有扩展 Drawable 的类配合使用,包括之后编写的类:

func render_all(items: Array[Drawable]) -> void:
	for item in items:
		item.resize(2)
		print(item.draw())
var items: Array[Drawable] = [Banner.new("Sale"), Circle.new(3)]
render_all(items)
Banner 'Sale' at size 2
Circle with radius 6

一个类只有一个父类,因此只能扩展一个接口。当一个类还要担任第二种角色(例如保存到文件)时,扩展主要接口,并使用 has_method() 检查它是否具备第二种角色:

if item.has_method("save"):
	item.save()

让每个接口都保持精简:只包含几个属于同一角色的方法。扩展该接口的类只需编写自己需要的方法。

challenge icon

挑战

简单

围绕一个接口构建媒体播放器。

  • 在 playable.gd 中,将 Playable 设为接口:一个包含抽象方法 play() -> String 和 duration() -> int 的抽象类,时长单位为秒。
  • Song 继承 Playable。play() 返回 Playing song: TITLE by ARTIST,duration() 返回对应的秒数。
  • Video 继承 Playable。play() 返回 Playing video: TITLE in RESOLUTIONp(例如 in 1080p),duration() 返回对应的秒数。
  • Playlist 只了解 Playable。play_all() 会打印每个项目的 play(),total_time() 会将总时长以 M:SS 格式返回(秒数占两位,例如 4:05)。

Song 和 Video 的构造函数已经写好。提供的代码会读取后续项目的数量,然后每个项目读取一行:song TITLE ARTIST SECONDS 或 video TITLE RESOLUTION SECONDS。代码会调用 play_all() 并打印总时长。对于 song Imagine Lennon 183 和 video Trailer 1080 95,会打印:

Playing song: Imagine by Lennon
Playing video: Trailer in 1080p
Total time: 4:38

你的代码应写在 playable.gd、song.gd、video.gd 和 playlist.gd 中。main.gd 包含提供的输入/输出代码,不能修改。

亲手试试

extends Node

func _ready():
	# 提供的输入和输出代码:保持原样。
	var count := int(OS.read_string_from_stdin())
	var playlist := Playlist.new()
	for i in count:
		var p := OS.read_string_from_stdin().split(" ")
		if p[0] == "song":
			playlist.add(Song.new(p[1], p[2], int(p[3])))
		else:
			playlist.add(Video.new(p[1], int(p[2]), int(p[3])))
	playlist.play_all()
	print("Total time: " + playlist.total_time())
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: GDScript 在线编译器