├── LICENSE ├── README.md └── _config.yml /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## S — The Single Responsibility Principle (SRP): 2 | 3 | ### Bad 4 | 5 | ```kotlin 6 | fun main() { 7 | val users = listOf(User(name = "Android User", mobileNumbers = listOf("987654321", "9999999999"))) 8 | val adapter = Adapter(users) 9 | } 10 | 11 | class Adapter(private val users: List) { 12 | 13 | /** Calling onBindViewHolder here just for a demo purpose. In a RecyclerView adapter, 14 | * onBindViewHolder will be triggered as part of adapter life cycle. 15 | **/ 16 | init { 17 | onBindViewHolder(0) 18 | } 19 | 20 | fun onBindViewHolder(position: Int) { 21 | val user = users[position] 22 | 23 | println("Name has been set as ${user.name} to TextView") 24 | 25 | /** 26 | * I didn't receive the proper data to display it in the UI.. 27 | * So let me convert it. 28 | **/ 29 | val mobileNumber = user.mobileNumbers.joinToString() 30 | 31 | println("Mobile numbers has been set as $mobileNumber to TextView") 32 | } 33 | } 34 | 35 | 36 | data class User(val name: String, val mobileNumbers: List) 37 | ``` 38 | 39 | ### Good 40 | 41 | ```kotlin 42 | 43 | fun main() { 44 | val users = listOf(User(name = "Android User", mobile = "987654321, 9999999999")) 45 | val adapter = Adapter(users) 46 | } 47 | 48 | class Adapter(private val users: List) { 49 | 50 | /** Calling onBindViewHolder here just for a demo purpose, 51 | * onBindViewHolder will be triggered as part of adapter life cycle. 52 | **/ 53 | init { 54 | onBindViewHolder(0) 55 | } 56 | 57 | fun onBindViewHolder(position: Int) { 58 | val user = users[position] 59 | 60 | println("Name has been set as ${user.name} to TextView") 61 | println("Mobile number has been set as ${user.mobile} to TextView") 62 | } 63 | } 64 | 65 | 66 | data class User(val name: String, val mobile: String) 67 | ``` 68 | ## O — The Open-Closed Principle (OCP) 69 | 70 | ### Bad 71 | 72 | ```kotlin 73 | fun main() { 74 | val mileageCalculator = MileageCalculator() 75 | mileageCalculator.showMileage(Car()) 76 | } 77 | 78 | class MileageCalculator { 79 | 80 | fun showMileage(anyView: Any) { 81 | when { 82 | anyView is Bike -> { 83 | print(anyView.getBikeMileage()) 84 | } 85 | anyView is Car -> { 86 | print(anyView.getCarMileage()) 87 | } 88 | } 89 | } 90 | } 91 | 92 | 93 | class Bike { 94 | fun getBikeMileage(): String = "50" 95 | } 96 | 97 | class Car { 98 | fun getCarMileage(): String = "12" 99 | } 100 | ``` 101 | 102 | ### Good 103 | 104 | ```kotlin 105 | fun main() { 106 | val mileageCalculator = MileageCalculator() 107 | mileageCalculator.showMileage(Bike()) 108 | } 109 | 110 | class MileageCalculator { 111 | 112 | fun showMileage(vehicle: Vehicle) { 113 | println(vehicle.getMileage()) 114 | } 115 | } 116 | 117 | interface Vehicle { 118 | fun getMileage(): String 119 | } 120 | 121 | class Bike: Vehicle { 122 | override fun getMileage(): String = "50" 123 | } 124 | 125 | class Car: Vehicle { 126 | override fun getMileage(): String = "12" 127 | } 128 | ``` 129 | 130 | ## L - The Liskov Substitution Principle (LSP) 131 | 132 | ### Bad 133 | ```kotlin 134 | fun main() { 135 | val adapter = Adapter() 136 | adapter.select(RadioButton()) 137 | } 138 | 139 | class Adapter { 140 | 141 | fun select(clickListener: ClickListener) { 142 | when { 143 | clickListener is ListItem -> { 144 | clickListener.changeTheBackground() 145 | } 146 | 147 | clickListener is RadioButton -> { 148 | clickListener.check() 149 | } 150 | } 151 | clickListener.onClick(1) 152 | } 153 | } 154 | 155 | interface ClickListener { 156 | fun onClick(position: Int) 157 | } 158 | 159 | class ListItem: ClickListener { 160 | override fun onClick(position: Int){ 161 | println("Clicked ListItem $position") 162 | } 163 | 164 | fun changeTheBackground() { 165 | println("Change the background color of the item view") 166 | } 167 | 168 | } 169 | 170 | class RadioButton: ClickListener { 171 | override fun onClick(position: Int){ 172 | println("Clicked RadioButton $position") 173 | } 174 | 175 | fun check() { 176 | println("Enable the radio button") 177 | } 178 | } 179 | ``` 180 | 181 | ### Good 182 | 183 | ```kotlin 184 | fun main() { 185 | val adapter = Adapter() 186 | adapter.select(RadioButton()) 187 | } 188 | 189 | class Adapter { 190 | 191 | fun select(clickListener: ClickListener) { 192 | clickListener.onClick(1) 193 | } 194 | } 195 | 196 | interface ClickListener { 197 | fun onClick(position: Int) 198 | } 199 | 200 | class ListItem: ClickListener { 201 | override fun onClick(position: Int){ 202 | changeTheBackground() 203 | println("Clicked ListItem $position") 204 | } 205 | 206 | fun changeTheBackground() { 207 | println("Change the background color of the item view") 208 | } 209 | 210 | } 211 | 212 | class RadioButton: ClickListener { 213 | override fun onClick(position: Int){ 214 | check() 215 | println("Clicked RadioButton $position") 216 | } 217 | 218 | fun check() { 219 | println("Enable the radio button") 220 | } 221 | } 222 | ``` 223 | ## I — The Interface Segregation Principle (ISP): 224 | 225 | ### Bad 226 | ```kotlin 227 | fun main() { 228 | val adapter = Adapter() 229 | adapter(object: Adapter.OnClickListener { 230 | override fun onItemClick(position: Int) { 231 | // Yes, I have received a callback, go to the next activity. 232 | println("Clicked position is $position") 233 | } 234 | override fun onRadioButtonClick(position: Int) { 235 | // This is no longer needed for this activity, but still I have been implemented for no use... 236 | } 237 | 238 | }) 239 | adapter.execute() 240 | } 241 | 242 | class Adapter { 243 | 244 | private var onClickListener: OnClickListener? =null 245 | 246 | operator fun invoke (onClickListener: OnClickListener) { 247 | this.onClickListener = onClickListener 248 | } 249 | 250 | fun execute() { 251 | onClickListener?.onItemClick(4) 252 | } 253 | 254 | interface OnClickListener { 255 | fun onItemClick(position: Int) 256 | fun onRadioButtonClick(position: Int) 257 | } 258 | } 259 | 260 | ``` 261 | ### Good 262 | 263 | ```kotlin 264 | fun main() { 265 | val adapter = Adapter() 266 | adapter(object: Adapter.OnItemClickListener { 267 | override fun onItemClick(position: Int) { 268 | // Yes, I have received a callback, go to the next activity. 269 | println("Clicked position is $position") 270 | } 271 | }) 272 | adapter.execute() 273 | } 274 | 275 | class Adapter { 276 | 277 | private var onItemClickListener: OnItemClickListener? =null 278 | 279 | operator fun invoke (onItemClickListener: OnItemClickListener) { 280 | this.onItemClickListener = onItemClickListener 281 | } 282 | 283 | fun execute() { 284 | onItemClickListener?.onItemClick(4) 285 | } 286 | 287 | interface OnItemClickListener { 288 | fun onItemClick(position: Int) 289 | } 290 | 291 | interface OnRadioClickListener { 292 | fun onRadioButtonClick(position: Int) 293 | } 294 | 295 | } 296 | ``` 297 | 298 | ## D - The Dependency Inversion Principle (DIP) 299 | 300 | ### Bad 301 | ```kotlin 302 | fun main() { 303 | val user = User() 304 | user.getMyData(3) 305 | } 306 | 307 | class User { 308 | 309 | fun getMyData(requestCode: Int) { 310 | when (requestCode) { 311 | 1 -> { 312 | val firebase = Firebase() 313 | firebase.fetchData() 314 | } 315 | 2 -> { 316 | val restClient = RestClient() 317 | restClient.fetchData() 318 | } 319 | else -> print("I dont care about the user. Don't do anything. Keep quiet!") 320 | } 321 | 322 | } 323 | } 324 | 325 | class Firebase { 326 | fun fetchData(){ 327 | print("Syncing the data from the firebase storage") 328 | } 329 | } 330 | 331 | class RestClient { 332 | fun fetchData(){ 333 | print("Hitting the api and getting back the response") 334 | } 335 | } 336 | ``` 337 | ### Good 338 | ```kotlin 339 | fun main() { 340 | /* As a end user, I don't care about how will I retrieve the data. 341 | * Do whatever you want and simply get my data. 342 | */ 343 | val user = User(dataFetcher = Firebase()) 344 | user.getMyData() 345 | } 346 | 347 | class User(private val dataFetcher: DataFetcher) { 348 | 349 | fun getMyData() { 350 | dataFetcher.fetchData() 351 | } 352 | } 353 | 354 | interface DataFetcher { 355 | fun fetchData() 356 | } 357 | 358 | class Firebase: DataFetcher { 359 | override fun fetchData(){ 360 | print("Syncing the data from the firebase storage") 361 | } 362 | } 363 | 364 | class RestClient: DataFetcher { 365 | override fun fetchData(){ 366 | print("Hitting the api and getting back the response") 367 | } 368 | } 369 | ``` 370 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman --------------------------------------------------------------------------------