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.0Si 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.
Desafío
FácilUna 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
PaymentMethodsea abstracta y declara dos métodos abstractos:fee() -> floatymethod_name() -> String. Escribereceipt(), que devuelveNAME: paid AMOUNT, fee FEE, total TOTALcon 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 esCredit card.BankTransfer: la comisión es1.5, o0.0cuando el importe es100o más, y el nombre esBank 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.50Tu 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)
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
1Fundamentos de la programación orientada a objetos
Archivos externosIntroducción a la programación orientada a objetosClases vs. objetosLa palabra clave selfMétodosPropiedadesConstructor (_init)Repaso: calculadora sencilla4Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas7Señales
¿Qué es una señal?Declarar y emitirConectarse a las señalesSeñales con argumentosRepaso: sistema de salud10Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite2Propiedades de clase
Variables de instancia y estáticasFunciones estáticasMétodos setter de propiedadesMétodos getter de propiedadesPrivado por convenciónRepaso: administrador de cuentas bancarias5Encapsulación
Miembros públicos y privadosValidación con settersOcultación de informaciónPropiedades de solo lecturaRepaso: sistema de registros de estudiantes8Conceptos avanzados de POO
Composición frente a herenciaClases internasNodos como componentesRefCounted frente a NodeEnums en clases3Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosCadenas de herenciaComprobaciones de tipo con isRepaso: jerarquía de empleados6Métodos especiales
Introducción a los métodos virtualesEl método _to_stringIteradores personalizadosRepaso: lista personalizada9Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de GDScript online