Розум-орієнтоване програмування h2>
Дмитро Сахань p>
Не
здається вам, що нині програмування інтелекту уперлося в непереборну
стіну? Тоді давайте спершу поміркуємо про еволюцію самого
програмування. На зорі розвитку (історія набагато глибше, але ми почнемо від
перший Бейсік) програмування обмежувалося простим командним
програмуванням. Не було поняття процедур і функцій, були тільки змінні і
оператори, тобто команди. Код програми виглядав у вигляді пронумерованого
списку інструкцій. Єдиною на той момент командою переходу між рядками
вихідного коду був оператор GOTO. Безумовно, дуже скоро можливості
командного програмування вичерпалися, потрібно було розширити його рамки. p>
Першої
ластівкою процедурного програмування з'явився оператор GOSUB - виклик
підпрограми. Але це ще не було процедурне програмування в чистому вигляді.
Був лише факт, що крок зроблений у правильному напрямку. Через короткий час
ідея виклику підпрограм оформилася у виклики функцій і процедур, а
програмування стало називатися процедурних. Основна фішка такого підходу
полягала в тому, що процедури і функції могли приймати велику кількість
вхідних параметрів, тобто код процедур вже не обов'язково повинен був
прив'язуватися до імен глобальних змінних. Разом з цим народилося поняття
глобальних і локальних (доступних тільки всередині процедури) змінних. Крім
того функції могли повертати результат виконання в викликала їхню точку
вихідного коду. У свою чергу це призвело до можливості рекурсивного
програмування (коли функція викликає саму себе N раз, аналізуючи свій же
повертається результат), яке по суті справи є стилем процедурного
програмування, а не окремим програмуванням. Ще з появою
процедурного програмування відпала необхідність нумерації рядків програми,
тому що функції та процедури мали свої імена і могли вільно розташовуватися в
будь-якому місці коду (нумерація же строк прив'язує фрагмент коду до певного
місцю розташування в вихідному коді). p>
Програмісти
швидко оцінили новий підхід і кинулися використовувати його можливості. Ще через
часом стали помітні вади і в ньому. Все більше ускладнювалися програми, всі
складніше ставало керувати зростаючою кількістю змінних, все чіткіше
переглядалася "спорідненість" між деякими змінними, все сильніше
розбухали рядка вхідних параметрів процедур. І ось комусь спало на думку
об'єднати споріднені змінні в структури, а нове програмування отримало
назва структурного або, іншими словами, орієнтованого під структури. Тут
ж з'явилися поняття структур (іноді їх називають записами), а також
що містяться в структурах полів даних, покажчиків на структури (щоб не
тягти вміст структури через стек) і такого іншого. Істотний плюс
полягав у можливості вкласти в структуру інші структури, в які, в
свою чергу, могли бути вкладені ще які-небудь структури. Тепер процедура
могла приймати у вхідному параметрі всього одну змінну (структуру), а вже
з неї витягувати будь-які вкладені дані (поля). Відразу ж склалася зручна
практика вказувати потрібне поле, перераховуючи через символ точки (в мові Сі
через "->") повний шлях до поля всередині структури. p>
AgeData
= Record// оголошення структури (AgeData) p>
Birth: String// p>
Dead: String// p>
end p>
Worker = record// оголошення наступної структури
(Worker) p>
Name:
String// p>
Age:
AgeData// в ній знаходиться вкладена структура типу AgeData p>
Address: String// p>
Remark: String// p>
end p>
var p>
A:
Worker// оголошення змінної із структурою типу Worker p>
begin
p>
A. Name
= "Петя Іванов"// доступ до потрібного поля через символ точки p>
A.Age.Birth
= "01 января 2000"// доступ до потрібного поля через символ точки p>
print (A. Name)
//Доступ до потрібного поля через символ точки p>
end p>
Вигоди
структурного програмування здавалися вражаючими, поки програмісти не
натрапили на наступний непереборний бар'єр. Багато структури оброблялися
одними і тими ж процедурами, але самі процедури залишалися розрізненими. Те
є в нову програму набиралися (по частинах) вже налагоджені процедури з
минулих програм. При великій кількості процедур їх перенесення в нову програму
не здавався простою справою, тому що потрібно було перенести все, що могло
знадобитися для використовуваної структури. Спочатку проблема вирішувалася перенесенням
часто використовуваних процедур в окремі модулі (файли), через що навіть
з'явився термін "модульне програмування". Проте не все виявилося
так просто. З'ясувалося, що певні поля в структурах повинні б мати пряму
залежність від конкретних процедур. Причому залежність була така, що не поле
змінювалося процедурою, а при зміні поля повинна була бути викликана процедура.
p>
З
розвитком графічних інтерфейсів ситуація прояснилася за рахунок того, що
елементи оформлення добре асоціювалися з окремими об'єктами. Саме
спостерігаючи за кнопочками, меню, списками і тому подібним програмісти відзначили,
що на певну дію "об'єкт" повинен відповідати яких-небудь
подією, а сама дія найчастіше зводиться до зміни деякого властивості
"об'єкту". Далі було зазначено, наскільки незначна різниця між
певними структурами і процедурами, як наслідок, розумно було віднести їх
до одних і тих же класах дій. Таким чином, в програмуванні з'явилося
поняття класів. Це було вже не просто кодування процедур і структур в одному
модулі, а планомірний зв'язування процедур зі структурами. Родзинка була в тому,
що начебто звичайна структура включала всередину себе відповідні їй процедури.
Фактично, змінної структурного типу можна було крім зміни якогось
її поля ще й дати команду щось виконати. У результаті структура
перетворювалася на об'єкт, а нове програмування стало називатися
об'єктно-орієнтованим програмуванням (ООП). p>
Тепер
Повідомляти змінні такого ось нового структурного типу стала називатися
об'єктом, а вихідний код "структури" став називатися класом.
Відповідно в ООП поняття "мінлива такого-то структурного типу"
звучить як "об'єкт такого-то класу". До речі, в ООП залишилися і просто
структури, тому що ніхто не збирався відмовлятися від додаткових
можливостей структурного програмування. Надалі класи допрацювали
зв'язком між окремими полями класу (колишньої структури) та його процедур, а
пов'язані поля стали іменувати властивостями. У результаті об'єкт став у стані не
тільки виконувати певні "команди", але й робити
запрограмовані дії при зміні його властивостей (полів). У кінцевому
рахунку, народилися поняття властивостей, методів і подій об'єкта (класу). Під властивістю
розумілася внутрішня мінлива об'єкта, при зміні якої викликалася та
чи інша внутрішня процедура. Дуже позитивно, що ще одну процедуру можна
було призначити властивості у разі спроби читання з нього. Під методом розумілася
певна внутрішня процедура, яку можна було викликати безпосередньо.
Події - в принципі, ті ж методи, тільки що викликаються автоматично при
певних діях з об'єктом. p>
Worker
= Class// оголошення класу (Worker) p>
Name:
String// поле (змінна) всередині класу p>
Birth:
String// поле (змінна) всередині класу p>
Age:
String// поле (змінна) всередині класу p>
//
p>
procedure
Create// процедура (метод) всередині класу p>
procedure
ComputeAge// процедура (метод) всередині класу p>
procedure
Destroy// процедура (метод) всередині класу p>
end p>
var p>
A: Worker// оголошення об'єкту класу Worker p>
begin p>
A. Create
//Виконати Create - це метод об'єкта p>
A. Name
= "Петя Іванов" p>
A. Birth
= "01 января 2000" p>
A. ComputeAge
//Викликається ще один метод об'єкта p>
print (A. Name) p>
end p>
Не дивно,
що класи можна впроваджувати всередину інших класів, можна наслідувати класи (то
є породжувати нові), можна розділяти властивості, змінні і методи класу по
ступенями доступу до них (особисті, захищені, загальнодоступні). Все це породило
справжній вибух в технологіях програмування. Змінні-об'єкти раптом ожили
- Самі реагують на зовнішні події, самі роблять все, що їм вказано.
Програміст, що викликає метод об'єкта або міняє якесь його властивість, може
зовсім не замислюватися, з якими внутрішніми діями це пов'язано. Дав
команду - отримав результат, і знати не треба, що там до чого і як воно
працює. p>
Методи як класи методів h2>
В
Нині програмування зупинилося на ООП, але все явнее відчувається
наступний бар'єр. З історії програмування можна було помітити, як
змінні перетворилися на структури, а ті в свою чергу в об'єкти. Довгий
час об'єкти задовольняли програмістів, поки справа не дійшла до розумних (з
точки зору розуму взагалі) дій. Начебто в об'єктах більше нічого не
придумаєш, і все-таки щось має змінитися. Зараз важко уявити, який
вид приймуть "розумні" об'єкти. Велику проблему становить
самостійна перебудова роботи об'єкта. Тут звичайними властивостями і
методами проблему не вирішити. Справа в тому, що розумний організм уміє
адаптуватися до навколишніх умов, тобто змінювати алгоритми свого
функціонування. Ще складніше, що методи "розумного" об'єкта взагалі
можуть не задаватися явно в момент створення об'єкту, вони можуть бути "сконструйовані"
об'єктом потім в результаті його досвіду. Природно, повинні бути якісь
базові методи, з яких надалі збирається задовольняє
конструкція-метод. p>
Велике
значення має співвідношення методу з самостійним класом. Тобто клас
методів, а не клас об'єктів. Тут трохи інше поняття, і поки занадто
примарно видається, як повинен виглядати клас методів. В якості
приклад можна навести клас методів пошуку розумного організму. Коли,
наприклад, людині кажуть: "Знайди щось там-то", фактично,
називають клас методів, що просять залучити для виконання необхідного
дії, але не вказують, як конкретно виконувати метод. Навіть можна сказати,
що під методом "Знайди" мають на увазі набір схожих алгоритмів, а розумний
організм уже сам вирішить, який же з алгоритмів вибрати в даному випадку. Такий
собі метод-масив, де під одним і тим же ім'ям ховається одразу кілька
алгоритмів. Словосполучення "метод-масив" умовно і всього лише служить
для образного представлення багатомірності одного методу. Також клас методів
може включати в себе інші класи методів. p>
І
знову повернемося до нашого прикладу з розумним організмом. Рухати ногою - це базовий
метод людини, даний йому від природи. Рухати ногою вправо, вліво, вперед,
тому - це придбані методи, так як людина в міру розвитку дізнається, де
які напрямки. До того ж рухати можна по-різному - з піднятою стопою,
нахиленою і так далі. Йти - це теж придбаний метод, але він містить у
себе ціле сімейство методів по руху ніг. p>
Взагалі
"клас методів" - не рідня поняттю "клас об'єктів",
оскільки тут вступають в силу інші правила, хоча в загальних рисах схожість
є. У звичайних об'єктах методи теж можуть бути схожими на багатовимірні, адже
програміст може викликати метод предка (клас, від якого був породжений даний
клас), тільки там програміст примусово вказує, чий саме метод повинен
бути виконаний, тут же "розумний" об'єкт вибирає необхідний метод
сам. Додайте сюди і те, що методи можуть конструювати по ходу роботи
об'єкта. Методу можна, наприклад, як би сказати: "Йти туди-то - це
робиться так-то й так "або" Йти туди-то - це ідентичне такому-то
дії за винятком таких-то моментів ". У свою чергу метод
самостійно розширює свою багатовимірність. Саме ж поняття конструюється
методу вказує на характерний спосіб функціонування. Код об'єкту в ООП
компілюється, і потім алгоритм його методів не може змінюватися. А раз
"розумний" об'єкт може адаптувати свої методи, значить, повинен бути
якийсь формат опису алгоритмів неіснуючих (конструюються в ході роботи)
методів. p>
Спробую
пояснити взаємодія класів методів на наочному прикладі. Припустимо, у нас
є певний об'єкт "А". Нехай об'єкт знаходиться в двовимірної
площині, поділеної на клітини. Одна з клітин позначена червоним кольором.
Об'єкт бачить клітини (вздовж лінії погляду) тільки перед собою. Об'єкт може
повертатися на 90, 180 і 270 градусів праворуч або ліворуч. Об'єкт може крокувати
на одну клітину вперед. Завдання об'єкту "А": знайти червону клітку,
щоб вона опинилася в будь-якій клітці прямо перед ним. p>
p>
Ясна
справа, в об'єкта повинні бути хоч якісь базові методи. У даному випадку це
буде "Рухатися вперед", "Повернутися", "Бачу чи
задану клітку "і" Чи досягли краю площині ". І ось, що
тепер відбувається. p>
Підключити
до об'єкта метод "Рухатися вперед" p>
Підключити
до об'єкта метод "Повернутися" p>
Підключити
до об'єкта метод "Бачу чи задану клітку" p>
Підключити
до об'єкта метод "Чи досягли краю площині" p>
Якщо
перераховані методи начебто (пізніше поясню, чому "начебто б")
відносяться до базових, то тепер потрібен конструюються метод "Знайти
клітку ". Фактично, ми повинні навчити об'єкт, як йому шукати клітку. Для
цього уявімо, що у нас вже розроблений якийсь формат опису алгоритмів
конструюються методів. Дивимося, що відбувається далі. P>
1.
Створити метод "Знайти клітку" і підключити його до об'єкта p>
2.
Вкласти в метод "Знайти клітку" методи "Рухатися вперед", p>
"Повернутися",
"Бачу чи задану клітку" і p>
"Досягли
Чи краю площині " p>
3.
Методу "Знайти клітку" привласнити, наприклад, такий алгоритм: p>
Цикл,
поки за методом "Чи досягли краю площини" не досягли її p>
викликати
метод "Рухатися вперед" p>
Кінець
циклу p>
...
p>
...
p>
викликати
метод "Повернутися на 90 градусів праворуч" p>
...
p>
...
p>
Цикл,
поки за методом "Чи досягли краю площини" не досягли її p>
Якщо
за методом "Бачу чи задану клітку" не бачимо її, тоді p>
викликати
метод "Повернутися на 90 градусів праворуч" p>
викликати
метод "Рухатися вперед" p>
викликати
метод "Повернутися на 90 градусів вліво" p>
Інакше
p>
Клітка
знайдена p>
Кінець
якщо p>
Кінець
циклу p>
...
p>
...
p>
викликати
метод "Повернутися на 180 градусів" p>
...
p>
...
p>
Цикл,
поки за методом "Чи досягли краю площини" не досягли її p>
Якщо
за методом "Бачу чи задану клітку" не бачимо її, тоді p>
викликати
метод "Повернутися на 90 градусів праворуч" p>
викликати
метод "Рухатися вперед" p>
викликати
метод "Повернутися на 90 градусів вліво" p>
Інакше
p>
Клітка
знайдена p>
Кінець
якщо p>
Кінець
циклу p>
...
p>
...
p>
і
так далі p>
Тепер
ми можемо звертатися до методу "Знайти клітку", вже належить
об'єкту "А", тобто виклик типу "А. Знайти клітку (припустимо, на деякій
площині Z) ". А що ж буде, якщо об'єкт" А "якимось чином
потрапляє з площини на іншу фігуру, наприклад, куб? Очевидно, метод
"Чи досягли краю площині" буде непридатний для поверхні куба.
Тепер нам потрібно мати або базовий метод "Чи досягли краю поверхні
куба ", або створити такий метод, як ми створили метод" Знайти
клітку ". А як тільки ми створили (чи маємо його в якості базового)
потрібний метод, ми повинні розширити N-мірність методу "Знайти клітку",
сховавши в цьому методі ще один алгоритм пошуку, але вже для куба. p>
Розширити
метод "Знайти клітку" (тобто додати метод ще одна p>
алгоритм
пошуку), а в якості алгоритму взяти "площинний" p>
алгоритм
(попередній алгоритм), тільки в ньому використовувати p>
метод
"Чи досягли краю поверхні куба", а не "Чи досягли p>
краю
площині " p>
Тепер
вже об'єкт "А" здатний шукати клітку і на площині і на поверхні
куба (наприклад, "А. Знайти клітину (на деякій кубі Z)"), використовуючи
всього лише один метод "Знайти клітку". Зрозуміло, у цьому методі
ховається два алгоритми, але з об'єкта "А" видно тільки одна
єдиний метод, скільки б у ньому ні ховалося алгоритмів. Цей приклад,
звичайно, піднімає питання про те, як метод повинен визначати, який алгоритм
використовувати. Чи то це будуть вхідні параметри для методу, чи то йому буде
передаватися об'єкт, на якому буде виконуватися метод. Поки це питання
відкрито, тому що немає ще ні однієї специфікації, ні одного формату опису
алгоритмів конструюються методів. Я ж перейду до пояснення мого "на зразок
б ", спожитого раніше відносно базових методів. p>
Як
і в щойно описаному випадку з наявністю базового або вперше створюваного
методу для куба, так і у випадку базових методів об'єкту "А" (мето?? и
"Рухатися вперед", "Повернутися" і так далі) прийнятний
варіант, коли ці методи не були базовими, а створювалися в процесі
функціонування об'єкта "А". До того ж навіть базові методи можуть
розширювати свою N-мірність, адже вони - теж класи методів. Якщо, наприклад,
об'єкт "А" з якихось причин втратив ноги, і його пересадили в
інвалідне крісло, то метод "Знайти клітку" продовжує справно
працювати, тому що базові методи "Рухатися вперед" і
"Повернутися" все одно виконують своє завдання. А це відбувається за
рахунок того, що зазначені методи розширюють свою N-мірність додатковими
алгоритмами (адже хтось все одно змушений буде навчити методи новим
алгоритмах), що рухатися вперед на кріслі - це так-то й так, повертатися
- Це так-то й так. Власне, на інші методи об'єкту "А" ніяк
не впливає його "фізична потворність". p>
Якщо
раптом об'єкт дійшов до води, то метод "Знайти клітку" знову працює,
адже метод "Рухатися вперед" розширюється новим алгоритмом, що плисти
по воді - це так-то й так, задіяні такі-то і такі методи (наприклад,
"Веслувати руками"). Природно, нові методи типу "Веслувати руками"
додаються в об'єкт і обов'язково вкладаються всередину методу "Рухатися
вперед ". Якщо у об'єкта не виявиться руки (припустимо, буде протез), то
N-мірність методу "Веслувати руками" розшириться новим алгоритмом
"гребка" протезом, інші ж методи будуть продовжувати працювати так,
як треба. p>
Якщо
перед об'єктом виявиться стіна, то розшириться метод "Рухатися
вперед ", тому що тепер рухатися - це" перелізти через
стіну ", а перелізти через стіну - це зробити так-то й так. В принципі,
це стосується будь-якого методу, так як я приводив приклади з методами руху
об'єкта, оскільки вони наочніше. Так, наприклад, якщо ми шукаємо червону клітку
далеко від себе (або зовсім на чужій поверхні, або зовсім не червону клітку),
то метод "Бачу чи задану клітку" розшириться новими алгоритмами, що
бачити далеко від себе - це, наприклад, взяти бінокль, навести різкість,
посмотреть в нього і так далі. p>
Думаю,
вам став зрозумілий сенс взаємодії методів. Об'єкти
об'єктно-орієнтованого програмування в основному являють собою
вдосконалені змінні, де серйозні зміни торкнулися по більшій
мірою саме структуру змінних, лише найпростішим чином "втягнув"
в об'єкти так звані методи, які раніше були звичайними функціями і процедурами.
Тепер настав час серйозних змін в методах об'єктів. Як мені здається,
саме по цьому шляху піде розум-орієнтоване програмування. p>
Список літератури h2>
Для
підготовки даної роботи були використані матеріали з сайту http://www.sciteclibrary.ru
p>