Всяка част от кода в софтуерен проект е като малка част от машина, необходима за съществуването на глобален резултат, тоест за изпълнение на обща и конкретна задача.

В горното изображение виждаме система от зъбни колела, която работи заедно и съставлява едно цяло, в този случай цялото е машината. Ако някоя от частите спре да работи, най-вероятно машината също ще спре да работи или ще се държи неочаквано.

Обектно-ориентираното програмиране се обобщава в това, в обектно-базирани поведения, които правят цялата работа.

Нека се върнем към нашия пример за машината и нейната скоростна система. В програмирането всяко от тези зъбни колела е известно като Обект. Създаден е обект с калъп. В обектно-ориентираното програмиране тази форма се нарича: Клас.

Така че, ако един клас е мухъл, можем да кажем, че даден обект произлиза от клас (от мухъл). В програмирането казваме, че обект, който произлиза от клас, се нарича: Екземпляр.

Ще създадем нашата машина с езика Ruby, прилагайки концепцията на обектно-ориентираното програмиране.

Първото нещо, което ще направим, е да помислим: Какво ни трябва, за да създадем нашата машина? Можем да започнем, като създадем клас, наречен Machine и да продължим от там. В нашия текстов редактор нека създадем нов файл, наречен Machine.rbи да зададем нашия клас Machine (мухъл):

Сега имаме нашия шаблон или калъп за създаване на машина.

Важно: Когато именуваме клас, започваме с главна буква и ако класът ни е съставен от повече от една дума, ще използваме CamelCase, т.е. , всяка дума ще бъде съединена с предишната и първата й буква ще бъде главна. След като изяснихме това, можем да продължим.

Безполезно е да имаме нашия клас Machine (мухъл), ако не го използваме за създаване на обект (инстанция). В Ruby синтаксисът за създаване на нов обект е: Machine.new

Можем също да създадем променлива, наречена newMachineи да съхраним този нов обект в паметта, за да можем по-късно да взаимодействаме или да установим комуникация с този обект: newMachine = Machine.new

Нашата променлива newMachine съдържа нашия нов обект (инстанция), извлечен от класа Machine.

Всички обекти имат специален метод, наречен class, който връща класа, от който е извлечен този обект. Можем да приложим това към нашето упражнение. За да знаем от какъв клас произлиза нашият обект newMachine, можем да отпечатаме в конзолата newMachine.class и ще видим, че резултатът е Machine, което означава, че класът Machine е шаблонът, с който сме създали нашия нов обект newMachine.

Страхотно, създадохме нашия клас Machine и произлязохме от него, за да създадем обект newMachine, но засега нашата машина не прави нищо, не показва никаква функционалност. Тогава е време да поговорим за методи.

Методи

Има няколко дефиниции за това какво е метод, в зависимост от автора или източника, в който виждаме дефиницията му, някои дефиниции могат да произтичат едно от друго в някои неща, но същността е една и съща. Един метод може да се дефинира като:

  • Подпрограма
  • Подпрограма
  • Процес
  • функция
  • Рутина
  • Метод
  • Подалгоритъм

Най-общо казано, методът изпълнява функция и е част от универсален алгоритъм и решава конкретна задача.

Можем да мислим, например, че всички глаголи в нашия език са действия и следователно подпрограми, например:

  • Яжте
  • Смейте се
  • сън
  • работа
  • Плачи
  • Проучване
  • Усещам
  • и т.н.

Глаголите са действия, защото всеки представлява различна задача, така че човешките действия могат да се разглеждат като подалгоритми.

Надявам се тази илюстрация да ви помогне да разберете тези концепции.

Методите са дефинирани в нашия клас (мухъл), тъй като принадлежат към него, придават му идентичност и го отличават от другите класове. В Ruby методите се дефинират с инициалите def, последвани от името на метода, например:

Както виждаме, имаме клас (форма) за създаване на хора и този клас има 2 метода: здравей и сбогом, които са дефинирани само защото няма действие в рамките тях, но засега важното е да разберем, че методите влизат вътре в класовете. Класът Person може да има много повече методи, но това е само малък пример.

Да се ​​върнем към създаването на нашата машина. В момента имаме безжизнен клас, така да се каже, тъй като той не прави нищо, той е само дефиниран:

Една машина не може да стартира без двигател. Двигателят ще отговаря за захранването на различните предавки на машината. В нашия текстов редактор нека създадем нов файл, наречен Engine.rb, за да дефинираме класа Engine:

И тъй като говорим за съоръжения, нека сега създадем класа Gear. В нашия текстов редактор създаваме файла Gear.rb, за да дефинираме класа Gear:

Тъй като вече имаме клас Gear, можем да създадем всички предавки, които искаме за нашата машина. Всички наши съоръжения ще бъдат екземпляри на нашия клас Gear (мухъл) и следователно ще съдържат всички методи на класа, от който са извлечени.

Класът Зъбно колело (мухъл), който създадохме, ще отговаря за създаването на зъбно колело с посочения от нас размер, тъй като не всички зъбни колела са с еднакъв размер. За да направим това, ще трябва да използваме това, което наричаме в програмирането: Конструктор.

