Menu
CoddyTech

Clases y métodos abstractos

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 23 de 65.

Algunas clases existen únicamente para que se extiendan. Toda forma tiene un área, pero no puedes calcularla hasta saber si la forma es un círculo o un rectángulo. Marca una clase así con @abstract, en la línea anterior a class_name:

# shape.gd
@abstract
class_name Shape
extends RefCounted

@abstract func area() -> float
@abstract func perimeter() -> float

func describe() -> String:
	return "Area %.1f, perimeter %.1f" % [area(), perimeter()]

Una @abstract func tiene una firma y no tiene cuerpo: no lleva dos puntos ni código después. Indica que cada clase hija debe proporcionar este método. describe() es un método normal; las clases hijas lo heredan y ya puede llamar a los métodos abstractos.

No puedes crear un objeto de una clase abstracta. Shape.new() detiene el programa antes de que se inicie con Parse Error: Cannot construct abstract class "Shape".

Una clase derivada que implementa todos los métodos abstractos es una clase normal:

# rectangle.gd
class_name Rectangle
extends Shape

var width: float
var height: float

func _init(w: float, h: float) -> void:
	width = w
	height = h

func area() -> float:
	return width * height

func perimeter() -> float:
	return 2 * (width + height)
var rect := Rectangle.new(4.0, 6.0)
print(rect.describe())
Area 24.0, perimeter 20.0

Si una clase hija omite uno, Godot lo informa antes de ejecutar: Class "Square" must implement "Shape.perimeter()" and other inherited abstract methods or be marked as "@abstract". Así que cada objeto que puedes crear tiene area() y perimeter().

Una clase abstracta aún puede tener variables y un _init(). Las clases hijas lo llaman con super(), como de costumbre.

challenge icon

Desafío

Fácil

Una tienda acepta dos métodos de pago. Cada pago tiene un importe y un recibo, pero la comisión y el nombre dependen del método.

  • Haz que PaymentMethod sea abstracta y declara dos métodos abstractos: fee() -> float y method_name() -> String. Escribe receipt(), que devuelve NAME: paid AMOUNT, fee FEE, total TOTAL con dos decimales para cada número (el total es el importe más la comisión).
  • CreditCard: la comisión es el 3% del importe (amount * 0.03) y el nombre es Credit card.
  • BankTransfer: la comisión es 1.5, o 0.0 cuando el importe es 100 o más, y el nombre es Bank transfer.

Las clases hijas usan el constructor de PaymentMethod. El código proporcionado lee cuántos pagos siguen y después una línea por cada pago: card AMOUNT o transfer AMOUNT. Imprime cada recibo y la suma de las comisiones. Para card 50 y transfer 120, imprime:

Credit card: paid 50.00, fee 1.50, total 51.50
Bank transfer: paid 120.00, fee 0.00, total 120.00
Total fees: 1.50

Tu código va en payment_method.gd, credit_card.gd y bank_transfer.gd. main.gd contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: mantenlo tal como está
	var count := int(OS.read_string_from_stdin())
	var total_fees := 0.0
	for i in count:
		var p := OS.read_string_from_stdin().split(" ")
		var payment: PaymentMethod
		if p[0] == "card":
			payment = CreditCard.new(float(p[1]))
		else:
			payment = BankTransfer.new(float(p[1]))
		print(payment.receipt())
		total_fees += payment.fee()
	print("Total fees: %.2f" % total_fees)
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online