https://github.com/jrvansuita/solidkotlin
SOLID study using Kotlin π¨βπ«
https://github.com/jrvansuita/solidkotlin
codelab kotlin solid study
Last synced: about 1 year ago
JSON representation
SOLID study using Kotlin π¨βπ«
- Host: GitHub
- URL: https://github.com/jrvansuita/solidkotlin
- Owner: jrvansuita
- Created: 2022-07-21T01:59:39.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2022-07-27T01:00:37.000Z (almost 4 years ago)
- Last Synced: 2025-03-21T16:24:30.196Z (about 1 year ago)
- Topics: codelab, kotlin, solid, study
- Language: Kotlin
- Homepage:
- Size: 86.9 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# [Solid](https://simple.wikipedia.org/wiki/SOLID_(object-oriented_design)) Principles using Kotlin
S.O.L.I.D. an acronym of a group of five good principles in object-oriented programming.
Here are some classes I've implemented to study every SOLID principle using Kotlin.
- **S** ingle Responsibility Principle (known as SRP)
- **O** pen/Closed Principle
- **L** iskovβs Substitution Principle
- **I** nterface Segregation Principle
- **D** ependency Inversion Principle
> *This is my pont-of-view, my understanding about the principles. It's my personal study shared on github.*
-------
### Study
- [**S**ingle Responsibility ](/src/main/kotlin/SingleResponsibility.kt)
```kotlin
//A class should have only one reason to exists and responsible for one thing.
class SingleResponsibility {
/* β Violation Example */
//This class handles way too much
class SessionHandler {
fun startSession(user: User) = println("Starting ${user.name} session with ${user.id} id.")
fun activateUserAccount(user: User) = println("Activating ${user.name}.")
fun checkAccessRights(user: User) = println("Checking ${user.name} access.")
}
/* β
Correct Example */
//Now we can clearly see that each class is responsible for exactly one thing
class Session {
fun start(user: User) = println("Starting ${user.name} session with ${user.id} id.")
}
class UserAccount {
fun activate(user: User) = println("Activating ${user.name}.")
}
class AccessRights {
fun check(user: User) = println("Checking ${user.name} access.")
}
}
```
- [**O**penβClosed ](/src/main/kotlin/OpenClose.kt)
```kotlin
//Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
class OpenClose {
/* β Violation Example */
// Will to work only with MySqlConnection
class DataBase {
private val connection = MySqlConnection("any")
fun connect() = println("Connect to Database using ${connection.uri}")
}
/* β
Correct Example */
//Extending and provide any implementation of Connection. It can be MySql, Firebird, Oracle, Sql Server, etc...
open class DataBase(private val connection: Connection) {
fun connect() = println("Connect to Database using ${connection.uri}")
}
}
```
- [**L**iskov Substitution ](/src/main/kotlin/LiskovSubstitution.kt)
```kotlin
// All classes deriving from the base class should behave in the same manner as the superclass.
// If we decide to replace the base class with the derived one, it should not break the existing functionality.
class LiskovSubstitution {
interface Animal {
fun walk()
fun fly()
}
/* β Violation Example */
//Dog and Goose are animals, but Dog can't fly! Will break fly implementation.
class Dog : Animal {
override fun walk() = println("The dog is walking")
override fun fly() = throw RuntimeException("The dog is not able to fly!")
}
class Goose : Animal {
override fun walk() = println("The goose is walking")
override fun fly() = println("The goose is flying")
}
/* β
Correct Example */
//Cat is not a fowl, so it doesn't fly. Won't break fly implementation.
interface Animals {
fun walk()
}
interface Fowls : Animals {
fun fly()
}
class Cat : Animals {
override fun walk() = println("The cat is walking")
}
class Duck : Fowls {
override fun walk() = println("The duck is walking")
override fun fly() = println("The duck is flying")
}
}
```
- [**I**nterface Segregation ](/src/main/kotlin/InterfaceSegregation.kt)
```kotlin
//Many client-specific interfaces are better than one general-purpose interface
class InterfaceSegregation {
/* β Violation Example */
// An interface that handles a lot of responsibility is a violation of this principle
interface Database {
fun insert()
fun update()
fun updateById()
fun delete()
fun select()
fun selectAll()
fun selectById()
}
/* β
Correct Example */
// Break this interface as much as need to distinct all the purposes
interface ReadDatabase {
fun select()
fun selectAll()
fun selectById()
}
interface WriteDatabase {
fun insert()
fun update()
fun updateById()
fun delete()
}
}
```
- [**D**ependency Inversion ](/src/main/kotlin/DependencyInversion.kt)
```kotlin
//Depend upon abstractions, not your own implementation.
class DependencyInversion {
/* β Violation Example */
// The message is being formatted inside send method
class EmailService {
fun send(message: String) {
val formattedMessage = "Email: ${message.uppercase()}"
println("Sending formatted message: $formattedMessage")
}
}
/* β
Correct Example */
// The message is being formatted outside send method. You just inverted the formatting dependency.
class EmailService {
fun send(message: String, formatter: (String) -> String) {
val formattedMessage = formatter.invoke(message)
println("Sending formatted message: $formattedMessage")
}
}
}
```
### References
- Raj Suvariya [@medium.com](https://medium.com/mindorks/solid-principles-explained-with-examples-79d1ce114ace)
- Vijay Mishra [@medium.com](https://medium.com/the-android-caf%C3%A9/solid-principles-the-kotlin-way-ff717c0d60da)
- Samuel Oloruntoba [@digitalocean.com/community](https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design)