OOP - какво е това? Основни принципи на обектно-ориентираното програмиране. Обектно-ориентирано програмиране (ООП) Основните принципи на обектно-ориентираното програмиране са

За много PHP програмисти обектно-ориентираното програмиране е плашеща концепция, изпълнена със сложен синтаксис и други препятствия пред овладяването. В тази статия концепцията обектно-ориентирано програмиране(OOP) е представен като стил на кодиране, който ви позволява да групирате свързани дейности в класове, за да създадете по-компактен и ефективен код.

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

Обектно-ориентираното програмиране е стил на кодиране, който позволява на разработчика да групира подобни задачи класове. Така кодът отговаря на принципа DRY (не се повтаряйте) и става лесен за поддръжка.

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

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

Какво представляват обектите и класовете

Преди да се потопите в ясните дефиниции на OOP, е необходимо да имате основно разбиране за разликата между класовеИ обекти. Този раздел на статията ще ви помогне да получите представа за класовете, техните различни възможности и някои приложения.

Каква е разликата между класове и обекти

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

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

И обектът е истинска къща, която е изградена по проект. Данните, които се съхраняват в даден обект, са като дървото, жиците и бетона, които изграждат къща: без сглобяване според проекта, тя ще бъде просто купчина материали. Въпреки това, когато са събрани заедно, те правят отличен и удобен дом.

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

Структура на класа

Синтаксисът за създаване на клас е много прост: за да декларирате клас, използвайте ключовата дума class, последвана от името на класа и набор от фигурни скоби (()):

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

$obj = нов MyClass;

За да видите съдържанието на обект, използвайте var_dump():

Var_dump($obj);

Можете да тествате целия процес, като копирате целия код във файла test.php:

Заредете страницата в браузъра си и на екрана трябва да се появи следният ред:

Обект (MyClass)#1 (0) ( )

Току-що създадохте своя първи ООП скрипт.

Дефиниране на свойства на класа

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

За да добавите свойства към класа MyClass, използвайте този код във вашия скрипт:

Ключовата дума public определя видимостта на свойство, което ще разгледаме по-късно в тази глава. След това свойството се наименува с помощта на нормален синтаксис на променливата и му се присвоява стойност (въпреки че свойство на клас не трябва да се инициализира).

Ехо $obj->prop1;

Тъй като може да има множество реализации на клас, без препратка към конкретен обект, свойството не може да бъде прочетено, защото скриптът не може да определи от кой обект да се чете. Стрелката (->) е OOP конструкция, която се използва за достъп до свойствата и методите на даден обект.

Променете скрипта в test.php, за да прочете стойността на свойството, вместо да показва информация за целия клас:

опора1; // Показване на свойството?>

Обновете страницата в браузъра си, за да видите резултата от скрипта:

Свойство на класа

Дефиниране на класови методи

Методе функция от клас. Индивидуално действие, което обектът може да извърши, се дефинира в клас като метод.

Например, нека създадем методи, които задават и четат стойността на свойството $prop1:

