Перший параграф цієї документації з програмування (на Android) буде присвячений принципам SOLID.
Принципи SOLID - це 5 правил, дотримування яких дозволить писати масштабований, тестувабельний та просто приємний код.
І так, кожен принцип відповідає за якусь літеру слова SOLID (мені від цього легше пам’ятати їх не було).
S - Single Responsibility
Кожен клас відповідає за одну функцію.
Навіщо? Читабельність, легша модифікація, тестувабельність
Приклад:
Кожен програміст стикався такою думкою (думкою людей непрограмістів), нібито програміст може ВСЕ: і сайт зробити, і на телефон накодити, і гру створити. В реальності ж, все не так) Тому і в нашому коді не повинно бути так.
class Programmer{
fun makeSite(){
println("Done")
}
fun makeMobile(){
println("I want more salary")
}
fun makeGame(){
println("Too much, I'm quit...")
}
}
class WebDeveloper(){
fun makeSite(){
println("Done")
}
}
class MobileDeveloper(){
fun makeMobileApp(){
println("Done")
}
}
class GameDeveloper(){
fun makeGame(){
println("Done")
}
}
O - Open/Closed
Відкритий для доповнення та модифікацій, закритий для змін.
Навіщо? Щоб не ламалося те, що й так працює (змінена функція в іншій частині коду, наприклад)
Приклад:
Уявимо будинок (в якому живуть люди) і в ньому є кімнати. Вочевидь, усі кімнати облаштовані: в спальні стоїть ліжко, на кухні - плита, у вітальні - диван. Але так сталося, що у вас немає ванної, що робити? Її можна розмітити в якійсь наявній кімнати, змінивши планування інших речей. Ідеальний варіант, звісно, добудувати окрему кімнатку і поставити туди ванну. Хоч в житті таке зробити непросто, але в коді легко.
class MyHouse(){
fun kitchen(){
println("My favourite room")
}
fun office(){
println("Just working here...")
}
fun bedroom(){
println("Chillin, readin, sleepin")
}
}
fun MyHouse.bathroom(){
println("Forgot about this thing)")
}
L - Liskov Substitution
Нехай клас B є нащадком класу А, тоді він повинен бути замінюваним класом А.
Навіщо? Запобігання порушення поліморфізму та коректне наслідування
Приклад:
Давайте пограємо в дитячу гру. Я називаю категорію, а ви називаєте предмети, які їй належать. Що ж, слово “транспорт”.
Ви молодці! (навіть, якщо ви мовчали). До транспорта, звісно, відноситься: автівка, велосипед, потяг, літак, кінь… А що спільного? Воно рухається, там можуть бути люди. В подальшому в програмуванні ви теж мусите грати в цю гру - описуючи клас “транспорт” і нащадків у вигляді “авто”, “велосипед” і т.д. будь-який з нащадків повинен безпомилково працювати там, де необхідний клас “транспорт”.
interface MotorVehicle{
fun startEngine()
}
open class Vehicle {
open fun move(){
println("The vehicle is moving")
}
}
class Car: Vehicle(), MotorVehicle{
override fun startEngine() {
println("Start the engine")
}
}
class Bicycle: Vehicle(){
override fun move() {
println("The bicycle is moving by pedaling")
}
}
I - Interface Segregation
Принцип схожий з першим, розділення логіки, яка може бути притаманна одному об’єкту в кілька різних інтерфейсів. Тобто, класи не повинні використовувати логіку в інтерфейсах, яка їм не потрібна.
Навіщо? Менше сміттєвого коду (класи не реалізовуватимуть непотрібну логіку)
Приклад:
Давайте поностальгуємо. От ви пам’ятаєте ті часи, коли в людей був будильник, паперовий календар, цифрова камера? В кожного з цих предметів були свої функції та своя певна задача. Зараз же ми маємо смартфони - невеликий пристрій, який об’єднує всі, вище названі речі, в одному. Якби ми написали цей абзац кодом, він би реалізовував принцип сегрегації інтерфейсів.
interface Camera{
fun makePhoto()
fun recordVideo()
}
interface Computer{
fun openProgram()
fun typing()
}
class Smartphone: Camera, Computer{
override fun makePhoto() {
println("Just make a photo")
}
override fun recordVideo() {
println("Just record a video")
}
override fun openProgram() {
println("Open by TOUCH")
}
override fun typing() {
println("Typing by TOUCHES")
}
}
D - Dependency Inversion
Класи повинні залежати від абстрактних класів або інтерфейсів. Тобто, не бути залежними від класів з конкретною реалізацією.
Навіщо? Тестувабельність (підстановка імітацій), ґнучкість (підстановка різних реалізацій)
Приклад:
Зараз ходить тема блокування телеграму, ви чули? Вже думали, на що перейти? Чи може, створимо новий месенджер? А з чого ви б почали?
Я би спочатку описав увесь необхідний функціонал: відправка повідомлень, можливість дзвінків, сповіщення і т.д. А тепер запишемо цей план мовою Kotlin.
interface Messenger{
fun sendMessage()
//TODO
}
class Telegram: Messenger{
override fun sendMessage() {
println("Sending message...")
}
}
class WorkinSystem{
val messenger: Messenger = Telegram()
fun makeTicket(){
println("Send a ticket via ${messenger.javaClass}")
}
}
Що ж, вітаю, ваша концентрація вражає, ви дочитали цю статтю і збагатилися фундаментальними знаннями, які вам точно стануть в нагоді (звісно, якщо ви писатимете код :)
Discorbit