Created
December 3, 2023 09:40
-
-
Save vicaba/cb01dce0c297f940e46d0f12bac6b032 to your computer and use it in GitHub Desktop.
Liskov Substitution Principle in Scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| case class User(name: String, email: String) | |
| val dummyUser = User("Dummy", "[email protected]") | |
| // Not using LSP | |
| object NotUsingLsp { | |
| trait UserRepository { | |
| def insert(user: User): Int | |
| def read(id: Int): User | |
| } | |
| class MysqlUserRepository extends UserRepository { | |
| def insert(user: User): Int = ??? | |
| def read(id: Int): User = ??? | |
| } | |
| class MongoDbUserRepository extends UserRepository { | |
| def insert(user: User): Int = ??? | |
| def read(id: Int): User = throw new Exception("This Mongo doesn't support read") | |
| } | |
| class MyController(userRepository: UserRepository) { | |
| userRepository.read(1) | |
| userRepository.insert(dummyUser) // 1. Will the insert work? | |
| // 2. If the injected repository is a MysqlUserRepository: we are good! | |
| // 3. If the injected repository is a MongoDbUserRepository: exception. | |
| // 4. Same interface, but: sometimes it works, sometimes it doesn't... | |
| } | |
| } | |
| // Using LSP | |
| object UsingLsp { | |
| // 1. We can seggregating interfaces, so we have more flexibility in the composition | |
| trait WriteUserRepository { | |
| def insert(user: User): Int | |
| } | |
| trait ReadUserRepository { | |
| def read(id: Int): User | |
| } | |
| class MysqlUserRepository extends WriteUserRepository with ReadUserRepository { | |
| def insert(user: User): Int = ??? | |
| def read(id: Int): User = ??? | |
| } | |
| class MongoDbUserRepository extends WriteUserRepository { | |
| def insert(user: User): Int = ??? | |
| } | |
| class MyController( | |
| readUserRepository: ReadUserRepository, | |
| writeUserRepository: WriteUserRepository | |
| ) { | |
| readUserRepository.read(1) | |
| writeUserRepository.insert(dummyUser) | |
| // 2. We are seggregating interfaces, so we have more flexibility in the composition | |
| } | |
| // 3. Or we can use intersection types! Here, the only valid implementation is Mysql | |
| class AnotherMyController(readAndWriteUserRepository: ReadUserRepository & WriteUserRepository) { | |
| readAndWriteUserRepository.read(1) | |
| readAndWriteUserRepository.insert(dummyUser) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment