Lección 5 · 5 de 20
Clases abstractas e interfaces · Dart
Defina contratos en Dart con clases abstractas e interfaces, y distinga extends de implements con varios métodos de pago.

Una clase `abstract` no se puede instanciar (PaymentMethod() no compila) y puede declarar miembros sin cuerpo: name y fee son abstractos, y cada subclase decide cómo son. charge, en cambio, es concreto: está escrito una vez y lo heredan todas, aunque dentro llame a fee, que la clase base todavía no sabe calcular.
Card y BankTransfer heredan con extends y rellenan lo que falta. La tarjeta cobra un 1,5 % más 25 céntimos, con división entera (~/); la transferencia no cobra comisión. Observe que name puede implementarse con un getter (get name =>) o con un campo final: para quien lo usa es lo mismo.
`implements` es otra cosa: toma solo el contrato, sin heredar código. Refundable se declara como abstract interface class, un modificador de Dart 3 que indica que está pensada para implementarse. Además, en Dart toda clase es una interfaz implícita: GiftCard implements PaymentMethod y por eso debe escribir todos sus miembros, también charge, que no recibe de nadie.
En el bucle, la variable es de tipo PaymentMethod y is Refundable pregunta si el objeto cumple también el otro contrato. Como Refundable no es un subtipo de PaymentMethod, Dart no cambia el tipo de la variable tras el is, y hay que convertirla con as Refundable para llamar a refund. La transferencia no es reembolsable y por eso no muestra esa línea.
Código · main.dart
// Abstract: cannot be instantiated, may leave methods without a body.abstract class PaymentMethod { String get name; int fee(int amount); // abstract: each subclass decides // Concrete method that every subclass inherits. String charge(int amount) => '$name: ${amount + fee(amount)} (fee ${fee(amount)})';}// A pure contract: whoever implements it must write every member.abstract interface class Refundable { String refund(int amount); }class Card extends PaymentMethod implements Refundable { @override String get name => 'Card'; @override int fee(int amount) => amount * 15 ~/ 1000 + 25; // 1.5 % + 25 @override String refund(int amount) => 'refunds $amount to the card';}class BankTransfer extends PaymentMethod { @override final String name = 'Transfer'; @override int fee(int amount) => 0;}// implements takes only the contract: nothing is inherited.class GiftCard implements PaymentMethod, Refundable { @override String get name => 'Gift card'; @override int fee(int amount) => 0; @override String charge(int amount) => '$name: $amount from the balance'; @override String refund(int amount) => 'adds $amount back to the gift card';}void main() { for (final PaymentMethod method in [Card(), BankTransfer(), GiftCard()]) { print(method.charge(4000)); if (method is Refundable) print(' ${(method as Refundable).refund(4000)}'); }}Salida · dart run main.dart
Card: 4085 (fee 85) refunds 4000 to the card Transfer: 4000 (fee 0) Gift card: 4000 from the balance adds 4000 back to the gift card
Para recordar
- Una clase
abstractno se instancia y puede dejar métodos sin cuerpo. extendshereda código;implementssolo obliga a cumplir el contrato.- Toda clase de Dart sirve también como interfaz.
- Una clase puede implementar varias interfaces a la vez.
iscomprueba si un objeto cumple una interfaz.
Ejercicio
Cree un método de pago MobileWallet que implemente PaymentMethod y Refundable, con una comisión fija de 10 céntimos, y añádalo a la lista.