Перший параграф цієї документації з програмування (на 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

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Discorbit
Discorbit@discorbit

Про Android розробку

13Прочитань
0Автори
1Читачі
На Друкарні з 10 жовтня

Вам також сподобається

Коментарі (1)

Я PHP розробник, котрому завжди подобалися мови з повноцінним ООП не в теорії, а в реалізації. А kotlin взагалі весела мова.. там стільки fun в середині))

Вам також сподобається