Классы и функции

Мы про­дол­жа­ем рас­сказ об объектно-ориентированном про­грам­ми­ро­ва­нии: зачем оно нуж­но и в чём его сила. Это ско­рее тео­рия, чем необ­хо­ди­мая еже­днев­ная прак­ти­ка, но такие вещи при­во­дят в поря­док кар­ти­ну мира.

👉 Если вы пише­те про­стые про­грам­мы для себя, все эти вещи вам могут не при­го­дить­ся. Но если хоти­те стать про­фес­си­о­на­лом — доб­ро пожаловать.

🤔 Это обнов­лён­ная вер­сия ста­тьи. В ста­рой были огре­хи, кото­рые мы поста­ра­лись испра­вить, что­бы ста­тья ста­ла яснее и корректнее. 

Вспоминаем основные понятия

  • Есть про­грам­ма. В импе­ра­тив­ном про­грам­ми­ро­ва­нии про­грам­ма пред­став­ля­ет собой после­до­ва­тель­ность зада­ний, кото­рые мы даём ком­пью­те­ру. Делай одно, потом вто­рое, потом тре­тье. Есть ещё функ­ци­о­наль­ное про­грам­ми­ро­ва­ние, но это немно­го другое. 
  • Сами зада­ния про­стые, но из про­стых зада­ний мож­но сде­лать более слож­ные. Если такое более слож­ное зада­ние как-то назвать, мож­но ска­зать, что это функ­ция — мини-программа внут­ри программы.
  • В функ­цию мож­но упа­ко­вать любые после­до­ва­тель­но­сти дей­ствий, кото­рые вам часто нуж­ны в про­грам­ме: напри­мер сохра­нить файл осо­бым обра­зом, выве­сти что-то на осо­бый экран или отпра­вить элек­трон­ное пись­мо на осо­бый адрес. 
  • Внут­ри одних функ­ций мож­но вызы­вать дру­гие. Напри­мер, в таск-менеджере может быть функ­ция «Закрыть зада­чу», внут­ри кото­рой сна­ча­ла сохра­ня­ет­ся файл, потом отправ­ля­ет­ся пись­мо, потом всё выво­дит­ся на осо­бый экран. 
  • Про­бле­ма: когда мно­го функ­ций вызы­ва­ют­ся друг из дру­га, они пере­пле­та­ют­ся и созда­ют мно­го зави­си­мо­стей. Если изме­нить рабо­ту одной из функ­ций, могут посы­пать­ся другие. 
  • Реше­ние: стан­дар­ти­зи­ро­вать под­хо­ды к рабо­те функ­ций. В част­но­сти, для это­го при­ду­ма­ли объектно-ориентированное программирование.
  • В объектно-ориентированном про­грам­ми­ро­ва­нии глав­ная не функ­ция, а объ­ект. Объ­ект мож­но пред­ста­вить как короб­ку с дан­ны­ми и функциями.

Что есть класс

Вы може­те изго­то­вить объ­ект вруч­ную из любых функ­ций и дан­ных, кото­рые вам нуж­ны. Но если вам для рабо­ты про­грам­мы нуж­ны десят­ки похо­жих друг на дру­га объ­ек­тов, име­ет смысл как-то их стандартизировать. 

Если по-простому, то класс — это «чер­тёж», по кото­ро­му вы може­те изго­то­вить объ­ек­ты. Вы про­пи­сы­ва­е­те один класс, опре­де­ля­е­те его пове­де­ние и свой­ства, а потом даё­те коман­ду создать на осно­ве это­го клас­са нуж­ное чис­ло объектов. 

Напри­мер: 

  • У вас может быть класс для поль­зо­ва­те­ля интернет-магазина. Класс будет под­ска­зы­вать, что у поль­зо­ва­те­ля есть имя, адрес, поч­та и пароль, а так­же он может совер­шать покуп­ки с помо­щью таких-то функ­ций. На осно­ва­нии это­го клас­са вы буде­те реги­стри­ро­вать мно­же­ство пользователей.
  • Может быть класс для кноп­ки в интер­фей­се. Вы зна­е­те, что на кноп­ку мож­но нажи­мать и её мож­но отклю­чать при опре­де­лён­ных усло­ви­ях. Вы опи­сы­ва­е­те это пове­де­ние в клас­се, потом созда­ё­те мно­го кно­пок в интерфейсе. 

Пример: объекты, классы и функции в игре

Допу­стим, вы пише­те ком­пью­тер­ную игру. У вас есть герой, кото­рым управ­ля­ет игрок, и мно­го вра­гов, кото­ры­ми управ­ля­ет ком­пью­тер. И герой, и вра­ги могут стре­лять и лечиться. 

