Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сильный искусственный интеллект и объектно-ориентированное программирование синтез парадигм

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
а именно – незыблемая значимость точных последовательных дей­ствий и конкретных, идеально подобранных пропорций. В по­следнем определении алгоритма частично раскрывается суть того, что в функциональном программировании (да и в целом в программировании) называется «чистой функцией», т. е. функ­цией, не изменяющей значения своих аргументов и всегда воз­вращающей один и тот же результат при одних и тех же входных данных. Это яркий пример функционирования алгоритма. И имен­но этот же «шаблонный» пример практически недостижим при применении любого классического паттерна, так как паттерн в программировании вовсе не подразумевает высокого уровня конкретики и точности своих составляющих. Паттерн – это скорее логически связанный, практически апробированный и задокумен­тированный набор рекомендаций, которые сложились воедино в результате моделирования (примерно так же, как в нейролинг­вистическом программировании) успешных действий в каком-ли­бо контексте и направлены на решение некоторой задачи.
10.2. Демаркация между паттерном, шаблоном
и алгоритмом и контекст реализации паттерна
После общего ознакомления с понятиями шаблона, паттерна и алгоритма приведем пример, иллюстрирующий фундаменталь­ную разницу между ними как феноменами.
Шаблон «Материал». Тактико-технические характеристи­ки: тяжесть – БСТ, класс прочности – В30, морозостойкость – F300, подвижность – П5, водонепроницаемость – W10, плотность – D2500.
Алгоритм «Бетон М400». 1 весовая доля цемента, 1,2 весо­вые доли песка, 2,7 весовые доли щебня. Перемешивать 2 мину­ты при 15 оборотах в минуту.
Паттерн «Смесь». Смешивание песка некоторой степени очистки с цементом некоторого качества, а также щебня опреде­ленного размера способно приводить к появлению новых мате­риалов с определенными тактико-техническими характеристи­ками.
131
Можно заметить, что шаблону совершенно «все равно», ка­ким именно образом он будет достигнут, паттерн только лишь направляет и определяет общие черты, но ничего не конкрети­зирует и, более того, не гарантирует, а алгоритм совершенно «не в курсе», зачем именно он реализуется – он просто приносит один и тот же результат при одних и тех же входных данных и одинаковых действиях.
Примерно таким же образом все происходит и в рамках раз­работки программного обеспечения. В этой связи у нас наличе­ствует некоторая коллатеральная по отношению к основной вет­ви исследования ремарка. А именно: в области построения ПК практически всегда то, что называют шаблоном, на самом деле является паттерном. Просто, как мы и говорили ранее, проблема не только и не столько в переводе с английского на русский тер­минов pattern и template. Аналогичная проблема – путаница – существует также и в среде англоязычных программистов: по­нятие шаблона зачастую заменяется понятием паттерна и, соответ ­ственно, наоборот. А к примеру, русское выражение «действовать по шаблону» как раз и означает реализовывать непосредственно паттерн. Относительно же алгоритма следует заметить, что один и тот же алгоритм вполне может применяться и в рамках реали­зации различных паттернов, и для достижения совершенно раз­ных шаблонов – всего лишь изменяются дозировки и контекст.
Мы, в рамках нашего исследования, акцентируем на терми­нологических, методологических и сущностных различиях меж­ду шаблоном, паттерном и алгоритмом столь высокий уровень внимания по причине важности феномена паттерна непосред­ственно для построения систем сильного ИИ. У нас, на данном этапе развития парадигмы ИИ, нет и не может быть никакого шаблона и даже намека на него – мы и близко не представляем, чем именно должна и чем может быть система сильного ИИ. Еще раз напомним, что мы говорим именно о системе сильного ИИ в том смысле, в котором его понимал Джон Сёрл, т. е. искус­ственный разум, который «будет разумом в том смысле, в кото­ром человеческий разум – это разум» [61, с. 7]. Мы имеем неко­торое представление о том, что есть разум человеческий, но не
132
имеем ни малейшего представления, каким именно может быть разум нечеловеческий. Именно поэтому никакого шаблона быть не может. В этом постулате также убежден, к примеру, известный шведский исследователь, философ Ник Бостром. Он утвержда­ет: «Искусственный интеллект может быть менее человечен, чем пришелец. Нет ничего удивительного, что любого разумно­го пришельца могут побуждать к действию такие вещи, как го­лод, температура, травмы, болезни, угроза жизни или желание завести потомство. ИИ, по сути, ничто из перечисленного инте­ресовать не будет. Вряд ли вы сочтете парадоксальной ситуа­цию, если появится какой-нибудь ИИ, чьим единственным пред­назначением, например, будет: подсчитать песчинки на пля жах острова Боракай; заняться числом π и представить его, наконец, в виде обыкновенной десятичной дроби; определить максималь­ное количество канцелярских скрепок в световом конусе буду­щего» [82, с. 171–172].
С другой же стороны, если довести суть паттерна, как фено­мена, до апофеоза, то именно паттерн представляет собой, по сути, уникальный абстрактный механизм: абстракцию как целое, состоящую из абстракций как частей и несущую в себе общий образ действия. Смысл этого определения лучше всего иллю­стрируется метафорой «сначала был хаос, а потом из него нача­ли черпать идеи». Ранее мы говорили о реализации некоего аб­страктного паттерна, который должен выполнять определенные действия (порождать подпаттерны и связывать их в единый опыт) и приводить к соответствующему результату, который, собствен­но, и должен оказаться сильным искусственным интеллектом. Саму природу непосредственно алгоритма, который будет ис­пользоваться в рамках реализации паттерна, мы на данный мо­мент не затрагиваем. Ведь любой алгоритм, в осмысленном и целесообразном контексте, как и в случае с нашим примером выше, должен функционировать в соответствии с некоторым паттерном и именно им изначально и быть обусловлен, и детер­минирован. И уж тем более при полном отсутствии всякого шаб лона. Т. е. сначала нечто общее – паттерн, затем уже част­ности – алгоритм; сначала общий план действий, а затем уже
133
конкретные шаги; сначала представление о том, что нечто + не­что = что-то, а затем только А**2 + В**2 = С**2; сначала образ действия смешивания, а затем уже конкретные дозировки и ма­нипуляции. И именно по этой причине нам видится глубочай­ший смысл в использовании именно паттерна для построения систем сильного ИИ. Вопрос в том, какого именно и каким/ка­кими он/они должен/должны быть? И именно поэтому мы счи­таем необходимым глубже исследовать феномен паттерна в це­лом, паттерна в программировании, а также разобрать основные паттерны, непосредственно использующиеся в ООП: уже упо­мянутые «Абстрактную фабрику» и «Шаблонный метод», а так­же все остальные.
Вообще же о паттернах можно говорить в весьма обширном спектре абстракций – от наиболее общих и абстрактных до наи­более частных и конкретных. Имеют место паттерны вселенско­го масштаба, а также паттерны в рамках некоторой отдельно взятой предметной области. Дополнительно вводить какую-ли­бо классификацию паттернов по уровню абстракции или по дисциплинарной принадлежности нам целесообразным не ви­дится, так как в рамках исследования нас все же интересуют в первую очередь именно ПП ПК в рамках ООП и именно в кон­тексте их значимости для построения систем сильного ИИ.
О чем-то пока только подобном, а именно о ПП, упомянул Кристофер Александер в 1977 г., причем не только не в контек­сте ООП, но даже и не в рамках программирования вообще. Он говорил о проектировании городской архитектуры, и его харак­теристика, данная паттернам, выглядит так: «…каждый шаблон (паттерн) дает описание той или иной задачи, регулярно возни­кающей в окружающем нас пространстве, вслед за которым пред­ставлена суть решения данной проблемы, сформулированная таким образом, чтобы вы могли многократно использовать это решение, но никогда не копировать его» [118, с. 20]. Стоит заме­тить, что характеристика «отца-основателя», данная им паттер­нам, полностью соответствует нашим «наброскам» на данном этапе исследования. Т. е. просто решение некоторой более­менее схожей задачи в более-менее схожем контексте в некото-
134
ром роде похожим образом. Разительное отличие природы пат­терна от природы шаблона и тем более от сущности алгоритма налицо. Разумеется, что сказанное Александером о паттернах в контексте городского домостроительства вполне успешно и аб­солютно непринужденно теоретически экстраполируется также и в контекст программирования, как, собственно, и вообще на любой иной контекст.
Так, само собой, и случилось не только в теоретическом смыс­ле, но также и в плане практическом. В 1994 г. Эрих Гамма, Ри­чард Хелм, Ральф Джонсон и Джон Влиссидес, следуя прин­ципам выявления, абстрагирования и построения паттернов, написали книгу под названием Design patterns, что в дословном переводе означает «Паттерны дизайна» (была переведена как «Паттерны проектирования»). В книге были теоретически обо­значены, подробно описаны и тщательно проиллюстрированы (на языках программирования C++ и Smalltalk) 23 ПП про­граммного обеспечения. С тех пор книга много раз переиздава­лась, также появилось значительное количество дополнитель­ной литературы на тему ПП. Постепенно ввиду чуть большего, чем стандартное, количества авторов книги к ней «приросло» устойчиво прозвище Gang of four – «Банда четырех», которое в свою очередь эволюционировало до аббревиатуры GoF. И эти 23 ПП также стали называться по имени основателей GoF-pat­terns – «Паттерны банды четырех». И именно данные паттерны считаются классическими и основополагающими в контексте ООП. Теперь же, перед непосредственным проникновением в конкретику ПП в рамках парадигмы ООП, необходимо совер­шить одно небольшое, но необходимое отступление.
Очень даже возможно, что некоторые подобия ПП, применя­емых в рамках ООП, также возможны и в исключительно функ­циональном или декларативном программировании с суще­ствен ной подстройкой под контекст и особенности конкретной методологии программирования. Попробуем привести пример экстраполяции паттерна из области ООП в контекст функцио­нального программирования. Например, мы можем определить функцию, которая должна выводить, в зависимости от передан-
135
ных ей аргументов, некоторый диапазон простых чисел от a до n включительно. Мы также определяем функцию, которая осу­ществляет проверку числа на простоту. Т. е. первая функция по­лучает a и n и должна вернуть некоторое множество простых чисел, вторая определяет, простое ли число, переданное ей в ар­гументе, и возвращает некоторое булево значение – True или False. Собственно говоря, первая функция абсолютно не обяза­тельно сама должна высчитывать весь соответствующий диапа­зон – функционал счетчика передается третьей функции, которая в качестве аргументов получает верхнюю и нижнюю границы необходимого диапазона значений в виде переменных a и n, затем инкрементирует некоторую внутреннюю переменную x, сверяет ее текущее значение на предмет соответствия числа простому числу и вносит значение переменной в выходной спи­сок, возвращая его в первую функцию. Выходит, что вся работа осуществляется верно, все функции «чистые» и, что важно, пер­вая и вторая функции никак между собой не контактируют и во­все не подозревают о существовании друг друга – между ними отсутствует сильное зацепление, они внутренне сильно связаны и все их взаимодействие опосредовано третьей функцией. Опять же, во избежание возможной критики в излишнем усложнении, это все не выглядит совершенно необходимым и, конечно, весь указанный функционал мы вполне можем реализовать в рамках одной-единственной функции за счет использования вложенных циклов, таким образом нарушив первый из принципов SOLID – принцип единственной ответственности, сотворив некую God­function (аллюзия на метафору God-object из ООП), а также ли­шив себя возможности повторного использования каждого из участков логики указанного функционального взаимодействия. Поэтому приведенный пример можно считать реализацией на практике, в контексте функционального программирования, GoF­паттерна «Посредник». Разумеется, пример несколько притянут за уши и с его претензией на соответствие паттерну можно по­спорить, так как он далеко не в полной мере отражает суть и от­ветственности «Посредника» из ООП, но все же в случае экстра­поляции смысла из ООП в функциональное программирование он достаточно корректен.
136
Данный пример показателен в том плане, что позволяет оце­нить всю мощь абстракции, заключенной в феномене паттерна. У «Посредника» много вариантов реализации: столкновение двух астероидов через третий, смех сквозь слезы и так, собственно, далее – от уровня почти полного отсутствия всякой конкретики до почти алгоритмического.
Однако GoF-паттерны – это непосредственно ООП, и сочета­ние абстракции-конкретики на данном уровне именно такое и никакое не иное, а посему взаимоотношения между абстракт­ными компонентами в них описываются именно в терминоло­гии ООП – той терминологии, которая была нами озвучена ра­нее. Итак, все отношения между компонентами в рамках любой конкретной реализации любого условного паттерна описываются в контексте взаимодействия между классами и их экземплярами – объектами (а не как в вышеприведенном примере – функциями), каждому из которых назначена определенная ответственность. Выделяют следующие взаимодействия между классами в ООП: ассоциация, подразделяющаяся на агрегацию и композицию, а также отдельно – обобщение. Еще иногда отдельно выделяют зависимость и агрегирование (в качестве синонима делегирова­ния), но это уже далеко не всегда считается каноничным в плане введения этих типов связей в основные из наличествующих в ООП. Заранее скажем, что существует достаточно много раз­личных вариантов классификации взаимодействия между ПК в рамках ООП (к примеру, иногда ассоциацию выделяют как еще один отдельный тип связи) и мы отобрали наиболее все­охватывающую – в смысловом плане, а не по количеству вари­антов. Кратко охарактеризуем классификацию.
Агрегация – способ взаимодействия между ПК (большим и меньшим, целым и частью, общим и частным и так далее), при котором одна часть может существовать без другой части. Если вспомнить наш недавний пример: это про отношение между пе­ском и бетоном.
Композиция – способ взаимодействия между ПК (также об­щее-частное, часть-целое и так далее), при котором одна часть не может существовать отдельно от другой части. Вновь про
137
наш пример: бетон – материал композитный, и без своих частей он существовать не сможет.
Обобщение – обычно отношение наследования (описанного нами ранее как один из ключевых фундаментальных аспектов ООП), т. е. такое взаимодействие между ПК, при котором один обладает всеми характеристиками другого и, возможно, некото­рыми собственными, дополненными. Причем один компонент является «родительским» по отношению к другому, другой, со­ответственно, «дочерним».
Зависимость – способ взаимодействия между ПК, при кото­ром некоторое изменение в независимом компоненте неизбежно скажется на зависимом, т. е. с зависимым компонентом про­изойдут какие-либо (заранее оговоренные) изменения. Порой за­висимость есть реализация связи по принципу «один ко мно­гим». И тут можно привести очень хорошую метафору: «один с сошкой, а семеро с ложкой». Как только что-то меняется у ком­понента, от которого зависят остальные (от одного до очень многих), то тут же у всех наступают изменения, которые могут носить, в случае множественных связей, весьма непредсказуе­мый характер.
Агрегирование как синоним делегирования – некоторый антоним понятия Dependency injection, т. е. предоставление внешних зависимостей ПК в том смысле, что ПК перепоручает некоторые ответственности иному, отличному от самого себя, но в то же время именно своему собственному, внутреннему ПК.
Знание и понимание способов взаимодействия между ПК важно по той причине, что именно на взаимодействии между различными абстрактными сущностями реализуется концепту­альная суть и теоретический смысл паттерна, а затем уже, на практике, эта суть резюмируется в реальных конкретных про­граммных компонентах и определенных связях между ними.
Здесь стоит еще раз отметить, что мы, в рамках нашего ис­следования, будем выделять максимально абстрактные состав­ляющие данных связей, пусть даже в некоторый ущерб конкрет­ным реализациям. Мы, исключая некоторые отдельно взятые случаи, будем подходить с как можно более общих позиций по той причине, что конкретные реализации всегда есть следствие
138
их абстрактных каркасов. Поэтому мы целенаправленно форми­руем наиболее общий каркас, дабы не ограничивать рамки реа­лизации выявленных аспектов и ключевых деталей в дальней­шем. Более того, как правило, в рамках ООП связь между ПК рассматривается сугубо односторонне. Т. е., к примеру, считает­ся, что абстрактное нечто связано с конкретным нечто по типу агрегации, так как абстрактное нечто может существовать без конкретного нечто. И на этом все. Мы же считаем, что такого рас­смотрения недостаточно для полноценного осмысления спе­цифики функционирования ПК во взаимосвязи друг с другом. Поэтому мы полагаем целесообразным абстрагировать, переве­сти в философско-методологический контекст и затем перефор­мулировать ранее приведенную в примере мысль следующим образом: если абстрактное нечто связано с конкретным нечто по типу агрегации, так как абстрактное нечто способно существо­вать без конкретного нечто, то верно также и то, что конкретное нечто связано с абстрактным нечто по типу композиции, так как конкретное нечто не способно существовать без абстрактного нечто.
Также на данном этапе необходимо еще раз, во избежание неверного толкования результатов и дискурса нашего исследо­вания, обозначить и детализировать смысл весьма важной его особенности, которая заключается в том, что мы, со всем воз­можным осознанием ценности ПП для решения практических задач коммерческой промышленной разработки и пониманием того факта, что именно для наиболее эффективного решения задач сугубо практических в непосредственно прагматическом кон­тексте и оформлялись ПП, все же стараемся преодолеть рамки этого контекста. Мы, по сути, стараемся выявить абстракцию абстракций, т. е. выделить в самой природе паттернов в целом и последовательно в каждом по отдельности некие абстрактные характерные для него аспекты, которые бы помогли прибли­зиться к ответу на два ключевых вопроса: почему сильный ИИ до сих пор не сформирован при помощи паттернов ООП и каким именно образом при помощи паттернов и прочих ключевых осо­бенностей этого же ООП возможно его сформировать. Таким об­разом, мы используем примеры из области промышленной раз-
139
работки лишь в качестве объяснений и иллюстраций, а также порой опускаем некоторые детали, дабы сосредоточиться непо­средственно на цели нашего исследования. Более того, исполь­зуем философско-методологическое интерпретирование харак­терных особенностей и ключевых аспектов ООП. И именно с этих позиций мы намерены подойти к исследованию и описа­нию GoF-паттернов.
После этого небольшого, но необходимого отступления це­лесообразно перейти непосредственно к самим GoF-паттернам. Они по своей сути подразделяются на три группы разного раз­мера и функционала: порождающие (creational), поведенческие (bihevioral) и структурные (structural).
В каждом из данных паттернов, независимо от их групповой принадлежности, выделяют четыре неизменных атрибута: имя, задача, решение, результаты.
Имя. Идентификатор конкретного паттерна, призванный от­ражать его суть, обозначать область решаемой им проблемати­ки, недвусмысленно указывать на специфику решения и делать некоторый прогноз возможных результатов, а также, желатель­но, быть ассоциативно связанным с некоторыми общеупотреби­тельными понятиями.
Задача. Определение области решаемой проблематики: тео­ретическое обозначение ситуаций применения паттерна и кон­текста его применения, обозначение уровня абстракции для реа­лизации паттерна.
Решение. Обозначение до некоторого уровня конкретных ПК, используемых в контексте решения задачи с определенным уровнем конкретики, идентификаторы этих компонентов, опре­деление связей между компонентами и типов этих связей, опре­деление динамики происходящего в контексте работы с задачей.
Результаты. Вероятные ожидаемые и, насколько это воз­можно, прогнозируемые итоги применения решения к проблеме. Как нами уже не раз обозначалось, результаты применения ре­шения, оформленного в виде паттерна, и результаты примене­ния решения, оформленного в виде алгоритма, – совершенно разные результаты. В случае с алгоритмом они всегда гаранти­рованно одинаковы при одинаковых входных данных, включая
140
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]