1. Об'єкти та класи
Сьогодні ви дізнаєтеся трохи про те, як влаштовано типову програму мовою Java. І головна новина: кожна програма, написана мовою Java, складається з класів і об'єктів.
Що таке класи, ви вже знаєте, а що таке об'єкти?
Почну з аналогії. Уявіть, що ви хочете побудувати невеликий корабель. Спочатку потрібно створити креслення, потім віддати його на завод, де за цим кресленням виготовлять корабель. Або десяток. Та й узагалі, скільки завгодно кораблів. За одним кресленням будують десятки ідентичних кораблів — от що важливо.
У програмуванні мовою Java все так само.
Креслення
Програміст чимось схожий на проєктувальника. Тільки проєктувальник виконує креслення, а Java-програміст пише класи. Потім на основі креслень створюють деталі, а на основі класів — об'єкти.
Спочатку ми пишемо класи (робимо креслення), а відтак під час виконання програми на основі цих класів Java-машина створює об'єкти. Точнісінько так само, як кораблі споруджують на основі креслень.
Креслення одне, а кораблів може бути багато. Кораблі різні, у них різні назви, вони перевозять різні вантажі. Однак вони дуже схожі: це кораблі з ідентичною конструкцією та можуть виконувати подібні завдання.
А от інша аналогія…
Мурашник
Мурашник — це гарний приклад взаємодії об'єктів. У найпростішому мурашнику є три класи мурах: королева, солдати й робітники.
Кількість мурах кожного класу різна. Королева — одна на весь мурашник, солдатів — десятки, а робочих мурах — сотні. Три класи й сотні об'єктів. Мурахи взаємодіють одна з одною, з такими самими мурахами й мурахами інших класів за чітко визначеними правилами.
Це просто ідеальний приклад. У типовій програмі все так само. Є головний об'єкт, який створює об'єкти всіх інших класів. Об'єкти починають взаємодіяти один з одним та із «зовнішнім світом» програми. Усередині цих об'єктів жорстко запрограмовано їхню поведінку.
Обидва пояснення — це два боки однієї медалі. Істина — посередині. Перший приклад (про креслення й кораблі) демонструє зв'язок між класом і об'єктами цього класу. Аналогія дуже сильна. Другий приклад (про мурашник) показує зв'язок між об'єктами, що існують під час роботи програми, і написаними класами.
Спершу ви повинні створити класи для всіх наявних у програмі об'єктів, і до того ж описати взаємодію цих об'єктів. Саме так, але це легше, ніж здається.
У Java всі сутності під час роботи програми є об'єктами, а написання програми зводиться до опису різних способів взаємодії між ними. Об'єкти просто викликають методи один одного та передають у них потрібні дані.
Документація
А як дізнатися, які дані слід передавати в методи? Тут все вже придумано до вас.
Зазвичай кожний клас має опис, з якого зрозуміло, для чого цей клас створено. Так само і кожний публічний метод зазвичай має опис: що він робить і які дані слід у нього передавати.
Для використання класу потрібно в загальних рисах знати, що він робить. Крім того, потрібно точно знати, що робить кожен його метод. І зовсім необов'язково знати, як він це робить. Така собі чарівна паличка.
Погляньмо, наприклад, на код для копіювання файлу:
Копіювання файлу c:\data.txt у файл c:\result.txt |
---|
|
Якщо прочитати цей код по рядках, можна приблизно здогадатися, що він робить. Щоправда тут потрібні досвід і практика. Отож через деякий час цей код вам буде здаватися знайомим і зрозумілим.
2. Проєктування програми
Проєктування програми — це справжнє мистецтво. Це і просто, і складно водночас. Просто, оскільки ніяких суворих законів немає: що не заборонено — те дозволено. Ну а складно з тієї самої причини: є дуже багато способів щось зробити, тому нелегко обрати найкращий.
Проєктувати програму — це як писати книгу. З одного боку, ви просто пишете літери, слова, речення. А з іншого — важливими є сюжет, характери героїв, внутрішні суперечності, конфлікти, стиль оповіді, інтрига тощо.
Головне — розуміти, для кого ви пишете код. А код ви пишете для інших програмістів.
Розробка будь-якого продукту — це внесення змін: додали тут, видалили там, переробили тут. І так маленькими ітераціями народжуються великі, величезні й гігантські проєкти.
Основна вимога до коду — він має бути зрозумілим іншим програмістам. Неправильний, але зрозумілий код можна виправити. Правильний і незрозумілий код покращити не вдасться. Його залишиться тільки викинути.
Отже, як писати хороший і зрозумілий код?
Для цього потрібно робити три речі:
- Писати хороший і зрозумілий код усередині методів (найпростіше)
- Вирішувати, які сутності мають бути в програмі
- Правильно розбивати програму на логічні частини
Що ж стоїть за цими поняттями?
Писати хороший код усередині методів
Якщо ви хоча б на початковому рівні знаєте англійську, то, можливо, звернули увагу, як іноді легко читається код — ніби речення англійською мовою:
class Cat extends Pet
— клас Кіт розширює клас СвійськаТваринаwhile(stream.ready())
— поки потік готовий…if (a<b) return a; else return b
— якщоа
менше заb
, повернутиа
, інакше повернутиb
.
Так зробили навмисно. Java — одна з кількох мов, якими легко писати самодокументований код, тобто код, зрозумілий без коментарів. У хорошому коді на мові Java багато методів читаються просто як речення англійською мовою.
Ваше завдання під час написання коду — теж робити його якомога простішим і лаконічнішим. Просто думайте, наскільки легко читатиметься ваш код, і ви почнете рухатися в правильному напрямку.
У Java заведено писати легкочитний код. Бажано, щоб кожен метод цілком вміщався на екрані (довжина методу — 20–30 рядків). Це норма для всієї Java-спільноти. Якщо код можна поліпшити, його треба поліпшити.
Найкращий спосіб навчитися писати хороший код — постійна практика. Пишіть багато коду, аналізуйте чужий, просіть досвідченіших колег перевірити ваш код.
І пам'ятайте, що в той момент, коли ви скажете собі: «І так добре!», ваш розвиток зупиниться.
Вирішувати, які сутності мають бути в програмі
Вам потрібно писати код, зрозумілий іншим програмістам. Якщо 9 із 10 програмістів, проєктуючи програму, зроблять у ній класи A, B і С, то й вам також треба зробити у своїй програмі класи A, B, і C. Ваш код мають розуміти інші.
Відмінний, працюючий, швидкий нестандартний код — це поганий код.
Вам потрібно вивчати чужі проєкти: це найкращий, найпростіший і найлегший спосіб перейняти всю мудрість, яка десятиріччями накопичувалася в ІТ-індустрії.
І, до речі, у вас уже є напохваті чудовий, популярний, добре документований проєкт — Java SDK. Почніть із нього.
Розбирайте класи й структури класів. Думайте, чому одні методи зроблено статичними, а інші — ні. Чому методи мають саме такі параметри, а не інші. Чому саме такі методи, чому класи називаються саме так і містяться саме в таких пакетах.
Коли ви почнете розуміти відповіді на всі ці запитання, ви зможете писати код, зрозумілий іншим.
Проте хочу застерегти вас від розбору коду в методах Java SDK. Код багатьох методів було переписано з метою максимального збільшення швидкості роботи, тому такий код не завжди легкочитний.
Правильно розбивати програму на логічні частини
Будь-яку програму зазвичай розбивають на частини або модулі. Кожна частина відповідає за свій аспект програми.
От у комп'ютера є системний блок, монітор, клавіатура, і все це — окремі, малозалежні один від одного компоненти. Ба більше, їх взаємодію стандартизовано: USB, HDMI тощо. Натомість якщо ви проллєте каву на клавіатуру, її можна просто помити під краном, просушити й користуватися далі.
А от ноутбук — це приклад монолітної архітектури: логічні частини нібито і є, але інтегровані вони між собою набагато щільніше. Приміром, щоб почистити клавіатуру MacBookPro, потрібно розібрати половину ноутбука. А якщо пролити на нього чай, доведеться замовити новий. Але це буде не чай.
3. Створення власних класів
Оскільки ви лише вчитеся програмувати, слід починати з малого — вчитися створювати власні класи.
Ви їх, звісно, вже створювали, але вам важливо розвивати розуміння того, які класи мають бути в програмі, як вони мають називатися, які в них мають бути методи. І як вони мають один з одним взаємодіяти.
Список сутностей
Якщо ви не знаєте, з чого почати, почніть з початку.
На самому початку проєктування програми ви можете просто записати на аркуші список сутностей (об'єктів), які вона має містити. А відтак запрограмувати їх за таким принципом: кожна сутність — окремий клас.
Приклад
Припустімо, ви хочете написати гру в шахи. Вам знадобляться такі сутності: шахівниця і 6 типів фігур. Фігури ходять по-різному, мають різну цінність — логічно, що це окремі класи. І взагалі, на самому початку що більше класів, то краще.
Зустріти програміста-початківця, який замість двох класів написав би десять, — велика рідкість. От замість десяти створити два, а то й один — це новачки полюбляють. Отже, більше класів, панове програмісти. І ваш код стане зрозумілішим для всіх, окрім, можливо, вас 😛
Шахи
Припустімо, ми вирішили створити класи для шахів: який вигляд вони матимуть?
Шахівниця — це просто масив 8 на 8? Краще зробіть для неї окремий клас, який усередині зберігає посилання на масив. Тоді в клас «Шахівниця» ви зможете додати багато корисних методів, які, наприклад, перевіряють, клітинка порожня чи зайнята.
Загалом кажучи, на початку завжди можна керуватися таким принципом: У програмі є різні Сутності, а Сутність має тип. Оцей тип як раз і є класом.
4. Статичні змінні й методи
Також не забувайте користуватися статичними змінними й методами. Якщо у вас одна шахова фігура взаємодіє з іншою на шахівниці, значить, ваш код має містити метод, в який передаються посилання на першу фігуру, на другу та на шахівницю.
Щоби постійно не передавати посилання на об'єкти, які «існують завжди», їх зазвичай роблять статичними змінними, і до них можна звернутися з будь-якого місця програми.
Наприклад, отак:
Код | Примітка |
---|---|
|
Посилання на єдиний об'єкт типу ChessBoard .Двовимірний масив 8×8, нестатична змінна. Додаємо фігури на шахівницю. |
Також замість статичної змінної можна зробити метод, який повертає єдиний об'єкт. Наприклад, отак:
public class ChessBoard
{
private static ChessBoard board = new ChessBoard();
public static ChessBoard getBoard()
{
return board;
}
public ChessItem[][] cells = new ChessItem[8][8];
...
}
public class Game
{
public static void main(String[] args)
{
var board = ChessBoard.getBoard();
board.cells[0][3] = new King(Color.WHITE);
board.cells[0][4] = new Queen(Color.WHITE);
...
}
}
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