Конструктор и атрибути

Атрибут: това е характеристика, която има даден обект, като цвят, размер, форма и т.н. Атрибутите се съхраняват в паметта чрез използването на променливи, които се наричат ​​променливи на екземпляра.

Конструктор: е метод, подпрограма, която обикновено се използва за инициализиране на атрибутите на обект.

Всеки път, когато се създава обект, има взаимодействие между този нов обект и класа, от който идва, и един от начините да проверите това е чрез използване на конструктор.

В Ruby конструкторите се дефинират с думата initialize. За да приложим тази концепция, нека се върнем към примера на нашата машина и в класа Gear ще добавим нов метод на конструктор:

Когато създадем нов екземпляр на клас, автоматично се извиква методът initialize на този клас. В нашия пример методът initialize съдържа променлива, наречена @size, която запазва размера на всяко зъбно колело, когато създава екземпляр на Gear клас и променлива, наречена: мощност, която представлява мощността, която обектът на зъбно колело трябва да премести, което първоначално ще бъде false, тъй като първоначалното състояние на машината ще бъде изключено.

Време е да използваме конструктор за класа Machine, тъй като не искаме всички зъбни колела на нашата машина да са с еднакъв размер. Ще използваме следното изображение, за да установим размерите на зъбните колела, които машината ще има:

Нека отидем до класа Machine, използваме require_relative за извикване на класа Gear и създаваме метод за initialize така че при създаването на машината тя включва всяко от зъбните колела, всяко със съответния размер за работа. Не забравяйте, че всяка предавка ще има фалшива стойност на мощността, тъй като сме установили това в метода initialize на класа Gear:

Важно: Когато създавате всяко от зъбните колела в класа Machine, се извиква методът initialize на класа Gear.

Сега ще създадем метод на конструктор за нашия клас Engine, който ще показва съобщението „Нов двигател“ само в конзолата, когато бъде създаден нов двигател:

Нека сега да преминем към класа Machine, използваме require_relative за извикване на класа Engine и създаваме двигател вътре в неговия конструктор, така че накрая да имаме предавките и готов двигател в нашата машина:

Време е да тестваме нашата основна машина, която съдържа двигател и 4 предавки. В конзолата пишем ruby Machine.rb и ще видим следното съобщение:

Така проверяваме как е създадена нова машина, благодарение на методите на конструктора на всеки от класовете.

Сега е време да създадете процеса на включване на машината. Този процес ще се извърши чрез валидиране, т.е. само потребителите, които предоставят административната парола, ще могат да включат машината. Тогава е време да поговорим за частни методи.

Частни методи

Научихме, че методите са подалгоритми на общ алгоритъм и че изпълняват специфична функция. Нещо важно, което трябва да имате предвид е, че досега начинът, по който дефинирахме методите в предишните примери, беше публичен, защо? тъй като всички онези обекти, които произлизат от конкретен клас, имат достъп до методите на този клас, които са извън него. Тоест, връщайки се към нашия пример в класа Machine:

Обектът newMachine е извън класа, от който произлиза, и все още има достъп до метода за инициализация вътре в класа, затова казваме, че тези методи са публични. Освен това, тъй като newMachine е екземпляр, всички методи, дефинирани в класа, от който произлиза, стават методи на самия обект.

В програмирането обаче не всички методи трябва да са винаги публични, има процедури в нашите приложения, които е по-удобно да се запазят като лични.

Ще приложим концепцията за частен метод, така че двигателят, който имаме в нашата машина, да стартира само когато е предоставена тайна администраторска парола и след като двигателят стартира, машината ще се включи. Частният метод ще бъде този, който проверява паролата, предоставена от потребителя:

Създадохме метод, наречен turnOn, който ще иска от потребителя тайна парола и ще я съхранява в променлива. След като паролата бъде получена, частният метод validate ще бъде извикан и ще получи променливата като параметър, за да провери дали паролата е правилна.

Ако паролата е правилна, методът turnOn се извиква, този метод все още не съществува, нека го създадем:

Когато извикаме метода turnOn, всяка от предавките се получава като параметър и нейната стойност power се променя на true, т.е. двигателят им дава сила да се движат.

Когато работим с частни методи, винаги трябва да вземем предвид следното:

  • Частните методи са видими само в класа, в който се намират.
  • Частните методи използват ключовата дума private.
  • Не е необходимо да посочваме думата private за всеки от методите, които искаме да зададем като частни, просто поставете думата private веднъж и всички методи, които са под тази дума ще бъде частна.

В момента класът Engine няма достъп до атрибута power на класа Gear. Време е да поговорим за четене и писане.

Четене и писане

Атрибутите на даден обект са частни по подразбиране, тоест те принадлежат на самия екземпляр и следователно трябва да създадем метод, който връща стойността на този атрибут, когато искаме да имаме външен достъп до него, което в програмирането е известно като: четене на атрибут.

В програмирането думата get се използва за обозначаване на четенето на атрибут, а думата set се използва за обозначаване на писането или модифицирането на атрибут.