Если бы вы писа­ли всё на функ­ци­ях, у вас были бы такие функции: 

Герой_выстрелить();
Герой_подлечиться();
Враг1_выстрелить();

Враг99_выстрелить();
Враг1_подлечиться();

Враг99_подлечиться();

Классы и функции

Это доволь­но боль­шой зоо­парк из функ­ций, делать так не надо. Гораз­до луч­ше создать объ­ек­ты, а внутрь к ним поло­жить нуж­ные функции: 

Герой.выстрелить();
Герой.подлечиться();
Враг1.выстрелить();

Враг99.подлечиться();

Объектно ориентированное программирование Пред­ста­вим, что каж­дый пер­со­наж игры — это объ­ект. Внут­ри объ­ек­та что-то лежит 

Что­бы не про­пи­сы­вать все эти функ­ции и объ­ек­ты вруч­ную, мы созда­дим класс «Пер­со­наж»:

Класс «Пер­со­наж»{

имя: тут будет имя;
тип: герой или враг;
здо­ро­вье: 100;
функ­ция «Выстре­лить» {тут опи­сы­ва­ем, как стре­лять};
функ­ция «Под­ле­чить­ся» {тут опи­сы­ва­ем, как лечиться};

}

Теперь мы можем созда­вать сколь­ко угод­но пер­со­на­жей, напри­мер, так: 

Новый Пер­со­наж (имя:Герой);
Новый Пер­со­наж (имя:Враг1, здо­ро­вье: 10);
Новый Пер­со­наж (имя:Враг2, здо­ро­вье: 20);

Классы и функции

Допу­стим, мы реши­ли доба­вить в нашу игру систе­му инвен­та­ря. Что­бы не ходить по всем нашим вра­гам и геро­ям и не копи­па­стить в них код, мы про­пи­шем эту систе­му внут­ри класса: 

Класс «Пер­со­наж»{

имя: тут будет имя;
тип: герой или враг;
здо­ро­вье: 100;
функ­ция «Выстре­лить» {тут опи­сы­ва­ем, как стре­лять};
функ­ция «Под­ле­чить­ся» {тут опи­сы­ва­ем, как лечиться};

инвен­тарь: [сапоги-скороходы, меч-кладенец];
функ­ция «Сбросить_инвентарь» {как сбра­сы­вать};
функ­ция «Подобрать_предмет» {как подбирать};

}

Теперь у всех пер­со­на­жей появил­ся инвен­тарь. по умол­ча­нию у всех там лежат сапо­ги и меч, но при созда­нии пер­со­на­жа это мож­но пере­опре­де­лить. Так­же у всех пер­со­на­жей появи­лась воз­мож­ность сбро­сить весь инвен­тарь или подо­брать пред­мет с земли. 

Заметь­те, что всё это мы доба­ви­ли в одном месте, а появи­лось всё сра­зу у всех. В этом сила класса.

Объектно ориентированное программирование

Где применять классы и ООП, а где — функции

Если вы дела­е­те про­стую про­грам­му, кото­рую мож­но сде­лать тре­мя функ­ци­я­ми — делай­те. Или даже если про­грам­ма ста­нет слож­нее, в ней будет мно­го функ­ций, но все они логич­но свя­за­ны и понят­но, поче­му сде­ла­но имен­но так, — тоже хоро­шо. Нет ниче­го пло­хо­го в том, что вы не исполь­зу­е­те объектно-ориентированное про­грам­ми­ро­ва­ние там, где мож­но обой­тись без него.

А вот если у вас про­ект со мно­же­ством абстрак­ций, вза­и­мо­свя­зей внут­ри и вы зара­нее не може­те пред­ска­зать, когда что с чем будет вза­и­мо­дей­ство­вать, то луч­ше исполь­зо­вать клас­сы и все пре­иму­ще­ства ООП. Воз­мож­но, код ста­нет слож­нее, но это не все­гда так. С дру­гой сто­ро­ны, вы смо­же­те реа­ли­зо­вать такую логи­ку, кото­рую на функ­ци­ях было бы сде­лать непросто.

Текст:
Миша Поля­нин

Редак­ти­ро­вал и рисо­вал:
Мак­сим Ильяхов

Кор­рек­тор:
Ира Михе­е­ва

Иллю­стра­тор:
Даня Бер­ков­ский

Вёрст­ка:
Маша Дро­но­ва

Достав­ка:
Олег Веш­кур­цев