Understanding Polymorphism in Swift: A Comprehensive Guide
Polymorphism → Many Forms
Polymorphism, a cornerstone of object-oriented programming, empowers developers to write flexible and reusable code. In the realm of Swift, this concept takes center stage, offering a myriad of tools such as inheritance, protocols, and generics. In this article, we’ll embark on a savory exploration of polymorphism using a delectable analogy: burgers.
Example: The Burger Hierarchy
Consider a class hierarchy where Burger
is the parent class, and various burger types are represented by subclasses. Each burger type inherits core attributes from the parent class but adds its unique twist.
class Burger {
var name: String
var patty: String
var toppings: [String]
init(name: String, patty: String, toppings: [String]) {
self.name = name
self.patty = patty
self.toppings = toppings
}
func describe() {
print("A \(name) with \(patty) patty and toppings: \(toppings.joined(separator: ", "))")
}
}
class Cheeseburger: Burger {
var cheeseType: String
init(name: String, patty: String, toppings: [String], cheeseType: String) {
self.cheeseType = cheeseType
super.init(name: name, patty: patty, toppings: toppings)
}
// Overriding the describe method
override func describe() {
print("A \(name) with \(patty) patty, toppings: \(toppings.joined(separator: ", ")), and \(cheeseType) cheese.")
}
}
class VeggieBurger: Burger {
var veggiePatty: String
init(name: String, toppings: [String], veggiePatty: String) {
self.veggiePatty = veggiePatty
super.init(name: name, patty: "Veggie", toppings: toppings)
}
// Overriding the describe method
override func describe() {
print("A \(name) with Veggie patty, toppings: \(toppings.joined(separator: ", "))")
}
}
In this example, Burger
is the generic parent class, while Cheeseburger
and VeggieBurger
are specialized subclasses. Each subclass inherits the core properties of a burger but introduces additional features.
Let’s instantiate and use these burger classes to witness polymorphism in action.
// Creating instances of different burger types
let classicBurger = Burger(name: "Classic Burger", patty: "Beef", toppings: ["Lettuce", "Tomato", "Onion"])
let cheesyDelight = Cheeseburger(name: "Cheesy Delight", patty: "Beef", toppings: ["Bacon", "Pickles"], cheeseType: "Cheddar")
let veggieDelight = VeggieBurger(name: "Veggie Delight", toppings: ["Avocado", "Sprouts"], veggiePatty: "Black Bean")
// Using polymorphism: Storing different burger types in an array
let allBurgers: [Burger] = [classicBurger, cheesyDelight, veggieDelight]
// Iterating through the array and invoking the describe method
for burger in allBurgers {
burger.describe()
}
In the above code, the array allBurgers
contains instances of different burger types, demonstrating the beauty of polymorphism. The describe
method is called on each burger, and thanks to dynamic dispatch, the overridden describe
methods in the subclasses are invoked, showcasing the unique characteristics of each burger type.
Example : The Animal Kingdom
Consider a hierarchy where Animal
serves as the base class, and various animal types are represented by subclasses. Each animal exhibits unique characteristics, and through polymorphism, we can encapsulate their shared behaviors.
class Animal {
var name: String
var sound: String
init(name: String, sound: String) {
self.name = name
self.sound = sound
}
func makeSound() {
print("\(name) says: \(sound)")
}
}
class Lion: Animal {
override init(name: String) {
super.init(name: name, sound: "Roar")
}
// Additional lion-specific methods or properties can be added here
}
class Penguin: Animal {
override init(name: String) {
super.init(name: name, sound: "Honk")
}
// Additional penguin-specific methods or properties can be added here
}
class Elephant: Animal {
override init(name: String) {
super.init(name: name, sound: "Trumpet")
}
// Additional elephant-specific methods or properties can be added here
}
In this example, Animal
is the generic superclass, and Lion
, Penguin
, and Elephant
are specialized subclasses. Each subclass inherits the common properties and behaviors from Animal
but introduces its unique characteristics.
Now, let’s create instances of these animals and observe the magic of polymorphism in action:
// Creating instances of different animals
let simba = Lion(name: "Simba")
let skipper = Penguin(name: "Skipper")
let dumbo = Elephant(name: "Dumbo")
// Using polymorphism: Storing different animals in an array
let zoo: [Animal] = [simba, skipper, dumbo]
// Iterating through the array and invoking the makeSound method
for animal in zoo {
animal.makeSound()
}
In this code snippet, the array zoo
contains instances of different animals. Through polymorphism, we can treat all these animals uniformly, calling the makeSound
method on each one. Thanks to dynamic dispatch, the overridden makeSound
methods in the subclasses are invoked, showcasing the distinct sounds of lions, penguins, and elephants.
“Those were some examples to let you understand what polymorphism is “
If you found this blog helpful or have any questions, feel free to reach out to me on social media:
- YouTube: ElAmir’s YouTube Channel
- Facebook: ElAmir’s Facebook Page
- LinkedIn: Connect with ElAmir on LinkedIn
- Twitter: Follow ElAmir on Twitter
- Udemy: ElAmir’s Udemy Profile
I look forward to connecting with you and exploring more about Enums in Swift together! Thanks for reading.