Реалізація суцільних принципів у розробці Android


Програмне забезпечення для написання – це акт створення, і розробка не є винятком. Йдеться про більше, ніж просто зробити щось працювати. Йдеться про розробку додатків, які можуть з часом рости, адаптуватися та залишатися керованими.

Як розробник Android, який зіткнувся з незліченною кількістю архітектурних проблем, я виявив, що дотримання суцільних принципів може перетворити навіть найбільш заплутані кодові бази в чисті системи. Це не абстрактні принципи, але орієнтовані на результати та відтворювані способи написання надійного, масштабованого та реконструкції коду.

Ця стаття дасть розуміння того, як можна застосувати суцільні принципи до розробки Android за допомогою прикладів реального світу, практичних методик та досвіду з боку команди .

Суцільні принципи, запропоновані Робертом К. Мартіном,-це п’ять принципів дизайну для об’єктно-орієнтованого програмування, які гарантують чисту та ефективну архітектуру програмного забезпечення.

  • Принцип єдиної відповідальності (SRP): Клас повинен мати одну і лише одну причину для зміни.
  • Відкритий/закритий принцип (OCP): Суб’єкти програмного забезпечення повинні бути відкритими для розширення, але закрито для модифікації.
  • Принцип заміни Ліскова (LSP): Підтипи повинні бути замінними для їх базових типів.
  • Принцип сегрегації інтерфейсу (провайдер): Інтерфейси повинні бути специфічними для клієнта, а не змушувати реалізацію невикористаних методів.
  • Принцип інверсії залежності (DIP): Модулі високого рівня повинні залежати від абстракцій, а не від модулів низького рівня.

Інтегруючи ці принципи в розробку Android, ми можемо створити додатки, які простіше масштабувати, тестувати та підтримувати.

Принцип єдиної відповідальності – це основа написання реконструйованого коду. У ньому йдеться про те, що кожен клас повинен мати єдине занепокоєння, за яке він бере на себе відповідальність. Поширеним анти-Паттерном є розгляд діяльності чи фрагментів як деякі «заняття з Бога», які вирішують обов’язки, починаючи з надання інтерфейсу інтерфейсу, потім отримання даних, поводження з помилками тощо. Цей підхід робить тест і обслуговування кошмару.

З SRP окремі різні проблеми на різні компоненти: наприклад, у додатку для новин, створіть чи читайте новини.


class NewsRepository {
    fun fetchNews(): List {
        // Handles data fetching logic
    }
}
class NewsViewModel(private val newsRepository: NewsRepository) {
    fun loadNews(): LiveData {
        // Manages UI state and data flow
    }
}
class NewsActivity : AppCompatActivity() {
    // Handles only UI rendering
}

Кожен клас несе лише одну відповідальність; Отже, це легко перевірити та модифікувати, не маючи побічних ефектів.

У сучасній розробці Android, SRP в основному реалізується разом із рекомендованою архітектурою за допомогою Jetpack. Наприклад, логіка, пов’язана з логікою маніпулювання даними, може проживати всередині ViewModel, тоді як діяльність чи фрагменти повинні просто піклуватися про інтерфейс та взаємодії. Виведення даних може бути делеговане на деякі окремі сховище, або з локальних баз даних, таких як приміщення, або мережеві шари, такі як модернізація. Це знижує ризик того, що класи інтерфейсу погіршують, оскільки кожен компонент отримує лише одну відповідальність. Одночасно ваш код буде набагато простішим для тестування та підтримки.

Принцип відкритого/закритого заявляє, що клас повинен бути відкритий для розширення, але не для модифікації. Це більш розумно для додатків для Android, оскільки вони постійно оновлюють та додають нові функції.

Найкращим прикладом того, як використовувати принцип OCP в додатках Android, є інтерфейси та абстрактні класи. Наприклад:


interface PaymentMethod {
    fun processPayment(amount: Double)
}
class CreditCardPayment : PaymentMethod {
    override fun processPayment(amount: Double) {
        // Implementation for credit card payments
    }
}
class PayPalPayment : PaymentMethod {
    override fun processPayment(amount: Double) {
        // Implementation for PayPal payments
    }
}

Додавання нових методів оплати не вимагає змін до існуючих класів; Це вимагає створення нових класів. Тут система стає гнучкою і може бути зменшена.

У програмах, створених для пристроїв Android, принцип відкритого/закритого є досить корисним, коли мова йде про функції та конфігурації, взяті динамічно. Наприклад, якщо у вашому додатку є базовий інтерфейс Analyticstracker, який повідомляє про події різним службам аналітики, Firebase та Mixpanel та власним внутрішнім трекерам, кожна нова послуга може бути додана як окремий клас без змін існуючого коду. Це тримає ваш модуль аналітики відкритим для розширення, ви можете додати нові трекери, але закриті для модифікації: ви не переписуєте існуючі класи кожного разу, коли додаєте нову послугу.

Принцип заміни Ліскова зазначає, що підкласи повинні бути замінені для їх базових класів, а поведінка програми не повинна змінюватися. В Android цей принцип є основоположним для розробки багаторазових та передбачуваних компонентів.

Наприклад, додаток для малювання:


abstract class Shape {
    abstract fun calculateArea(): Double
}
class Rectangle(private val width: Double, private val height: Double) : Shape() {
    override fun calculateArea() = width * height
}
class Circle(private val radius: Double) : Shape() {
    override fun calculateArea() = Math.PI * radius * radius
}

Обидва Прямокутник і Кола може бути замінений будь -яким іншим взаємозамінним без відмови системи, а це означає, що система є гнучкою і слідує за LSP.