prop1 = $newval; ) публична функция getProperty() ( връща $this->prop1 . "
"; ) ) $obj = нов MyClass; echo $obj->prop1; ?>

Забележка- OOP позволява на обект да се позовава на себе си с помощта на $this. Когато работите вътре в метод, използването на $this ви позволява да използвате името на обекта извън класа.

За да използвате метод, извикайте го като обикновена функция, но първо укажете обекта, към който принадлежи. Ние четем свойството от MyClass, променяме стойността, четем го отново:

prop1 = $newval; ) публична функция getProperty() ( връща $this->prop1 . "
"; ) ) $obj = нов MyClass; echo $obj->getProperty(); // получаване на стойността на свойството $obj->setProperty("Ново свойство."); // Задаване на нова стойност echo $obj->getProperty () ; // Прочетете отново стойността, за да видите промените?>

Опресняваме страницата в браузъра и виждаме следното:

Свойство на клас Ново свойство

Предимствата на ООП се проявяват при използване на множество обекти от един и същи клас.

prop1 = $newval; ) публична функция getProperty() ( връща $this->prop1 . "
"; ) ) // Създаване на два обекта $obj = нов MyClass; $obj2 = нов MyClass; // Получаване на стойностите на $prop1 от двата обекта echo $obj->getProperty(); echo $obj2->getProperty( ); // Задаване на нови стойности на свойства за двата обекта $obj->setProperty("Нова стойност на свойство"); $obj2->setProperty("Свойството принадлежи на втория обект"); // Отпечатване на $prop1 стойности ​за двете echo $obj->getProperty(); echo $obj2->getProperty(); ?>

Когато заредите страницата в браузъра, ще видите следното:

Свойство на класа Свойство на класа Нова стойност на свойството Свойството принадлежи към втория обект

Забележка, OOP съхранява обекти като различни обекти, което улеснява разделянето на кода на различни малки и взаимосвързани части.

Магически методи в ООП

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

Използване на конструктори и деструктори

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

За да илюстрираме концепцията, нека добавим конструктор към класа MyClass. Той ще отпечата съобщение, когато бъде създаден нов обект от клас:

"; ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty() ( return $this->prop1 . "
"; ) ) // Създаване на нов обект $obj = new MyClass; // Получаване на стойността на свойството $prop1 echo $obj->
"; ?>

Забележка— константата __CLASS__ връща името на класа, в който е извикана; това е една от магическите константи на PHP.

Създаден е обект от клас "MyClass"! Край на свойството на файловия клас.

За да извикате функция по време на процеса на изтриване на обект, използвайте магическия метод __destruct(). Това е много полезен метод за правилно изчистване на свойствата на класа (например за правилно затваряне на връзка с база данни).

Ще покажем съобщение, когато обект от клас бъде изтрит с помощта на магическия метод:
__destruct() в MyClass:

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty() ( return $this->prop1 . "
"; ) ) // Създаване на нов обект $obj = new MyClass; // Получаване на стойността на свойството $prop1 echo $obj->getProperty(); // Показване на съобщение за достигане на края на файла echo "End на файл.
"; ?>

Опресняваме страницата в браузъра и получаваме резултата:

Създаден е обект от клас "MyClass"! Край на свойството на файловия клас. Обектът на класа "MyClass" е изтрит.

Когато се достигне краят на файла, PHP автоматично освобождава всички ресурси.

За изрично извикване на деструктор и премахване на обект, можете да използвате функцията unset():


"; ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty() ( return $this->prop1 . "
"; ) ) // Създаване на нов обект $obj = new MyClass; // Получаване на стойността на свойството $prop1 echo $obj->getProperty(); // Изтриване на обекта unset($obj); // Показване на съобщение за достигане на края на файла echo „Край на файла.
"; ?>

Сега резултатът от кода ще изглежда така след зареждане в браузъра:

Създаден е обект от клас "MyClass"! Свойство на клас Обектът на класа "MyClass" е изтрит. Край на файла.

Преобразуване в низ

За да се избегне грешка, ако скриптът се опита да изведе MyClass като низ, се използва друг магически метод, __toString().

Без да използвате __toString() опитът за извеждане на обект като низ ще доведе до фатална грешка. Опитайте да използвате функцията ехо, за да изведете обект, без да използвате магическия метод:

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty() ( return $this->prop1 . "

"; ?>

Резултатът ще изглежда така:

Създаден е обект от клас "MyClass"! Уловима фатална грешка: Обектът от клас MyClass не може да бъде преобразуван в низ в /Applications/XAMPP/xamppfiles/htdocs/testing/test.php на ред 40

За да избегнете грешката, използвайте метода __toString():

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty( ) ( върне $this->prop1 . "
"; ) ) // Създаване на нов обект $obj = new MyClass; // Извеждане на обекта като низ echo $obj; // Изтриване на обекта unset($obj); // Извеждане на съобщение за достигане на края на file echo "Край на файла.
"; ?>

В този случай опитът за конвертиране на обект в низ ще доведе до извикване на метода getProperty(). Заредете скрипта в браузъра и вижте резултата:

Създаден е обект от клас "MyClass"! Използваме метода toString: Свойство на клас Обектът на класа „MyClass“ е изтрит. Край на файла.

Използване на наследяване на класове

Класовете могат да наследяват методи и свойства от други класовеизползвайки ключовата дума extends. Например, нека създадем втори клас, който разширява MyClass и добавя метод:

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty( ) ( върне $this->prop1 . "
"; ) ) клас MyOtherClass разширява MyClass ( публична функция newMethod() ( echo "От новия метод на клас " . __CLASS__ .)."
"; ) ) // Създайте нов обект $newobj = new MyOtherClass; // Използвайте новия метод echo $newobj->newMethod(); // Използвайте метода от родителския клас echo $newobj->getProperty(); ? >

След като заредим скрипта в браузъра, получаваме резултата:

Създаден е обект от клас "MyClass"! От новия метод на класа "MyOtherClass". Свойство на клас Обектът на класа "MyClass" е изтрит.

Претоварване на наследени свойства и методи

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

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty( ) ( върне $this->prop1 . "
"; ) ) клас MyOtherClass разширява MyClass ( публична функция __construct() ( echo "Нов конструктор в клас " . __CLASS__ .)."

"; ) ) // Създаване на нов обект $newobj = new MyOtherClass; // Извеждане на обекта като низ echo $newobj->newMethod(); // Използване на метода от родителския клас echo $newobj->getProperty() ; ?>

Промените ще доведат до следния резултат при изпълнение на кода:

Нов конструктор в класа "MyOtherClass". От новия метод на класа "MyOtherClass". Свойство на клас Обектът на класа "MyClass" е изтрит.

Запазване на оригиналната функционалност при претоварване на методи

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

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) публична функция getProperty( ) ( върне $this->prop1 . "
"; ) ) клас MyOtherClass разширява MyClass ( публична функция __construct() ( parent::__construct(); // Извикване на конструктора на родителския клас echo "Нов конструктор в класа " . __CLASS__ .".
"; ) public function newMethod() ( echo "От нов метод на класа " . __CLASS__ . ".
"; ) ) // Създаване на нов обект $newobj = new MyOtherClass; // Извеждане на обекта като низ echo $newobj->newMethod(); // Използване на метода от родителския клас echo $newobj->getProperty() ; ?>

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

Създаден е обект от клас "MyClass"! Нов конструктор в класа "MyOtherClass". От новия метод на класа "MyOtherClass". Свойство на клас Обектът на класа "MyClass" е изтрит.

Определяне на обхвата на свойствата и методите

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

Забележка- Обхватът е ново свойство, въведено в PHP 5. За OOP съвместимост с PHP 4 вижте ръководството за PHP.

Свойства и методи публични (Общи)

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

Методите и свойствата са защитени

Когато свойство или метод е декларирано със защитена директива, може да бъде достъпен само в рамките на самия клас или в рамките на производни класове(класове, които разширяват базов клас, съдържащ метод с директива защитени).

Нека декларираме метода getProperty() като защитенив MyClass и се опитайте да получите достъп до него извън класа:

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) защитена функция getProperty( ) ( върне $this->prop1 . "

"; ) public function newMethod() ( echo "От нов метод на класа " . __CLASS__ . ".
"; ) ) // Създайте нов обект $newobj = new MyOtherClass; // Опитайте се да извикате защитения метод echo $newobj->getProperty(); ?>

Когато се опитате да изпълните скрипта, ще се генерира следната грешка:

Създаден е обект от клас "MyClass"! Нов конструктор в класа "MyOtherClass". Фатална грешка: Извикване на защитен метод MyClass::getProperty() от контекст "" в /Applications/XAMPP/xamppfiles/htdocs/testing/test.php на ред 55

Сега нека създадем нов метод в MyOtherClass за извикване на метода getProperty():

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) защитена функция getProperty( ) ( върне $this->prop1 . "
"; ) ) клас MyOtherClass разширява MyClass ( публична функция __construct() ( parent::__construct(); echo "Нов конструктор в класа " . __CLASS__ .".
"; ) public function newMethod() ( echo "От нов метод на класа " . __CLASS__ . ".
"; ) публична функция callProtected() ( return $this->getProperty(); ) ) // Създаване на нов обект $newobj = new MyOtherClass; // Извикване на защитен метод от публичен метод echo $newobj->callProtected() ; ?>

При стартиране на скрипта резултатът ще бъде така:

Създаден е обект от клас "MyClass"! Нов конструктор в класа "MyOtherClass". Свойство на клас Обектът на класа "MyClass" е изтрит.

Методи и свойства частни

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

За демонстрация нека декларираме метода getProperty() като частен V Моят класи нека опитаме да извикаме метода callProtected() от
MyOtherClass :

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) частна функция getProperty( ) ( върне $this->prop1 . "
"; ) ) клас MyOtherClass разширява MyClass ( публична функция __construct() ( parent::__construct(); echo "Нов конструктор в класа " . __CLASS__ .".
"; ) public function newMethod() ( echo "От нов метод на класа " . __CLASS__ . ".
"; ) публична функция callProtected() ( return $this->getProperty(); ) ) // Създаване на нов обект $newobj = new MyOtherClass; // Използване на метода от родителския клас echo $newobj->callProtected(); ?>

Запазваме скрипта, опресняваме страницата в браузъра и получаваме следното:

Създаден е обект от клас "MyClass"! Нов конструктор в класа "MyOtherClass". Фатална грешка: Извикване на частен метод MyClass::getProperty() от контекста "MyOtherClass" в /Applications/XAMPP/xamppfiles/htdocs/testing/test.php на ред 49

Статични методи и свойства (статични)

Методите и свойствата, декларирани със статична директива, могат да бъдат достъпни без иницииране на клас. Просто използвате името на класа, оператора за разрешение за видимост и името на свойството или метода.

Едно от основните предимства на статичните свойства е, че те запазват стойностите си през целия скрипт.

За да демонстрираме, нека добавим статично свойство $count и статичен метод plusOne() към класа Моят клас. След това ще настроим do...while цикъл за отпечатване на нарастващата стойност на $count, докато стане по-голяма от 10:

"; ) публична функция __destruct() ( echo "Обект на клас "", __CLASS__, "" изтрит.
"; ) публична функция __toString() ( echo "Използвайте метода toString: "; върнете $this->getProperty(); ) публична функция setProperty($newval) ( $this->prop1 = $newval; ) частна функция getProperty( ) ( върне $this->prop1 . "
"; ) публична статична функция plusOne() ( return "count = ". ++self::$count. ".
"; ) ) клас MyOtherClass разширява MyClass ( публична функция __construct() ( parent::__construct(); echo "Нов конструктор в класа " . __CLASS__ .".
"; ) public function newMethod() ( echo "От нов метод на класа " . __CLASS__ . ".
"; ) публична функция callProtected() ( return $this->getProperty(); ) ) do ( // Извикване на plusOne без иницииране на класа MyClass echo MyClass::plusOne(); ) докато (MyClass::$count< 10); ?>

Забележка- За достъп до статични свойства, знакът за долар ($) трябва идва след оператора за разрешение за видимост.

Изпълнението на скрипта в браузъра ще доведе до следния резултат:

Брой = 1. Брой = 2. Брой = 3. Брой = 4. Брой = 5. Брой = 6. Брой = 7. Брой = 8. Брой = 9. Брой = 10.

Абстрактни типове данни

Концепцията за абстрактни типове данни е ключова в програмирането. Абстракцията предполага отделяне и независимо разглеждане на интерфейса и изпълнението.

Нека разгледаме един пример. Всички гледаме телевизионни програми. Нека наречем телевизора модул или обект. Този обект има интерфейс с потребителя, т.е. контроли (набор от бутони), възпроизвеждане на изображение и звук. Колкото по-напреднал е интерфейсът, толкова по-удобен е телевизорът за използване. Превключваме програмите чрез натискане на определени бутони и в същото време не мислим за физическите процеси, протичащи в телевизора. Експертите знаят за това. Когато избираме телевизор, ние се интересуваме от неговата цена и параметри на производителност, т.е. качество на изображението, звука и т.н. Но не се интересуваме от това какво има вътре. С други думи, връщаме се към свойствата на обекта (модула), които са интерфейс и имплементация. Основната цел на абстракцията в програмирането е именно да отдели интерфейса от имплементацията.

Да се ​​върнем към нашия пример. Да предположим, че някой субект е уверен, че познава добре структурата на телевизора. Той премахва капака и започва да го „подобрява“. Въпреки че понякога това води до някои междинни (локални) успехи, крайният резултат почти винаги е отрицателен. Следователно подобни действия трябва да бъдат забранени. В програмирането това се поддържа от механизми за отказ на достъп или скриване на вътрешни компоненти. На всеки обект (модул) е дадено правото да управлява „собствената си собственост“, т.е. тези функции и операции. Пренебрегването на този принцип нарушава стабилността на системата и често води до нейното пълно разрушаване. Принципът на абстракцията изисква използването на механизми за скриване, които предотвратяват умишлено или случайно модифициране на вътрешни компоненти.

Абстракцията на данни включва дефиниране и разглеждане абстрактни типове данни(ATD) или, което е същото, нови типове данни, въведени от потребителя.

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

Концепция за обектно-ориентирано програмиране

Според дефиницията на авторитет в областта на обектно-ориентираните методи за разработка на програми, Гради Буча, „обектно-ориентираното програмиране (ООП) е методология за програмиране, която се основава на представянето на програма като колекция от обекти, всеки от които е имплементация на определен клас (специален вид тип), а класовете образуват йерархия на принципите на наследимостта.“

Обектно-ориентираната методология, подобно на структурната методология, е създадена с цел да дисциплинира процеса на разработка на големи софтуерни системи и по този начин да намали тяхната сложност и цена.

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

Както знаете, един от принципите на управление на сложността на проекта е декомпозицията. Гради Бух разграничава два вида декомпозиция: алгоритмична (както той нарича декомпозиция, поддържана от структурни методи) и обектно-ориентирана, разликата между които според него е следната: „Разделението по алгоритми концентрира вниманието върху реда на случващите се събития , а разделянето по обекти придава особено значение на факторите, които предизвикват действия или са обект на прилагане на тези действия.

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

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

OO програмирането несъмнено е една от най-интересните области за професионална разработка на софтуер.

Обекти и класове

Основните блокове на обектно-ориентираната програма са обекти и класове. По отношение на съдържанието, един обект може да бъде представен като нещо усетено или въобразено и имащо добре дефинирано поведение. Така един обект може или да бъде видян, или докоснат, или поне да се знае, че е там, например представен под формата на информация, съхранена в паметта на компютъра. Нека дефинираме обект, като се придържаме към мнението на Гради Буча: „Обектът е осезаема единица, която ясно проявява своето поведение.“

Предмет -той е част от реалността около нас, т.е. съществува във времето и пространството (концепцията за обект в програмирането е въведена за първи път в езика Simula). Формално обектът е доста труден за дефиниране. Това може да стане чрез някои свойства, а именно: обектът има състояние, поведение и може да бъде уникално идентифициран (с други думи, има уникално име).

клас -това е набор от обекти, които имат обща структура и общо поведение. Класът е описание (абстракция), което показва как да се конструира променлива от този клас, която съществува във времето и пространството, наречена обект.Значението на изреченията „описание на класови променливи“ и „описание на класови обекти“ е едно и също.

Предметима състояние, поведение и паспорт (средство за еднозначната му идентификация); описват се структурата и поведението на обектите в класове,на които те са променливи.

Нека сега дефинираме понятията състояние, поведение и идентификацияобект.

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

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

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

Вече беше казано по-горе, че процедурният (както и модулният) подход ви позволява да създавате програми, състоящи се от набор от процедури (подпрограми), които изпълняват дадени алгоритми. От друга страна, обектно-ориентираният подход представя програмите като набор от обекти, които взаимодействат помежду си. Обектите взаимодействат чрез съобщения. Да приемем, че нашият обект е кръг. Тогава съобщението, изпратено до този обект, може да бъде: „нарисувай себе си“. Когато кажем, че е изпратено съобщение до обект, ние всъщност извикваме някои функциятози обект (функционален компонент). И така, в горния пример ще извикаме функция, която ще начертае кръг на екрана на дисплея.

Основни принципи на ООП

Основните принципи на стила на обектно-ориентираното програмиране включват:

  • опаковане или капсулиране;
  • наследяване;
  • полиморфизъм;
  • предаване на съобщение.

Опаковка (капсулиране)

включва комбиниране на данни и функции, които манипулират тези данни в един обект. Достъпът до някои данни в пакета може да бъде отказан или ограничен.

Обектът се характеризира като набор от всички негови свойства (например за животни - наличие на глава, уши, очи и т.н.) и техните текущи стойности (глава - голяма, уши - дълги, очи - жълти, и т.н.), както и набор от действия, приемливи за този обект (способността да се яде, седи, стои, бяга и т.н.). Тази комбинация в един обект на двете „материални“ съставни части (глава, уши, опашка, лапи) и действия, които манипулират тези части (действието „бягане“ бързо движи лапите) се нарича капсулиране.

В ООП данните се наричат ​​обектни полета, а алгоритмите се наричат ​​обектни методи.

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

Наследство

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

тогава при създаването на обектно-ориентирана йерархия се приема различен изглед на същия оригинален обект. Обектно-ориентираната йерархия непременно отразява наследяването на свойствата на родителските (покриващите) типове обекти към дъщерните (основните) типове обекти.

Според Gradi Booch, "наследяването е връзка между обекти, в която един обект повтаря структурата и поведението на друг."

Принципът на наследствеността действа в живота навсякъде и всеки ден. Бозайниците и птиците наследяват характеристиките на живите организми; за разлика от растенията, орелът и гарванът наследяват общо свойство за птиците - способността да летят. От друга страна, лъвовете, тигрите, леопардите наследяват „устройството” и поведението, характерно за представителите на разред Felidae и др.

Типовете на горните нива на обектно-ориентирана йерархия обикновено нямат конкретни екземпляри на обекти. Няма, например, конкретен жив организъм, който сам по себе си да се нарича „бозайник“ или „птица“. Такива типове се наричат ​​абстрактни. Конкретните екземпляри на обекти, като правило, имат типове от най-ниските нива на OO йерархията: „Крокодилът Гена“ е специфичен екземпляр на обект от типа „крокодил“, „Котката Матроскин“ е специфичен екземпляр на обект от типа "котка".

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

Принципът на наследяването решава проблема с модифицирането на свойствата на даден обект и дава на ООП като цяло изключителна гъвкавост. Когато работи с обекти, програмистът обикновено избира обект, който е най-близък по своите свойства до решаването на конкретен проблем, и създава един или повече потомци от него, които „могат“ да правят неща, които не са внедрени в родителя.

Последователното прилагане на принципа „наследи и промени“ се вписва добре и силно насърчава постепенния подход към разработването на големи софтуерни проекти.

Когато създавате нов клас чрез наследяване от съществуващ клас, можете:

  • добавете нови компоненти на данни към новия клас;
  • добавяне на нови функционални компоненти към новия клас;
  • замени в новия клас функционалните компоненти, наследени от стария клас.

Полиморфизъм

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

Полиморфизмът е свойството на свързаните обекти (т.е. обекти, които имат един общ родител) да решават проблеми с подобно значение по различни начини. Например действието „бягане“ е обичайно за повечето животни. Всеки от тях обаче (лъв, слон, крокодил, костенурка) извършва това действие по различен начин.

С традиционен (необектно-ориентиран) подход към програмирането, програмистът ще премести животните, като извика отделна подпрограма за конкретно животно и конкретно действие.

В рамките на ООП, поведенческите свойства на даден обект се определят от набора от методи, включени в него, програмистът само посочва кой обект трябва да извърши какви от присъщите му действия и (за разглеждания пример) веднъж описани животински обекти ще се движат по характерен за тях начин, използвайки включените в състава му методи. Чрез промяна на алгоритъма на конкретен метод в потомците на даден обект, програмистът може да даде на тези потомци специфични свойства, които родителят няма. За да промените метод, трябва да го замените в дете, т.е. декларирайте едноименен метод в наследника и изпълнете необходимите действия в него. В резултат на това два метода с едно и също име ще работят в родителския обект и дъщерния обект, като имат различна алгоритмична основа и следователно дават на обектите различни свойства. Това се нарича обектен полиморфизъм.

Така в нашия пример с животински обекти действието „бягане“ ще се нарича полиморфно действие, а разнообразието от форми на проявление на това действие ще се нарича полиморфизъм.

Описание на типа обект

Клас или обект е структура от данни, която съдържа полета и методи. Като всяка структура от данни, тя започва със запазена дума и завършва с оператора край. Формалният синтаксис не е сложен: описание на тип обект се получава чрез замяна на думата в описанието на записа записна дума обектили класи добавете декларация на функции и процедури над полетата.

Тип<имя типа объекта>= обект
<поле>;
<поле>;
….
<метод>;
<метод>;
край ;

В ObjectPascal има специална запазена дума класза описание на обекти, заимстван от C++.

Тип<имя типа объекта>= клас
<поле>;
….
<метод>;
<метод>;
край ;

ObjectPascal поддържа и двата модела на описание на обекта.

Обектният компонент е или поле, или метод. Полето съдържа име и тип данни. Методът е процедура или функция, декларирана в декларация на тип обект, включително специални процедури, които създават и унищожават обекти (конструктори и деструктори). Декларация на метод в рамките на декларация на тип обект се състои само от заглавка. Това е вид предварително описание на подпрограма. Тялото на метода следва декларацията за тип обект.

Пример. Въвежда се тип обект "предшественик", който има поле с данни за име и може да извършва две действия:

  • прокламирайте: „Аз съм прародител!“;
  • дайте името си.

Тип tPredoc = име на обект: низ; (поле с данни за обект)
Процедурна декларация ; (декларация на обектни методи)
Процедура MyName ;
Край ;

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

Процедура tPredoc.Declaration; (имплементация на обектен метод)
започвам
writeln("Аз съм прародител!");
край ;
Процедура tPredoc.MyName ; (имплементация на обектен метод)
започвам
writeln("Аз съм", Име);
край;

В описанията на методите полетата и методите от даден тип се споменават просто по име. Така че методът MyName използва полето Name, без да посочва изрично собствеността си върху обекта, сякаш неявният оператор with е изпълнен<переменная_типа_объект>направи.

Под обекти се разбират и променливи от обектен тип – те се наричат копия. Като всяка променлива, екземплярът има име и тип: те трябва да бъдат декларирани.

…….(декларация на тип обект и описание на неговите методи)
var v 1: tPredoc ; (декларация за екземпляр на обект)
започвам
v1. Име:= "Петров Николай Иванович";
v1.Декларация;
v1.MyName
край.

Използването на поле с данни на v1 обект е същият синтаксис като използването на полета за запис. Извикването на методи на екземпляр на обект означава, че посоченият метод се извиква с данните на обекта v 1. В резултат на това редовете ще бъдат показани на екрана

Аз съм прародител!
Аз съм Николай Иванович Петров

Подобно на записите, полетата на променливите тип обект могат да бъдат достъпни с помощта на квалифицирани идентификатори или оператор with.

Например в текста на програмата, вместо оператори

възможно е да се използва оператор with от този тип

с v1 направете
започвам
Име:= "Петров Николай Иванович";
Декларация ;
Моето име
Край ;

Освен това използването на израза with с типове обекти, както и за записи, е не само възможно, но и препоръчително.

Типова йерархия (наследяване)

Типовете могат да бъдат подредени в йерархия. Един обект може да наследява компоненти от друг тип обект. Наследяващ обект е дете. Обектът, който се наследява, е прародителят. Подчертаваме, че наследяването се отнася само за типове, а не за екземпляри на обекти.

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

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

Производният клас може да включва допълнителни методи, които не съществуват в основния клас. Може да предефинира методите (или дори да ги премахне изцяло).

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

Процесът на наследяване може да продължи. Клас, който е извлечен от базов клас, може сам да стане базов клас за други производни класове. По този начин OO програмите създават класова йерархия.

Най-често структурата на класовата йерархия се описва като дърво. Върховете на дървото съответстват на класове, а коренът съответства на клас, който описва нещо общо (най-често срещано) за всички останали класове.

Наследяването от дъщерни типове на информационни полета и методи на техните родителски типове се извършва съгласно следните правила.

Правило 1. Информационните полета и методите на родителския тип се наследяват от всички негови дъщерни типове, независимо от броя на междинните нива на йерархията.

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

Правило 3. Никой дъщерен тип не може да използва идентификаторите на полетата на своите родителски типове.

Правило 4. Дъщерен тип може да дефинира произволен брой свои собствени методи и информационни полета.

Правило 5. Всяка промяна на текста в родителски метод автоматично засяга всички методи на дъщерните типове, които го извикват.

Правило 6. За разлика от информационните полета, идентификаторите на методите в дъщерните типове могат да бъдат същите като имената на методите в родителските типове. В този случай се казва, че дъщерният метод замества (потиска) родителския метод със същото име. В рамките на дъщерен тип, когато се указва името на такъв метод, ще бъде извикан дъщерният метод, а не родителският.

Нека продължим с нашия пример. В допълнение към типа предшественик tPredoc, който въведохме, можем да въведем типове наследници:

ture tSon= object(tPredoc) (Тип, който наследява tPredoc)
процедура Декларация; (припокриващи се предходни методи)
процедура Моето име(Predoc: tPredoc);
край ;

Тип tGrandSon=object(tSon) (Тип, наследен от tSon)
процедура Декларация ; (припокриващи се предходни методи)
край ;

Името на типа предшественик е дадено в скоби след думата обект.Създадохме наследствена йерархия от три типа: tSon („син“) е наследник на типа tPredoc, а типът tGrandSon („внук“) е наследник на типа tSon. Типът tSon отменя методите Declaration и My Name, но наследява полето Name. Типът tGrandSon заменя само метода за декларация и наследява полето за име от неговия общ предшественик, а заменения метод за декларация от своя непосредствен предшественик (тип tSon).

Нека да разберем какво точно искаме да променим в родителските методи. Факт е, че „синът” трябва да провъзгласи малко по-различно от своя прародител, а именно да каже „Аз съм бащата!”

процедура tSon.Declaration; (имплементация на методи на наследствени обекти)
започвам
writeln("Аз съм бащата!");
край;

И когато дава името си, „синът“ трябва да предостави следната информация:

  • аз<фамилия имя отчество >
  • Аз съм синът<фамилия имя отчество своего предка>

процедура tSon .My Name (predoc: tPredoc);
започвам
наследени Mu Име ; (извикване на метод на непосредствен предшественик)
writeln("Аз съм синът", predoc.Name, "a");
край;

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

Сега да се заемем с "внука". Методът, в който "внукът" казва името си, е точно същият като неговия непосредствен предшественик (тип tSon), така че няма нужда да отменяте този метод, по-добре е автоматично да наследите този метод и да го използвате като свой собствен. Но в метода Декларация трябва да декларирате „Аз съм внук!“, така че методът ще трябва да бъде предефиниран.

процедура tGrandSon.Declaration;
започвам
writeln("Аз съм внук!");
край;

Нека разгледаме пример за програма, в която дефинираме екземпляр от типа tPredoc, наричаме го „дядо“, екземпляр от типа tSon „баща“ и екземпляр от типа tGrandSon „внук“. Нека ги помолим да се представят.

Примерна програма, използваща ООП

(заглавие на програмата)
……………….
(раздел с описания на типове, включително типове обекти tPredoc, tSon, tGrandSon)
(Забележка! Екземплярите на типове обекти могат да бъдат описани като въведени константи, което направихме по-долу за примера)
конст ded: tPredoc = (Име: "Николай Иванович Петров");
otec: tSon = (Име: "Петров Сергей Николаевич");
vnuk: tGrandSon = (Име: "Петров Олег Сергеевич");
(раздел с описания на процедури и функции, където трябва да бъдат написани всички методи, декларирани в типове обекти)
започвам
дед.Декларация; (извикване на методи с общ предшественик)
ded.Моето име;
writeln;
otec.Декларация;
otec.MyName(ded); (извикващи методи на otec обект от тип tSon)
writeln;
vnuk.Декларация; (извикващи методи на vnuk обект от тип tGrandSon)
vnuk.MyName(otec);
край.

Нашата програма ще покаже:

Пример за показване на резултата

Аз съм прародител!
Аз съм Николай Иванович Петров

Аз съм бащата!
Аз съм Петров Сергей Николаевич
Аз съм син на Петров Николай Иванович

Аз съм внук!
Аз съм Петров Олег Сергеевич
Аз съм син на Сергей Николаевич Петров

Моля, обърнете внимание, че в заглавката на процедурата tSon. MyName получава тип данни tPredoc като параметър и при използване на тази процедура му се предават променливи от двата типа tPredoc и tSon. Това е възможно, защото предшественикът е типово съвместим със своите потомци. Обратното не е вярно. Ако заменим tSon в заглавката на процедурата. MyName, когато описва параметри от тип tPredoc на tSon, компилаторът ще посочи несъвместимост на типа, когато използва променливата ded в реда otec. MyName(ded).

Полиморфизъм и виртуални методи

Полиморфизъм– това е свойството на свързаните обекти (т.е. обекти, които имат един и същ родител) да решават проблеми с подобно значение по различни начини.

Два или повече класа, които са извлечени от един и същ базов клас, се наричат ​​полиморфни. Това означава, че те могат да имат общи характеристики, но и да имат свои собствени свойства.

В рамките на ООП поведенческите свойства на даден обект се определят от набора от методи, включени в него. Чрез промяна на алгоритъма на конкретен метод в потомците на даден обект, програмистът може да даде на тези потомци специфични свойства, които родителят няма. За да промените метод, трябва да го замените в дете, т.е. декларирайте едноименен метод в наследника и изпълнете необходимите действия в него. В резултат на това два метода с едно и също име ще работят в родителския обект и дъщерния обект, като имат различна алгоритмична основа и следователно дават на обектите различни свойства. Това се нарича обектен полиморфизъм.

В примера, обсъден по-горе, и трите типа обекти tPredoc, tSon и tGrandSon имат едни и същи методи Declaration и MyName. Но обектният тип tSon имплементира метода MyName малко по-различно от своя предшественик. И трите метода за декларация с едно и също име се изпълняват по различен начин за всеки обект.

Обектните методи са статични, виртуални и динамични.

Статични методи

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

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

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

Виртуални методи

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

Този принципно нов механизъм, наречен късно свързване, осигурява полиморфизъм, т.е. различен начин на поведение за различни, но еднородни (в смисъл на наследяване) обекти.

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

процедура Метод (списък с параметри); виртуален;

Използването на виртуални методи в йерархията на типа обект има определени ограничения:

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

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

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

Конструкторът е специален метод, който инициализира обект, съдържащ виртуални методи. Заглавката на конструктора изглежда така:

Метод на конструктора (списък с параметри);

Запазена дума конструкторзамества думите процедура и виртуален .

Основната и специална цел на конструктора е да установява връзки с таблицата на виртуалните методи (VMT) - структура, съдържаща препратки към виртуални методи. По този начин конструкторът инициализира обекта чрез установяване на връзка между обекта и VMT с адресите на кодовете на виртуалния метод. По време на инициализация възниква късно свързване.

Всеки обект има своя собствена VMT виртуална таблица с методи. Това е, което позволява на метода със същото име да извиква различни процедури.

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

Заглавката на деструктора изглежда така:

деструктор Готово;

Основната цел на деструкторите е да унищожат VMT на даден обект. Често деструкторът не прави нищо друго и е празна процедура.

деструктор Готово;
начало край;

Обектно-ориентирано програмиране(OOP) ви позволява да разложите проблем на съставни части, всяка от които става независим обект. Всеки от обектите съдържа свой собствен код и данни, които се отнасят до този обект.

Всяка програма, написана на ООП език, отразява в своите данни състоянието на физически обекти или абстрактни концепции - програмни обекти, с които е предназначена да работи.

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

Един обект е свързан с набор от действия, иначе наричани методи. От гледна точка на езика за програмиране, набор от действия или методи са функции, които получават указател към обект като задължителен параметър и извършват определени действия с данните на програмния обект. OOP технологията забранява работата с обект по друг начин освен чрез методи, като по този начин вътрешната структура на обекта е скрита от външния потребител.

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

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

Един клас може да се сравни с план, според който са създадени обектите. Обикновено класовете се разработват по такъв начин, че техните обекти да съответстват на обектите от домейна на проблема, който се решава.

Основни понятия на обектно-ориентираното програмиране

Всяка функция в програмата е метод за обект от някакъв клас.

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

Цялата програма в тази форма е обект от някакъв клас с един метод за изпълнение.

Програмирането от клас към клас включва редица нови концепции. Основните понятия на ООП са

  • капсулиране;
  • наследяване;
  • полиморфизъм.

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

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

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

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

Наследство . Нов или производен клас може да бъде дефиниран въз основа на съществуващ или основен клас.

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

С други думи, новият клас наследява както данните от стария клас, така и методите за тяхната обработка.

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

Пример за наследяване е дефиницията на структура, чийто отделен член е предварително дефинирана структура.

Полиморфизмът е свойство, което позволява един и същ идентификатор (едно и също име) да се използва за решаване на два или повече подобни, но технически различни проблема.

Целта на полиморфизма, приложена към ООП, е да се използва едно име за определяне на действия, общи за редица класове обекти. Такъв полиморфизъм се основава на възможността за включване в обектните данни на информация за методите за тяхната обработка (под формата на указатели към функции).

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

Например намирането на абсолютна стойност в C изисква три различни функции с различни имена.

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

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

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

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

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

Основни ООП концепции

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

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

ООП се характеризира със следните принципи (според Алън Кей):

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

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

Абстракцияви позволява да отделите логическото значение на програмен фрагмент от проблема с неговото изпълнение, разделяне външно описание(интерфейс) на обект и неговите вътрешна организация(изпълнение).

Определение 10.2. Капсулиране- техника, при която вътре в него е скрита информация, която е незначителна от гледна точка на интерфейса на обекта.

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

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

Определение 10.4.

Концепцията за обектно-ориентирано програмиране (ООП) се появи преди повече от четиридесет години, като развитие на идеите на процедурното програмиране. Идеологията на процедурното програмиране не е нищо особено: всички програми са представени от набор от процедури и функции, докато самите процедури и функции са последователности от изрази, изпълнявайки които компютърът променя стойностите на променливите в паметта. Основната програма в процедурното програмиране също е процедура (функция), чието тяло може да съдържа извиквания на други процедури и функции - подпрограми. Същността на процедурното програмиране е проста: данните са отделни, поведението е отделно. Опитах се да събера от какво се състои процедурният език за програмиране (какви конструкции включва) в отделен раздел. Разделянето на кода на подпрограми, първо, ви позволява да маркирате фрагменти от код за многократна употреба, и второ, прави програмния код структуриран.

Идеологията на обектно-ориентираното програмиране, както подсказва името, е изградена около концепцията за обект. Един обект съчетава както данни, така и поведение. Обект е всеки обект, с който работи програмата, а именно: обекти на домейн, моделирани от програмата; ресурси на операционната система; мрежови протоколи и много други. По същество обектът е същата структура (композитен тип), но допълнена с процедури и функции, които управляват елементите на тази структура. Например, за да работите с файл на процедурен език за програмиране, ще бъде създадена променлива отделно за съхраняване на името на файла и отделно за съхраняване на неговия дескриптор (уникален идентификатор на ресурс в операционната система), както и редица процедури за работа с файла: отваряне на файла, четене на данни от файла и затваряне на файла. Всички тези процедури, в допълнение към обичайните параметри и променливи за съхраняване на резултата, ще трябва да приемат един и същ дескриптор, за да разберем за кой файл говорим. В обектно-ориентиран език за същата цел ще бъде описан файлов обект, който също ще съхранява име и манипулатор в себе си и ще предоставя на потребителя процедури за отваряне, четене и затваряне на самия себе си (файлът, свързан със специфичен обект). Разликата би била, че манипулаторът ще бъде скрит от останалата част от програмата, създаден в рутинния код за отваряне на файла и използван само имплицитно от самия обект. По този начин потребителят на обекта (програмният код на външната за обекта програма) не би трябвало да предава манипулатора всеки път в параметрите на процедурата. Обектът е набор от данни и методи за работа с тези данни, някои от които може да са скрити от света около тях, което включва подробности за изпълнението. Терминологията на обектно-ориентираното програмиране ще бъде разгледана по-подробно по-долу.

В един обектно-ориентиран език за програмиране почти всичко е обект, с изключение на операторите: елементарните типове са обекти, описанието на грешка е обект и накрая основната програма също е обект. Остава да разберем какво е обект от гледна точка на самата програма, как се създава и използва. Втората основна концепция на ООП е класът. Класът е нов тип данни в сравнение с процедурното програмиране, чиито екземпляри се наричат ​​обекти. Класът, както вече беше споменато, е подобен на съставен тип данни или структура, но допълнен с процедури и функции (методи) за работа с неговите данни. Сега е моментът да опишем основните термини на обектно-ориентираното програмиране.

Терминология на обектно-ориентираното програмиране

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

  • Клас– тип данни, който описва структурата и поведението на обектите.
  • Предмет– екземпляр на клас.
  • Поле– елемент от данни на клас: променлива от елементарен тип, структура или друг клас, който е част от клас.
  • Състояние на обекта– набор от текущи стойности на полето на обект.
  • Метод– процедура или функция, която се изпълнява в контекста на обекта, на който е извикана. Методите могат да променят състоянието на текущия обект или състоянието на обекти, предадени им като параметри.
  • Имот– специален вид методи, предназначени за модифициране на отделни полета на обект. Имената на свойствата обикновено са същите като имената на съответните полета. Външно работата със свойствата изглежда абсолютно същата като работата с полета от структура или клас, но всъщност, преди да се върне или присвои нова стойност на поле, може да се изпълни програмен код, който извършва различни видове проверки, например проверка дали новата стойност е валидна.
  • Член на класа– полета, методи и свойства на класа.
  • Модификатор за достъп– допълнителна характеристика на членовете на класа, която определя дали те са достъпни от външна програма или се използват изключително в границите на класа и скрити от външния свят. Модификаторите за достъп разделят всички членове на клас в подробности за изпълнението и публичен или частично публичен интерфейс.
  • Конструктор– специален метод, изпълняван веднага след създаване на екземпляр на клас. Конструкторът инициализира полетата на обекта – привежда обекта в първоначалното му състояние. Конструкторите могат да бъдат със или без параметри. Конструктор без параметри се нарича конструктор по подразбиране, който може да има само един. Името на метода на конструктора най-често съвпада с името на самия клас.
  • Деструктор– специален метод, извикван от средата за изпълнение на програмата в момента, когато даден обект се изтрива от RAM. Деструкторът се използва в случаите, когато класът включва ресурси, които изискват изрично освобождаване (файлове, връзки към бази данни, мрежови връзки и т.н.)
  • Интерфейс– набор от методи и свойства на обект, които са публично достъпни и предназначени за решаване на определен набор от проблеми, например интерфейс за генериране на графично представяне на обект на екрана или интерфейс за запазване на състоянието на обект във файл или база данни.
  • Статичен член– всеки елемент от клас, който може да се използва без създаване на съответен обект. Например, ако метод на клас не използва нито едно поле, а работи изключително с параметрите, които са му предадени, тогава нищо не пречи той да се използва в контекста на целия клас, без да се създават отделни негови екземпляри. Константите в контекста на клас обикновено винаги са статични членове на класа.

Предимства на обектно-ориентираното програмиране

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

  • Капсулиранеозначава скриване на подробностите за изпълнение на клас чрез възнаграждаване на отделни членове с подходящи модификатори за достъп. По този начин цялата функционалност на даден обект, насочен към взаимодействие с други програмни обекти, е групирана в отворен интерфейс, а детайлите са внимателно скрити вътре, което спестява основния бизнес логически код на информационната система от ненужни неща. Капсулирането подобрява надеждността на вашия код, защото гарантира, че определени данни не могат да бъдат променени извън съдържащия се клас.
  • Наследство. Крайъгълният камък на ООП. В обектно-ориентираното програмиране е възможно да се наследи структурата и поведението на един клас от друг клас. Класът, от който те наследяват, се нарича база или суперклас, а класът, който се получава в резултат на наследяването, се нарича производен или просто потомък. Всеки клас може да действа както като суперклас, така и като потомък. Отношенията на наследяване на класове образуват класова йерархия. Множественото наследяване е дефиницията на клас, извлечен от няколко суперкласа едновременно. Не всички обектно-ориентирани езици за програмиране поддържат множествено наследяване. Наследяването е ефективен начин за изолиране на части от код за многократна употреба, но има и недостатъци, които ще бъдат обсъдени по-късно.
  • Абстракция. Възможност за комбиниране на класове в отделни групи, подчертавайки общи характеристики, които са значими за всички тях (общи полета и общо поведение). Всъщност абстракцията е следствие от наследяването: базовите класове не винаги имат собствена проекция върху обекти от реалния свят, а са създадени единствено с цел подчертаване на общите характеристики на цяла група обекти. Например мебелният предмет е основно понятие за маса, стол и диван, като всички те са обединени от факта, че са движима вещ, част от интериора на помещението и могат да бъдат направени за дома или офиса , а също така се отнасят за „икономичен“ или „премиум“ ” към класа. В OOP има отделна концепция за това: абстрактен клас - клас, чиито обекти са забранени за създаване, но могат да се използват като базов клас. Наследяването и абстракцията позволяват да се опишат програмните структури от данни и връзките между тях по точно същия начин, както изглеждат съответните обекти в разглеждания модел на домейн.

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

Диаграма на класове или йерархия на наследяване „Превозни средства“. Белите квадрати представляват абстрактни класове.

  • Полиморфизъм. Друго имущество, което е следствие от наследство. Факт е, че обектно-ориентираните езици за програмиране ви позволяват да работите с набор от обекти от една и съща йерархия по същия начин, сякаш всички те са обекти от техния базов клас. Ако се върнем към примера с мебелите, можем да предположим, че в контекста на създаването на информационна система за мебелен магазин е разумно да добавим общ метод „показване на характеристиките“ към базовия клас за всички видове мебели. При разпечатване на характеристиките на всички видове стоки, програмата извиква този метод безразборно за всички обекти, като всеки конкретен обект сам решава каква информация да му предостави. Как се прилага това: Първо, базовият клас дефинира общ метод за всички с общо поведение. В случая с нашия пример, това ще бъде метод, който отпечатва параметри, общи за всички видове мебели. Второ, във всеки производен клас, където е необходимо, те предефинират основния метод (добавяйки метод със същото име), където разширяват основното поведение със свои собствени, например показват характеристики, които са характерни само за определен тип мебелен продукт. Методът в базов клас понякога не трябва да съдържа никакъв код, а е необходим само за дефиниране на име и набор от параметри - сигнатурата на метода. Такива методи се наричат ​​абстрактни методи и класовете, които ги съдържат, автоматично стават абстрактни класове. И така, полиморфизмът е способността за еднаква комуникация с обекти от различни класове чрез специфичен интерфейс. Идеологията на полиморфизма гласи, че за да комуникирате с обект, не е нужно да знаете неговия тип, а по-скоро какъв интерфейс поддържа.
  • Интерфейс. В някои езици за програмиране (C#, Java) концепцията за интерфейс е ясно дефинирана - това не са само публични методи и свойства на самия клас. Такива езици, като правило, не поддържат множествено наследяване и компенсират това, като позволяват на всеки обект да има един основен обект и да реализира произволен брой интерфейси. В тяхната интерпретация интерфейсът е като абстрактен клас, съдържащ само описание (сигнатура) на публични методи и свойства. Внедряването на интерфейс пада върху плещите на всеки клас, който възнамерява да го поддържа. Един и същи интерфейс може да бъде реализиран от класове с напълно различни йерархии, което разширява възможностите на полиморфизма. Например, интерфейсът „запазване/възстановяване на информация в база данни“ може да бъде реализиран както от класовете на йерархията „мебели“, така и от класовете, свързани с пускането на поръчки за производство на мебели, и когато щракнете върху бутона „запази“, програмата ще премине през всички обекти, ще ги попита за този интерфейс и ще извика съответния метод.

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

Някои елементи на съвременното обектно-ориентирано програмиране

Времето не стои неподвижно и вече е минало доста време от появата на OOP, така че не трябва да е изненадващо, че днес речникът на обектно-ориентираното програмиране е нараснал значително. И така, ето някои нови термини и концепции, свързани с ООП.

  • събития. Специален тип обекти, създадени за уведомяване на някои обекти за събития, случващи се с други обекти. В различните езици за програмиране механизмът за събития се реализира по различни начини: понякога с помощта на специални синтактични конструкции, а понякога с помощта на основни ООП инструменти.
  • Универсален тип. Концепцията за генерични типове не е пряко свързана с концепцията за ООП, но е причина за появата на елементи като генеричен клас, генеричен метод, генерично събитие и др. Общият тип е тип, който е параметризиран от друг тип (набор от типове). Какво представлява този тип параметър в контекста на дизайна на общия тип е неизвестно, въпреки че е възможно да се ограничат стойностите на типовете параметри, като ги принудите да произлизат от конкретен клас или да внедрят определени интерфейси. Пример е универсален клас за сортиране на последователност от елементи, където типът на елемента в последователността е предварително неизвестен. При проектирането на такъв клас е важно да се уточни, че типът параметър трябва да поддържа операцията за сравнение. Когато създавате обекти от общи типове, вие изрично посочвате параметър, като тип цяло число или низ, и самият обект започва да се държи така, сякаш е екземпляр на клас, създаден специално за сортиране на цели числа или низове.
  • Изключения. Друг специален тип обект, поддържан от механизъм за обработка на грешки и изключения, вграден в специфичен език за програмиране. Изключенията, в допълнение към кода на грешката, съдържат нейното описание, възможните причини и набор от извиквания на методи, възникнали преди изключението да се появи в програмата.

Недостатъци на обектно ориентираното програмиране

Вече казах, че популярността на обектно-ориентирания подход за създаване на софтуерни продукти е огромна. Също така вече отбелязах, че има доста хора, които се стремят да разширят тази парадигма. Но има и друг начин да се откроите сред огромната общност от специалисти по информационни технологии - това е да заявите, че ООП не се оправда, че не е панацея, а по-скоро плацебо. Сред тези хора има наистина много висококласни специалисти като Кристофър Дейт, Александър Степанов, Едсгер Дейкстра и други, чието мнение заслужава внимание, но има и такива, за които казват, че „винаги нещо пречи на лош танцьор." Ето ги най-очевидните недостатъци на ООП, които експертите посочват:

1. OOP генерира огромни класови йерархии, което води до факта, че функционалността е разпръсната или, както се казва, замъглена в базовите и производните членове на класа и става трудно да се проследи логиката на работата на конкретен метод.

2. В някои езици всички данни са обекти, включително елементарни типове, и това не може да не доведе до допълнителна памет и потребление на процесорно време.

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

4. Психологически аспект. Много хора смятат, че ООП е готино и започват да използват неговите подходи винаги и навсякъде и безразборно. Всичко това води до намаляване на ефективността на програмата в частност и дискредитиране на ООП като цяло.