→ Пошук по сайту       Увійти / Зареєструватися
Знання Мова програмування C#

Основні поняття ООП: об'єкти, класи і методи.

Викладемо апарат об'єктно-орієнтованого підходу до програмування.

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

Сформулюємо на інтуїтивному рівні визначення таких основоположних для об'єктно-орієнтованого підходу до програмування понять, як об'єкт, клас, властивість і метод.

Під об'єктом будемо розуміти математичне представлення сутності реального світу (або предметної області), яке використовується для моделювання.

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

Під властивістю (або атрибутом) будемо розуміти пропозиційну функцію, визначену на довільному типі (даних).

Методом (або функцією) назвемо операцію, яка визначена над об'єктами того чи іншого класу.

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

Функцію такого роду прийнято називати індивідуалізуючою функцією. Індивідуалізуюча функція фактично є моделлю експертної класифікації.

Важливою умовою при дослідженні об'єктно-орієнтованого підходу до програмування є встановлення взаємозв'язків фундаментальних сутностей. Зазначимо у цьому зв'язку, що поняття класу є спочатку більш загальним, ніж поняття об'єкта. Точніше, кажуть, що об'єкт є екземпляром (instantiation) класу.

Таким чином, клас може розглядатися як сукупність об'єктів (подібно до того як множина або домен є сукупністю елементів).

У рамках об'єктно-орієнтованого підходу до програмування довільний клас може бути елементарним або розділятися на підкласи (подібно до того як множина або домен підрозділяється на підмножини або субдомени).

Наприклад, більш загальний клас PERSON може містити усередині себе підклас STUDENT, який, у свою чергу, містить конкретний об'єкт John_Smith.

Як зазначалося у вступній лекції, в 90-і роки В.Е. Вольфенгагеном (Vyatcheslav E. Wolfengagen) була створена так звана дворівнева схема концептуалізації, заснована на дворазовому застосуванні постулату згортання, до певної міри аналогічного операції ламбда-абстракції.

Розглянемо більш детально основні аспекти даної формалізації об'єктно-орієнтованого підходу до програмування. У загальних рисах схема побудови моделі виглядає наступним чином.

Основу моделі складає типізований варіант ламбда-числення, семантика якого моделюється за допомогою повних і безперервних решіток Д. Скотта.

Для опису об'єктів довільної складності вводяться аплікативні структури з приписуванням типів. Остання обставина необхідна для формалізації ієрархії класів, в які об'єднуються об'єкти.

Для формалізації визначень використовуються певні дескрипції Скотта-Фурмана виду:

IxФ 

що означає "той єдиний об'єкт x, для якого значення індивідуалізуючої функції Ф істинно".

При такому підході довільний об'єкт моделюється впорядкованою трійкою елементів виду:

<Концепт, індивід, стан> 

складові якої з'єднані співвідношенням.

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

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

| | Ix (x) Ф (x) | | i = d <=>
{D} = {d D | | | Ф (d) | | i = true} 

Наведемо словесну інтерпретацію формули: значенням індивідного концепту є функція з співвідносної в індивіди.

З точки зору даної формальної теорії, довільний об'єкт d предметної області D може бути єдиним способом індивідуалізований за допомогою функції Ф (де i означає співвідношення).

Зауважимо, що при співвідношенні загальної теорії з мовами програмування домен D можна також інтерпретувати як клас, а елемент домену d - як об'єкт мови програмування.

Розглянувши інтуїтивне визначення поняття класу, а також представивши домени як формальні моделі класів мов програмування в цілому, зупинимося детальніше на класах у мові об'єктно-орієнтованого програмування C #.

За аналогією з іншими відомими мовами об'єктно-орієнтованого програмування (зокрема, C + + і Java), під класом в мові C # розуміється ні що інше, як контрольний тип, визначений користувачем.

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

Членами (або, інакше, елементами) класу мови програмування C # можуть бути такі конструкції:

  • Константа, поле, метод, оператор, конструктор, деструктор;
  • Властивість, індексатор, подія;
  • Статичні і початкові члени.

Доступ до членів класу визначається виходячи із значення модифікатора області дії ідентифікатора класу, який може приймати такі значення: public, protected, private (дане значення використовується за замовчуванням), internal, protected internal.

Ініціалізація об'єкту класу мови програмування C # проводиться за допомогою оператора new, про яке буде розказано нижче.

Розглянемо маніпулювання класами на прикладі наступних фрагментів програм мовою C #.

Перш за все, наведемо найпростіше опис класу. Опис класу C c цілочисловим полем value на мові C # має вигляд:

class C
{
        ...
        int value = 0;
        ...
} 

Зауважимо, що в описі класу C на мові програмування C # крім розглянутого поля value можуть бути присутні й інші поля (тобто атрибути об'єктів класу) допустимих в мові C # типів, а також методи (тобто способи маніпулювання об'єктами даного класу).

У мові програмування C # ініціалізація поля (тобто зв'язування його з початковим значенням) не є обов'язковою. Для забезпечення безпеки програмного коду і через реалізацію принципу інкапсуляції, ініціалізація поля деякого класу C не повинна відкривати можливості для доступу до полів і методів даного типу. При цьому доступ до елементів класу всередині класу реалізується за допомогою обігу і не вимагає повного імені об'єкта:

... value ... 

На відміну від попереднього випадку, доступ з сторонніх класів вимагає вказівки повного імені об'єкта (у прикладі послідовно виробляються ініціалізація і звернення):

C c = new C ();
... c.value ... 

Розглянемо більш розгорнутий приклад опису класів і маніпулювання їхніми елементами.

Наведемо опис класу Rectangle, що моделює прямокутник з полями origin, width і height, вказуючи, відповідно, початкову точку (з парою координат), ширину і висоту, а також методом MoveTo, моделюючим переміщення початкової точки в задану:

