Domina la herencia en Swift con ejemplos claros: aprende a sobrescribir métodos y propiedades con override, a combinar resultados con super, a usar observers como didSet para lógica reactiva y a proteger APIs con final para evitar cambios en subclases. Todo con el caso de Vehicle, Train, Car y AutomaticCar.
¿Cómo funciona la sobrescritura en Swift?
Sobrescribir en Swift implica redefinir en la subclase lo que la clase padre ya tiene. Con la palabra reservada override indicas que tu implementación reemplaza la del padre y será la que se ejecute.
Usa override en métodos y propiedades computadas.
Lo del padre no se ejecuta, a menos que invoques super.
Si la subclase no implementa override, hereda el comportamiento del padre.
¿Qué cambia al sobrescribir métodos como makeNoise?
En el ejemplo, el tren redefine el sonido con override. Así el método del hijo se ejecuta en lugar del del padre.
classVehicle{var currentSpeed:Double=0.0var description:String{"Viajando a \(currentSpeed) kilómetros por hora"}funcmakeNoise(){print("El ruido depende del vehículo")}}classTrain:Vehicle{overridefuncmakeNoise(){print("chu, chu")}}let train =Train()train.makeNoise()// chu, chu
Idea clave:override sustituye la implementación del padre.
Si otra subclase, como Tandem, no hace override, ejecuta la del padre: "El ruido depende del vehículo".
¿Qué sucede si no hay override en la subclase?
El método del padre se utiliza sin cambios.
Útil cuando varias subclases comparten el mismo comportamiento base.
Puedes decidir si una subclase reutiliza al padre o añade su propia lógica.
¿Cómo sobrescribir properties, getters/setters y observers?
Además de métodos, puedes sobrescribir propiedades computadas y sus getters/setters, e incluso observers como didSet, para ajustar la lógica cuando cambia el estado.
¿Cómo combinar super.description con información extra?
El coche añade una propiedad gear y enriquece la descripción usando super.description.
classCar:Vehicle{var gear:Int=1overridevar description:String{returnsuper.description +" en la marcha \(gear)"}}let car =Car()car.currentSpeed =55car.gear =3print(car.description)// Viajando a 55 kilómetros por hora en la marcha 3
Patrón común: toma lo del padre con super y agrega contexto propio.
Mantiene coherencia y evita duplicar lógica.
¿Cómo ajustar gear automáticamente con didSet?
El coche automático calcula la marcha en función de la velocidad con un observer.
classAutomaticCar:Car{overridevar currentSpeed:Double{didSet{ gear =Int(currentSpeed /15.0)+1}}}let automatic =AutomaticCar()automatic.currentSpeed =35print(automatic.description)// ... en la marcha 3automatic.currentSpeed =55print(automatic.description)// ... en la marcha 4automatic.currentSpeed =65print(automatic.description)// ... en la marcha 5
Lógica reactiva:didSet responde a cambios en tiempo real.
Fórmula simple y legible: velocidad/15.0 más 1.
¿Cómo evitar que una subclase sobrescriba con final?
Cuando no quieres que una API cambie en herencias, marca métodos o propiedades como final. Así, ninguna subclase podrá sobrescribirlos.
¿Qué implica marcar una property como final?
Si el tren fija un dato que no debe cambiar en subclases, usa final.
classTrain:Vehicle{finalvar numberOfWagons:Int=0overridefuncmakeNoise(){print("chu, chu")}}classRailway:Train{// override var numberOfWagons: Int = 10// Error: property does not override any property from its superclass}
Protección de diseño:final impide cambios indeseados en herencia.
Aplica a métodos, propiedades, subscripts y también a métodos estáticos declarados con class.
¿Te gustaría ver más variantes con Bicycle o Tandem y decidir cuándo usar el del padre o su propio override? Cuéntame en comentarios qué implementarías y por qué.
Esta clase te hace reflexionar que antes de ponerte a codear busques maquetear como podrías hacerlo.
Quizá eso mejore tu productividad y calidad de código.
Exactamente, esa es la finalidad del diagrama de clases
Interesante esto en otros lenguajes se llama sobrecarga de funciones.
No, exactamente. La sobrecarga de funciones (y en el caso de POO la sobrecarga de métodos )permite escribir y utilizar múltiples funciones con el mismo nombre, pero con diferente lista de argumentos.
Mientras que en la sobre-escritura no cambias los argumentos
Se le puede aplicar el final a la propia clase para que esta no tenga propiedad de herencia ?
import UIKit
class Vehiculo{
var currentSpeed=0.0
var description:String{
return "Viajanda a (currentSpeed) km/h"
}
func makeNoise(){
print( "El ruido depende del vehiculo")
}
}
let someVehicle=Vehiculo()
print(someVehicle.description)
// herencia
class Bicyclew:Vehiculo{
var hasBasket=false
override func makeNoise() {
print("El ruido de este vehiculo es Glin Glin")
}
}
//herencia de hijo-- y este hereda de su padre
class Tandem:Bicyclew{
var currrentNumberOfPassangers=0
}
let tandem=Tandem()
tandem.hasBasket=true
tandem.currentSpeed=22.0
tandem.currrentNumberOfPassangers=2
print(" (tandem.description) y su cantidad de pasajeros es (tandem.currrentNumberOfPassangers)")
// override metodos padre
class Train:Vehiculo{
var numberOfWagones=0
override func makeNoise() {
print("Chooooo Chooooooo")
}
}
let train=Train()
train.makeNoise()
tandem.makeNoise()
didSet es un observador de propiedad en Swift que se ejecuta inmediatamente después de que se establece un nuevo valor en una propiedad. Se utiliza para realizar acciones adicionales cada vez que se cambia el valor de la propiedad. Por ejemplo, podrías usar didSet para actualizar la interfaz de usuario o realizar cálculos relacionados con el nuevo valor.
var score:Int=0{didSet{print("El puntaje ha cambiado a \(score)")}}
En este ejemplo, cada vez que score se actualiza, se imprime un mensaje con el nuevo valor. Esto es útil para rastrear cambios y reaccionar ante ellos.
Algo curioso es que con la palabra final evitamos que una clase hija sobreescriba variables, metodos etc.
Pero si intentamos asignarle un valor a esa variable final desde la instancia y no desde la definicion de la nueva clase, si se puede sobreescribir.
Ejemplo:
classVehicle{varcolor:String=""varcurrentSpeed:Double=0.0 final varbrand:String="Renault"}var myVehicle =Vehicle()myVehicle.brand="Honda"// no da error y asigna correctamente el nuevo valor.