В Ruby методите set и get се създават по следния стандарт:

  • Методът, който е създаден за четене на атрибута (get), трябва да има същото име като атрибута и обикновено връща стойността на атрибута.
  • Методът, който е създаден за писане или модифициране на атрибут (set), трябва да бъде извикан по същия начин като атрибута и с оператор = в края на атрибута.

Нека се върнем към създаването на нашата машина, за да разберем по-добре тази концепция. В нашия клас Gear ще създадем метод за четене, наречен power, тъй като искаме да имаме достъп до стойността на атрибута, съхранена в променлива @power > така че когато двигателят се стартира, можем да променим стойността на мощност на true. Причината нашият метод да се нарича по същия начин като атрибута е, че отговаря на стандарт 1:

Методът, който е създаден за четене на атрибута, трябва да има същото име като атрибута и обикновено връща стойността на атрибута.

Следователно методът power ще върне стойността на нашата променлива на екземпляр @power:

Сега нека създадем метод за запис:

Сега също имаме метод за писане или модифициране, тоест, че ако имаме обект, в нашия случай зъбно колело с фалшива стойност на мощността, която вече е посочена по време на създаването му, можем да променим тази стойност. В нашия случай стойността @power ще бъде променена от класа Engine, когато се включи.

Сега, когато двигателят иска да промени стойността на мощност, той ще може да го направи, защото вече има достъп до атрибута:

Методът на писане, който създадохме, отговаря на стандарт 2:

Методът, който е създаден за писане или модифициране на атрибут, трябва да се нарича по същия начин като атрибута и с = в края на атрибута.

Преки пътища в Ruby

Научихме много неща, вече знаем как да създаваме класове и обекти, които произлизат от тях. Знаем също какво е метод и какви са атрибутите на обекта. Също така говорихме за метода на конструктора (initialize) и четенето и модифицирането на атрибути (get и set).

Нашата машина вече има 4 скорости и двигател, който има функцията да стартира машината. Сега: Какво ще стане, ако вместо 1 или 2 атрибута в клас имахме 10 атрибута?, ще трябва да създадем методи за четене (get) и запис (set) за всеки от тях и накрая ще имаме много редове код, повтарящи един и същ модел на четене и писане отново и отново. Благодарение на езика Ruby, можем да направим този процес много по-лесен в един ред, като използваме преки пътища.

Има 3 вида пряк път, те са обяснени по-долу:

  • attr_accessor: позволява както четенето, така и модифицирането на атрибут (set и get).
  • attr_writer: Позволява само модификация на атрибут (set).
  • attr_reader: позволява само четене на атрибут (get).

Ще приложим тази система за бърз достъп, вместо да дефинираме четене(get) и запис(set ) за атрибута на захранването, ще използваме attr_accessor, за да дадем външни разрешения за четене и запис:

По този начин нашата променлива @power може да бъде прочетена и модифицирана външно от класа, в който се намира. Нашият код сега изглежда по-ясен и лесен за разбиране.

След като зъбните колела получат необходимата сила от двигателя, ще създадем метод за контрол, така че машината да се включи или да се покаже съобщение за грешка в случай, че предоставената парола е неправилна:

Методът наконтрола потвърждава, че всички предавки имат мощност. Ако е така, ще покаже съобщението “Машината е включена!”, в противен случай ще покаже съобщението “ГРЕШКА!”

Единственото нещо, което ни остава, за да тестваме нашата машина, е да извикаме метода turnOn от newMachine(ред 40):

Нека да отидем на конзолата и да напишем ruby Machine.rb и ще видим, че ни се иска да предоставим парола. Когато предоставим неправилна парола, ще видим съобщението „ГРЕШКА!“, но ако предоставим правилната парола (123456), ще видим съобщението „Машината е включена!“

И накрая, важно е да споменем, че понякога, когато искаме даден атрибут да има същото име като метод, в Ruby използваме думата self.

С self това, което правим, е да посочим, че това е метод на обекта, а не атрибут, по този начин разграничаваме атрибута на метод, когато те имат едно и също име.

Ние ще приложим тази концепция. Връщаме се към нашата машина. Нека покажем кредитите на производителя на машината (нас), за това в метода initialize на класа Machine добавяме променливата credits, която ще запази резултата, който връща метод на обект със същото име кредити:

След това дефинираме метода, който ще покаже кредитите:

Можем да изпълним нашето упражнение с ruby ​​Machine.rb и ще видим, че първото нещо, което ще се покаже, са кредитите, последвани от компонентите на машината и накрая инструкцията за въвеждане на ключа:

Поздравления, създадохте машина, прилагаща научените концепции.

Това е само малък пример, който можете дори да подобрите и да направите кода си по-функционален, така че ви каня да експериментирате сами и по този начин да постигнете по-добро овладяване на тези концепции. Други елементи на обектно-ориентираното програмиране ще бъдат разгледани в бъдещи статии. Ако статията ми ви е харесала, ще се радвам, ако я споделите с вашите приятели и колеги.

Благодаря ви много и до скоро!