Розглянемо Android Recyclerview.adapter підкласи. Кожен підклас адаптера простягається з Recyclerview.adapter і переосмислює основні функції, як -от oncreateviewholder, неповторнийі титул. З Recyclerview Можна використовувати будь -який підклас взаємозамінно до тих пір, поки ці методи будуть реалізовані правильно, а не порушувати функціональність вашої програми. Тут підтримується LSP, і ваш речовинний перегляд може бути гнучким, щоб замінити будь -який підклас адаптера за бажанням.

У більших додатках часто визначати інтерфейси з занадто великою відповідальністю, особливо навколо мереж або зберігання даних. Натомість розбийте їх на мен, більш цілеспрямовані інтерфейси. Наприклад, інтерфейс Apiauth, що відповідає за кінцеві точки аутентифікації користувача, повинен відрізнятися від інтерфейсу Apiposts, відповідального за публікації в блозі або кінцеві точки соціального каналу. Цей розділення не дозволить клієнтам, які потребують лише після пов’язаних методів, змусити залежати та впроваджувати дзвінки аутентифікації, отже, зберігаючи ваш код, а також тестове покриття, худорляче.

Принцип сегрегації інтерфейсу означає, що замість того, щоб мати великі інтерфейси, слід використовувати кілька менших, цілеспрямованих. Принцип запобігає ситуаціям, коли заняття впроваджують непотрібні методи.

Наприклад, замість того, щоб мати один великий інтерфейс, що представляє дії користувачів, розглянемо код Kotlin:


interface Authentication {
    fun login()
    fun logout()
}
interface ProfileManagement {
    fun updateProfile()
    fun deleteAccount()
}

Класи, які впроваджують ці інтерфейси, можуть зосередитись лише на потрібній їм функціональності, тим самим очищаючи код і роблячи його більш реконструкцією.

Принцип інверсії залежності сприяє роз’єднуванню, забезпечуючи залежність модулів високого рівня від абстракцій, а не конкретних реалізацій. Цей принцип ідеально узгоджується з сучасною практикою розвитку Android, особливо з рамками для введення залежності, такими як кинджал і рукоятка.

Наприклад:


class UserRepository @Inject constructor(private val apiService: ApiService) {
    fun fetchUserData() {
        // Fetches user data from an abstraction
    }
}

Ось, UserRepository залежить від абстракції Апісерціяробить його гнучким і перевіреним. Цей підхід дозволяє нам замінити реалізацію, наприклад, використання макетної послуги під час тестування.

Рамки, такі як рукоятка, кинджал та коїн, сприяють введенням залежності, забезпечуючи спосіб забезпечення залежності до компонентів Android, усуваючи необхідність інстанціювати їх безпосередньо. Наприклад, у сховищі, замість того, щоб створити реалізацію модернізації, ви будете вводити абстракцію, наприклад, інтерфейс Apiservice. Таким чином, ви можете легко переключити реалізацію мережі для екземпляра, макетну службу в пам’яті для локального тестування, і не потрібно було б нічого змінювати у вашому коді сховища. У реальних програмах ви можете виявити, що класи анотуються @inject або @provides, щоб забезпечити ці абстракції, отже, зробити вашу програму модульною та зручною для тесту.

Прийняття суцільних принципів розвитку Android дає відчутні переваги:

  1. Покращена перевірка: Цілеспрямовані класи та інтерфейси полегшують записи тестів на одиницю.
  2. Посилена ремонтопридатність: Чітке розділення проблем спрощує налагодження та оновлення.
  3. Масштабованість: Модульні конструкції дозволяють безшовні доповнення.
  4. Співпраця: Добре структурований код полегшує роботу в команді та скорочує час на борту нових розробників.
  5. Оптимізація продуктивності: Худні, ефективні архітектури мінімізують непотрібну обробку та використання пам’яті.

У багатих на функції додатки, такі як додатки електронної комерції чи соціальних мереж, застосування твердих принципів може значно знизити ризик регресій щоразу, коли додається нова функція чи послуга. Наприклад, якщо нова вимога вимагає потоку покупки в додатку, ви можете ввести окремий модуль, який буде реалізувати необхідні інтерфейси (оплата, аналітика), не торкаючись існуючих модулів. Цей вид модульного підходу, керований SOLID, дозволяє вашому додатку Android швидко адаптуватися до потреб на ринку і не дозволяє кодової бази не перетворюватися на спагетті з часом.

Працюючи над великим проектом, який вимагає від багатьох розробників співпрацювати ,, настійно рекомендується зберігати складну базу коду з суцільними принципами. Наприклад, розділення отримання даних, логіки бізнесу та обробки інтерфейсу в модулі чату допомогло зменшити ймовірність регресій, масштабуючи код новими функціями. Аналогічно, застосування DIP мало вирішальне значення для абстрактних мережевих операцій, отже, вміти змінювати майже без зривів між клієнтами мережі.

Більше, ніж теоретичне посібник, принципи твердого речовини – це насправді практична філософія створення стійкого, пристосованого та реконструкції програмного забезпечення. У світі швидкоплинного розвитку Android, вимоги змінюються майже так само часто, як і технології, дотримання цих принципів забезпечує тверду підставу, на якій може бути заснований успіх.

Хороший код – це не лише те, щоб зробити щось, що працює – це створення системи, яка може продовжувати працювати і рости з розвитковими потребами. Отримавши суцільні принципи, ви не тільки напишете кращий код, але й будуєте додатки, які є радістю розвивати, масштабувати та підтримувати.



Джерело

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *