S — The Single Responsibility Principle (SRP):
Bad
fun main() {
val users = listOf(User(name = "Android User", mobileNumbers = listOf("987654321", "9999999999")))
val adapter = Adapter(users)
}
class Adapter(private val users: List<User>) {
/** Calling onBindViewHolder here just for a demo purpose. In a RecyclerView adapter,
* onBindViewHolder will be triggered as part of adapter life cycle.
**/
init {
onBindViewHolder(0)
}
fun onBindViewHolder(position: Int) {
val user = users[position]
println("Name has been set as ${user.name} to TextView")
/**
* I didn't receive the proper data to display it in the UI..
* So let me convert it.
**/
val mobileNumber = user.mobileNumbers.joinToString()
println("Mobile numbers has been set as $mobileNumber to TextView")
}
}
data class User(val name: String, val mobileNumbers: List<String>)
Good
fun main() {
val users = listOf(User(name = "Android User", mobile = "987654321, 9999999999"))
val adapter = Adapter(users)
}
class Adapter(private val users: List<User>) {
/** Calling onBindViewHolder here just for a demo purpose,
* onBindViewHolder will be triggered as part of adapter life cycle.
**/
init {
onBindViewHolder(0)
}
fun onBindViewHolder(position: Int) {
val user = users[position]
println("Name has been set as ${user.name} to TextView")
println("Mobile number has been set as ${user.mobile} to TextView")
}
}
data class User(val name: String, val mobile: String)
O — The Open-Closed Principle (OCP)
Bad
fun main() {
val mileageCalculator = MileageCalculator()
mileageCalculator.showMileage(Car())
}
class MileageCalculator {
fun showMileage(anyView: Any) {
when {
anyView is Bike -> {
print(anyView.getBikeMileage())
}
anyView is Car -> {
print(anyView.getCarMileage())
}
}
}
}
class Bike {
fun getBikeMileage(): String = "50"
}
class Car {
fun getCarMileage(): String = "12"
}
Good
fun main() {
val mileageCalculator = MileageCalculator()
mileageCalculator.showMileage(Bike())
}
class MileageCalculator {
fun showMileage(vehicle: Vehicle) {
println(vehicle.getMileage())
}
}
interface Vehicle {
fun getMileage(): String
}
class Bike: Vehicle {
override fun getMileage(): String = "50"
}
class Car: Vehicle {
override fun getMileage(): String = "12"
}
L - The Liskov Substitution Principle (LSP)
Bad
fun main() {
val adapter = Adapter()
adapter.select(RadioButton())
}
class Adapter {
fun select(clickListener: ClickListener) {
when {
clickListener is ListItem -> {
clickListener.changeTheBackground()
}
clickListener is RadioButton -> {
clickListener.check()
}
}
clickListener.onClick(1)
}
}
interface ClickListener {
fun onClick(position: Int)
}
class ListItem: ClickListener {
override fun onClick(position: Int){
println("Clicked ListItem $position")
}
fun changeTheBackground() {
println("Change the background color of the item view")
}
}
class RadioButton: ClickListener {
override fun onClick(position: Int){
println("Clicked RadioButton $position")
}
fun check() {
println("Enable the radio button")
}
}
Good
fun main() {
val adapter = Adapter()
adapter.select(RadioButton())
}
class Adapter {
fun select(clickListener: ClickListener) {
clickListener.onClick(1)
}
}
interface ClickListener {
fun onClick(position: Int)
}
class ListItem: ClickListener {
override fun onClick(position: Int){
changeTheBackground()
println("Clicked ListItem $position")
}
fun changeTheBackground() {
println("Change the background color of the item view")
}
}
class RadioButton: ClickListener {
override fun onClick(position: Int){
check()
println("Clicked RadioButton $position")
}
fun check() {
println("Enable the radio button")
}
}
I — The Interface Segregation Principle (ISP):
Bad
fun main() {
val adapter = Adapter()
adapter(object: Adapter.OnClickListener {
override fun onItemClick(position: Int) {
// Yes, I have received a callback, go to the next activity.
println("Clicked position is $position")
}
override fun onRadioButtonClick(position: Int) {
// This is no longer needed for this activity, but still I have been implemented for no use...
}
})
adapter.execute()
}
class Adapter {
private var onClickListener: OnClickListener? =null
operator fun invoke (onClickListener: OnClickListener) {
this.onClickListener = onClickListener
}
fun execute() {
onClickListener?.onItemClick(4)
}
interface OnClickListener {
fun onItemClick(position: Int)
fun onRadioButtonClick(position: Int)
}
}
Good
fun main() {
val adapter = Adapter()
adapter(object: Adapter.OnItemClickListener {
override fun onItemClick(position: Int) {
// Yes, I have received a callback, go to the next activity.
println("Clicked position is $position")
}
})
adapter.execute()
}
class Adapter {
private var onItemClickListener: OnItemClickListener? =null
operator fun invoke (onItemClickListener: OnItemClickListener) {
this.onItemClickListener = onItemClickListener
}
fun execute() {
onItemClickListener?.onItemClick(4)
}
interface OnItemClickListener {
fun onItemClick(position: Int)
}
interface OnRadioClickListener {
fun onRadioButtonClick(position: Int)
}
}
D - The Dependency Inversion Principle (DIP)
Bad
fun main() {
val user = User()
user.getMyData(3)
}
class User {
fun getMyData(requestCode: Int) {
when (requestCode) {
1 -> {
val firebase = Firebase()
firebase.fetchData()
}
2 -> {
val restClient = RestClient()
restClient.fetchData()
}
else -> print("I dont care about the user. Don't do anything. Keep quiet!")
}
}
}
class Firebase {
fun fetchData(){
print("Syncing the data from the firebase storage")
}
}
class RestClient {
fun fetchData(){
print("Hitting the api and getting back the response")
}
}
Good
fun main() {
/* As a end user, I don't care about how will I retrieve the data.
* Do whatever you want and simply get my data.
*/
val user = User(dataFetcher = Firebase())
user.getMyData()
}
class User(private val dataFetcher: DataFetcher) {
fun getMyData() {
dataFetcher.fetchData()
}
}
interface DataFetcher {
fun fetchData()
}
class Firebase: DataFetcher {
override fun fetchData(){
print("Syncing the data from the firebase storage")
}
}
class RestClient: DataFetcher {
override fun fetchData(){
print("Hitting the api and getting back the response")
}
}