class Rectangle
{
        Point origin;
        public int width, height;
        public Rectangle()
        {
               origin = new Point(0,0);
               width=height=0;
        }
        public Rectangle(Point p, int w, int h)
        {
               origin = p;
               width = w;
               height = h;
        }
        public void MoveTo (Point p)
        {
              origin = p;
        }
} 

Зауважимо, що модифікатор області видимості для даного класу і його елементів дозволяє загальнодоступне застосування (public). Розглянемо приклад використання класу Rectangle:

Rectangle r = new Rectangle (
new Point (10,20), 5,5);
int area = r.width * r.height;
r.MoveTo (new Point (3,3)); 

Зауважимо, що в даному прикладі послідовно здійснюються ініціалізація об'єкта класу Rectangle з початковою точкою (10,20), шириною і висотою в п'ять одиниць (тобто квадрата), підрахунок його площі area і переміщення початку відліку в точку з координатами (3, 3).

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

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

class Rectangle
{
      static Color defaultColor;
      // Для кожного класу
      static readonly int scale;
      // Для кожного класу
      int x, y, width, height;
      // Для кожного об'єкта
      ...
} 

Зауважимо, що статичні поля defaultColor і scale залишаються незмінними всередині класу, тоді як динамічні поля x, y, width і height індивідуально змінюються в залежності від стану кожного з об'єктів класу. Доступ зсередини класу здійснюється за допомогою звернення:

... defaultColor ... scale ... 

а із зовнішніх класів - за допомогою звернення:

... Rectangle.defaultColor
 ... Rectangle.scale ... 

із зазначенням повних імен об'єктів. Оскільки статичні поля є незмінними з часом, вони реалізуються виділенням пам'яті з статичної області.

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

Розглянемо особливості використання методів на прикладі наступної програми на мові C #, що представляє опис класу C з полями sum і n і методами Add і Mean:

class C
{
        int sum = 0, n = 0;
        public void Add (int x)
        {
               sum = sum + x; n++;
               //процедура
        }
        public float Mean()
        {
               return(float)sum/n;
               //функція (повинна повертати
               //значення)
       }
} 

Перш за все, відзначимо, що методи в мові програмування C # діляться на функції (які зобов'язані повертати значення) та процедури (які можуть і не повертати значення, на що вказує тип void). У даному прикладі Add - процедура, а Mean - функція, в якій повернення значення явно вказується оператором return. Доступ до методу, як і до поля, можна отримати зсередини класу:

this.Add (3);
float x = Mean (); 

а також з інших класів, з явною вказівкою повного імені:

c = new C ();
c.Add (3);
float x = c.Mean (); 

Зауважимо, що оператор this являє собою вказівник на поточний об'єкт.

Продовжуючи аналогію між полями та методами як елементами класів, ми приходимо до поняття статичного методу. Розглянемо особливості реалізації статичних методів у мові програмування C#  на наступному прикладі:

class Rectangle
{
        static Color defaultColor;
        public static void ResetColor ()
        {
            defaultColor = Color.white;
        }
} 

Як виявляється з наведеного прикладу, під статичним методом розуміється операція над статичними елементами класів (тобто над статичними полями).

У даному прикладі опису класу Rectangle статичним є метод ResetColor (зауважимо, що він не повертає значення, тобто ResetColor - це статична процедура).

За аналогією з попередніми випадками, для доступу до статичного методу зсередини класу достатньо вказати тільки коротке ім'я даного методу:

ResetColor (); 

У разі доступу з сторонніх класів необхідно вказати повне ім'я статичного методу:

Rectangle.ResetColor ();

Дослідивши особливості опису та управління поведінкою основних елементів класів, об'єктів і методів для динамічного і статичного випадків, коротко зупинимося на особливостях наслідування властивостей (полів та методів) класів об'єктів мови програмування C #. Для ілюстрації наведемо наступний приклад фрагмента програми на мові C #:

class Stack
{
        int[] values;
        int top = 0;
        public Stack(int size)
        {
               ...
        }
        public void Push(int x)
        {
               ...
        }
        public int Pop()
        {
               ...
        }
} 

У даній програмі наведено (зі скороченнями) опис класу, що моделює стек (аналогічний стеку КАМ) за допомогою масиву елементів values з вершиною top, функціями створення стека Stack розміром size і "виштовхування" Push елемента x з стека, а також "внесення" Pop елемента в стек.

Аналогічно об'єктам посилальних типів, об'єкти класів (як принципово динамічні) зберігаються в динамічній області пам'яті (або так званої "купі"). У силу обмежень безпеки програмного коду будь-який об'єкт мови програмування C # до використання необхідно ініціалізувати оператором new, наприклад:

Stack s = new Stack (100);
 

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

Підводячи підсумки обговорення основних понять об'єктно-орієнтованого підходу до програмування (класів, об'єктів і методів) стосовно мови програмування C #, коротко відзначимо переваги і недоліки підходу.

До переваг об'єктно-орієнтованого підходу слід віднести:

  • Інтуїтивну близькість довільної предметної області;
  • Можливість моделювання як завгодно складною предметної області, високий рівень абстракції (розглянуті приклади дають уявлення про "масштабованості" моделювання складних об'єктів);
  • Подієво-орієнтований підхід (динаміка об'єктів і можливість маніпулювання ними за допомогою методів приводять до управління об'єктами за допомогою подій);
  • Можливість повторного використання описів (заснована на зверненні до полів і методів ззовні опису класів, а також на використанні механізму успадкування);
  • Параметризація методів обробки об'єктів (заснована на використанні механізму інтерфейсів, які будуть детально розглянуті в ході подальших лекцій).

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

загрузка...
Сторінки, близькі за змістом