The Interface Segregation Principle states that code shouldn’t be forced to have methods it doesn’t need. Whenever a class implements an interface, it has to implement all its methods. What do you do when a new class appears to need some of the behaviors defined in an interface but not all? In this demo, you’ll learn how to solve this problem in your e-commerce app.
Start by opening the Kotlin playground in your browser. Download the course material from the GitHub link at the side of the video. Copy and paste the code from InterfaceSegregation.kts in the Starter folder for Lesson 4.
Currently, the app provides a UI feature that controls things a user can do in the app. Two main types of users are identified — kids and parents. Run the app:
Parent account viewing products...
Product added to the cart (Parent): Laptop
Parent account viewing cart...
Kids account viewing products...
Product added to the cart (Kids): Laptop
Kids account viewing cart...
This shows everything each type of user can do: view product, add to cart, and view cart. You need to add a new UI feature, except this feature only applies to parents: manage payment settings. Adding this behavior to the interface will make it available to kids too. But that’s not what you want. If you make it a no-op in the kids’ implementation, this violates the Interface Segregation Principle.
The way to solve this is to break the interface into smaller ones. First, break down UserInterface into ProductsViewable, CartViewable, and CartAddable interfaces:
interface ProductsViewable {
fun viewProducts()
}
interface CartViewable {
fun viewCart()
}
interface CartAddable {
fun addToCart(product: Product)
}
You can now pick and choose the exact behavior each type of user needs. Here’s how KidsAccount will look after this update:
class KidsAccount : ProductsViewable, CartViewable, CartAddable {
override fun viewProducts() {
println("Kids account viewing products...")
}
override fun addToCart(product: Product) {
println("Product added to the cart (Kids): ${product.name}")
}
override fun viewCart() {
println("Kids account viewing cart...")
}
}
Then, you can create the new behavior that was requested and have ParentAccount implement it in addition to the others. Create the new behavior with:
interface PaymentSettingsManageable {
fun managePaymentSettings()
}
And have ParentAccount implement PaymentSettingsManageable with the following code:
class ParentAccount : ProductsViewable, CartViewable, CartAddable, PaymentSettingsManageable {
override fun viewProducts() {
println("Parent account viewing products...")
}
override fun addToCart(product: Product) {
println("Product added to the cart (Parent): ${product.name}")
}
override fun viewCart() {
println("Parent account viewing cart...")
}
override fun managePaymentSettings() {
println("Parent account managePaymentSettings...")
}
}
That’s it. Uncomment the code below // TODO: Uncomment manage payment settings behavior to see the new behavior in action:
// TODO: Uncomment manage payment settings behavior
parentAccount.managePaymentSettings()
Rerun the app:
Parent account viewing products...
Product added to the cart (Parent): Laptop
Parent account viewing cart...
Parent account managePaymentSettings...
Kids account viewing products...
Product added to the cart (Kids): Laptop
Kids account viewing cart...
All done! You’ve applied the interface segregation principle to your e-commerce app. Now, proceed to last of the SOLID principles — Dependency Inversion.