Abstract and Interface Classes

 Abstract and Interface Classes cannot be instantiated on their own, which means you cannot create objects of those types yet. 

Abstract class starts with abstract keyword

we need to provide subclasses that implement its missing functionality

The difference is that abstract classes have constructors while interfaces can not have any constructor logic.

Both interfaces and abstract classes can contain implementations of methods.

On interfaces, we call them default implementations.

The big difference really is in when and how you use them:

- Use an interface if you have a lot of methods and one or two default implementations like this: 

interface AquariumAction {
fun eat()
fun jump()
fun clean()
fun catchFish()
fun swim(){
println("swim")
}
}

- Use an abstract class anytime you can not complete a class

interface FishAction {
fun eat()
}
abstract class AquariumFish : FishAction {
abstract val color: String  // This is abstract because there isn't a default fish color
override fun eat() {
println("yum")          // Default implementation for eat
}
}




A final thing that you can do in Kotlin,  when using classes that implement interfaces, is create objects where you specify that the only thing you can do with them is what's defined in the interface.

When you have a lot of classes, this can help you keep clearer and more organized.

Example using interface and abstract classes: 

Main.kt

// File:            Main.kt
// Programmer: Engineer Nolverto Urias Obeso
// Creation Date: 06/18/2023
// Email: nolvertou@gmail.com
// Description: Learning how to use interface and abstract classes

fun main() {
makeFish()
}

fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()

println("Shark: ${shark.color}, Plecostomus: ${pleco.color}")

shark.eat()
pleco.eat()
}

Abstract Class:

abstract class AquariumFish : FishAction {
abstract val color: String  // This is abstract because there isn't a default fish color
override fun eat() {
println("yum")          // Default implementation for eat
}
}

Interface

interface FishAction {
fun eat()
}


Shark Class that uses Abstract class and interface

class Shark: AquariumFish(), FishAction{
override val color = "gray"
override fun eat() {
println("Hunt and eat fish")
}
}

Plecostomus Class that uses Abstract class and interface

class Plecostomus: AquariumFish(), FishAction {
override val color = "gold"
override fun eat() {
println("Much on algae")
}
}

Output: 

Shark: gray, Plecostomus: gold
Hunt and eat fish
Much on algae


Kotlin provides us a better tool for this than abstract classes: Interface delegation. 

Interface delegation let's you add features to a class via composition.

Composition is when you use an instance of another class as opposed to inheriting from it. Instrad of requiring the callers subclass, a giant abstract class, give them a smaller interface, and let them delegate those interfaces to an object. This sounds pretty abstract hehe.

Interface delegation is really powerfull, and you should generally consider how to use it whenever you might use an abstract class in another language.

It let's you use composition to plug-on behaviors, instead of requiring a lot of subclasses, each specialized in different way 


Interface Delegation Example: 

Main.kt

// File:            Main.kt
// Programmer: Engineer Nolverto Urias Obeso
// Creation Date: 06/18/2023
// Email: nolvertou@gmail.com
// Description: Using an interface delegation to provide a color implementation

fun main(args: Array<String>) {
delegate()
}

fun delegate() {
val pleco = Plecostomus()
println("Fish has color ${pleco.color}")
pleco.eat()
}

Plecostomus Class

class Plecostomus(fishColor: FishColor = GoldColor):
FishAction by PrintingFishAction("a lot of algae"),
FishColor by fishColor { // This means implement the interface FishColor by deferring all calls to the object GoldColor
// So every time you call the color property on this class
// It will actually call the color property on GoldColor by default
// override fun eat(){
// println("eat algae")
// }
}

FishAction Interface

interface FishAction {
fun eat()
}

PrintingFishAction Class

class PrintingFishAction(val food: String): FishAction {
override fun eat() {
println(food)
}
}


FishColor Interface

interface FishColor {
val color: String
}

GoldColor Object

// Kotlin let's us declare a class where we can only have
// one instance by using the keyword "object" instead of "class"
// This will declare a class and make exactly one instance of it,
// the instance will be called GoldColor and there is NO way to make
// another instance of this class.
// If you are familiar with the Singleton Patern, this how to implement it in Kotlin

// To do the interface delegation we need an object that knows how to provide a FishColor
object GoldColor: FishColor {
override val color = "gold"

}

RedColor Object

// To do the interface delegation we need an object that knows how to provide a FishColor
object RedColor: FishColor {
override val color = "red"
}

 








Comments

Popular posts from this blog