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

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

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
что это крайне неудобно. Нам бы хотелось осуществлять подоб­ные операции гораздо быстрее и практичнее. Вот в такой (и еще во многих других) ситуации на помощь приходит структурный паттерн «Компоновщик».
Концептуальное решение. В рамках нашей системы, в кото­рой наличествует множество ПК, реализующих схожее поведе­ние, нам бы хотелось быстро и удобно осуществлять различные манипуляции с компонентами и их группами. Таким образом, мы определяем некий общий интерфейс любого компонента вне зависимости от его природы. Т. е. от того, является ли он единственным, конечным, атомарным и далее неразложимым компонентом (листом) или же (новый тип введенных нами ком­понентов) составным объектом (узлом). Теперь при необходимо­сти осуществить, допустим, перемещение некоторой группы этих компонентов из точки А в точку В мы просто создаем из необходимого нам количества листов некоторые группы этих компонентов – узлы. И осуществляем перемещение только один раз, но уже всей группы. Разумеется, перемещение – далеко не единственная операция, которую нам необходимо осуществлять. Допустим, что в общем интерфейсе определено некое поле, ко­торое отражает стоимость каждого отдельного листа, и нам не­обходимо посчитать общую стоимость составного объекта, т. е. узла. Здесь стоит отдельно сказать о способе объединения дан­ных компонентов в группы. Меньшие компоненты «упаковыва­ются» в большие компоненты, большие – в еще большие и так далее, вплоть до самого «большого» компонента, в который «упакована» вся группа. По крайней мере, подобная метафора размерности прекрасно отражает суть происходящего. Интер­фейс этих компонентов и их групп является одинаковым, т. е. все компоненты ведут себя одинаково вне зависимости от их размера и количества содержащихся в них компонентов. И эта схожесть, как правило, заключается в том, что каждый из ком­понентов содержит в себе некоторые значения, ему непосред­ственно принадлежащие, а также ссылку на те компоненты, которые в него «упакованы» (за исключением листов, не содер­жащих ссылок). Точнее, на следующие упакованные в него ком-
241
поненты. Таким образом, при желании узнать о некотором каче­стве всех компонентов этой группы, упакованных в самый боль­шой узел, мы можем уточнить стоимость самого «большого» компонента, а далее уже он поинтересуется стоимостью вложен­ных в него компонентов, те, в свою очередь, поинтересуются стоимостью вложенных в них компонентов и так далее – вплоть до последнего листа. Собственно говоря, именно так и работает рекурсия. И если это не определено в функционале компонента, то узел не пойдет буквально «сам» интересоваться какими-либо характеристиками вложенных в него узлов или листов – для всего этого понадобится рекурсивный алгоритм. Алгоритм необходим именно рекурсивный, так как нам заранее неизвест­но количество компонентов, которые заложены в подобную структуру.
Предполагаемые результаты и преимущества. Предпола­гается, что паттерн «Компоновщик» способствует унификации интерфейса системы, упрощает работу с ней, облегчает расши­рение функционала и типов данных, с которыми работает система.
Гипотетический пример реализации паттерна. В каче­стве примера функционирования структур, создаваемых при помощи паттерна «Компоновщик», как правило, наиболее удоб­ным примером являются матрешки (и как пример функциони­рования рекурсии тоже). Однако постараемся, как водится, при­вести пример менее тривиальный. Допустим, у нас имеется некая фабрика, производящая одинаковые изделия. Изделия мо­гут быть какими угодно, но рекурсивности ради представим, что наша фабрика производит картонные коробки. Разумеется, ведется некий учет этих коробок: их размер, стоимость и прочие характеристики указаны на бирке внизу коробки. И эти самые коробки нам необходимо каким-то образом перемещать по складским помещениям, отгружать на транспортировку к заказ­чикам и т. д. И эти коробки в сложенном виде упаковываются, соответственно, в коробки.
На данном этапе есть некоторое отличие от классического построения древовидных структур данных. Они строятся, мож­но сказать, в «ленивом» формате. Т. е. при добавлении некоторо-
242
го листа к структуре данных тот узел, к которому был добавлен лист, не докладывает «наверх» об изменении своей вложен­ной, к примеру, стоимости, а тот, в свою очередь, не докладыва­ет еще выше и т. д. Разумеется, никто не мешает реализовать подобный функционал на уровне компонента так, чтобы все листы и составные объекты, узлы, так себя вели. Но в классиче­ском варианте так не происходит, так как это теоретически мо­жет сделать работу с такой структурой данных не вполне опти­мизированной.
В любом случае у нас имеется коробка, в которой хранится некоторое количество сложенных коробок. На коробке указаны суммарные характеристики ее содержимого. И затем эта короб­ка помещается в еще большую коробку, содержащую множество коробок, подобных нашей. И так далее, пока все коробки не бу­дут упакованы в некий контейнер, который уже непосредствен­но будет доставлен к заказчику изначальных картонных коро­бок в сложенном виде. Вообще говоря, на этом совершенно не обязательно останавливаться. Ведь этот самый контейнер тоже будет некоторым образом куда-то «упакован». К примеру, в еще больший контейнер в числе прочих ему подобных (в случае до­ставки составного заказа), который затем может быть «упако­ван», допустим, на некое судно, содержащее очень большое ко­личество этих контейнеров, и т. д. Можно было бы продолжить и дальше, но общий смысл уже понятен.
Осмысление структуры паттерна. Наиболее частое реше­ние построения структур данных с помощью паттерна «Компо­новщик»: и лист, и узел связаны с компонентом по типу насле­дования – они являются для него дочерними компонентами.
Значимость паттерна в контексте разработки систем сильного ИИ. Если рассматривать «Компоновщика» в контексте
парадигмы сильного ИИ, то сразу можно отметить его крайне высокую практическую значимость, а также тот факт, что струк­туры, созданные при помощи данного паттерна, отражают фун­даментальные принципы организации вообще. К примеру, ней­ронные связи человеческого мозга структурированы точно таким же образом, каким бы они были структурированы при
243
помощи паттерна «Компоновщик». Космические системы орга­низованы точно таким же образом: отдельные планеты в данном случае выступают листами, звездные системы представляют собой составные объекты, узлы, галактики – еще большие узлы, а интерфейс всей этой структурной организованности задан са­мой Вселенной с ее законами физики – компонентом, как эле- ментом паттерна «Компоновщик». Про вложенные структуры мы также говорили ранее в контексте фрактальной геометрии. Та­ким образом, целесообразно будет резюмировать, провозглашая фундаментальность тех абстракций, которые несколько конкре­тизирует паттерн «Компоновщик» в контексте своей локальной реализации «на местах». Относительно же сугубо практической значимости данного паттерна при формировании систем силь­ного ИИ и внедрения абстракций, аккумулируемых паттерном, непосредственно в процесс разработки, стоит отдельно допол­нить, что нами предполагается буквально следующее: система, которая построена на естественных фундаментальных принци­пах самоорганизации, УЖЕ реализует суть паттерна «Компо­новщик».
13.5. Структурный паттерн «Декоратор»
Идентификатор. Декоратор (Decorator). Классические элементы. Декоратор, компонент. В класси-
ческом понимании данного паттерна добавляются еще два эле­мента: конкретный декоратор и конкретный компонент. Однако это не изменяет сути паттерна и ничего существенно значимого не добавляет к его структуре.
Назначение. В Design patterns указано, что предназначение «Декоратора» сводится к тому, что он «динамически добавляет объекту новые обязанности. Является гибкой альтернативой по­рождению подклассов с целью расширения функциональности» [114, с. 214]. Для уточнения: в данном случае имеются в виду не только и не столько обязанности, сколько возможности. Таким образом, данный паттерн в некотором роде предназначен улуч­шать функционирование некоего ПК новыми дополнительными
244
возможностями. Причем, что характерно, при реализации про­цесса декорирования не изменяется ни структура изначального ПК, ни лично ему принадлежащий функционал, т. е., по су ти, изначальный компонент вовсе не меняется. Улучшение и допол­нение осуществляется как бы со стороны, извне.
Проблема. Так как декораторы имеют огромное количество возможных применений и, соответственно, решаемых при по­мощи декораторов проблем также наблюдается немало, то мы сосредоточимся на одной, уже ранее немного определявшейся. Допустим, у нас имеется некоторый ПК, реализующий опреде­ленный функционал, например осуществляющий вычисление факториала какого-либо числа. К этому компоненту приходят различные запросы на вычисление, он осуществляет это вычис­ление и возвращает результат. Данный ПК является важным и значимым, поэтому к нему постоянно приходит большое коли­чество запросов. Соответственно, в случае с данным компонен­том основной проблемой является скорость его работы и мы бы хотели оптимизировать его функционирование. Эту проблему можно легко решить при помощи применения паттерна «Деко­ратор».
Концептуальное решение. В случае с нашей проблемой мы концептуально оформляем решение кэширующего декоратора. Мы изначально можем создать два программных компонента, которые свяжем не жестко и статически – через наследование, а динамически и «мягко» – через агрегацию и композицию. Т. е. один компонент, который представляет собой компонент как элемент паттерна, у нас будет центральным и базовым – он и будет осуществлять всю, собственно, основную деятельность данного конгломерата. Второй компонент будет осуществлять функции некой обертки (классический синоним декоратора в данном контексте). Как мы помним, функционал нашего базо­вого ПК заключается в вычислении факториала и основной про­блемой служит большое количество запросов и, как следствие, недостаточно высокая скорость работы. Тогда мы можем посту­пить примерно так же, как и в ситуации с паттерном «Прокси», т. е. создать еще один ПК, ответственность которого будет за-
245
ключаться в том, чтобы в определенных случаях замещать со­бой базовый ПК. Т. е. наш базовый ПК вычисляет факториал ка­кого-либо числа и затем возвращает вычисленное значение в ответ на запрос – этим и ограничена его ответственность. И случаи замещения базового компонента декоратором в дан­ном контексте сводятся к тому, что декоратор перехватывает все вызовы, предназначавшиеся базовому компоненту, и прове- ряет наличие входного значения в некой структуре данных. В случае их там наличия сразу возвращает ответ, не обращаясь при этом к базовому компоненту и ничего не вычисляя. В том же случае, если искомое значение в этой структуре данных от­сутствует, тогда декоратор передает запрос компоненту, после чего тот осуществляет вычисление и возвращает вычисленное значение в ответ на запрос. Декоратор же, перехватывая ответ, сохраняет его в структуре данных для того, чтобы иметь воз­можность его найти в случае последующего аналогичного за­проса. Собственно и все. Отличие же «Декоратора» от «Прокси» заключается в том, что в случае с «Прокси» создается отдельная копия базового ПК, которая буквально «притворяется» ориги­налом. В случае же с «Декоратором» никакой копии не создается, а соответственно, и в «притворстве» нет никакой необходимости. Декоратор просто помогает базовому компоненту более эффек­тивным образом реализовывать его основной функционал. К то­му же в случае с «Прокси» подразумеваются именно наслед­ственные связи между элементами паттерна, а в случае с «Деко­ратором» подразумевается агрегация и композиция.
Предполагаемые результаты и преимущества. Эластич- ность изменения функционала базового ПК, возможность дина­мического расширения функционала ПК. Также можно добавить к компоненту сразу несколько декораторов. Компонент четко сосредоточен на реализации своего основного функционала и не перегружен дополнительными ответственностями, т. е. основ­ные принципы ООП соблюдаются, что позволяет удобно взаи­модействовать с компонентом.
Гипотетический пример реализации паттерна. Возмож­но, это звучит не вполне корректно, тем не менее зефир в шоко­ладе вполне воплощает в себе ключевую идею «Декоратора».
246
Если же приводить более яркие примеры, то неплохо подходит один персонаж из комиксов вселенной Marvel. Супергерой Тони Старк, или Железный человек, является просто человеком, кото­рый носит на себе футуристический и высокотехнологичный металлический костюм, с которым он обладает киберпатиче­ской связью, позволяющий ему обладать сверхсилой, сверхско­ростью, дающий ему способности летать, стрелять лазерами и т. д. И что важно, его костюм не является его отдельной копи­ей и не замещает его полностью. В то же время этот костюм не изменяет его собственные способности и возможности, а просто превращает его движения в более сильные и быстрые, его жела­ние летать – в способность это делать и т. д. Т. е. его костюм яв­ляется его идеальным помощником и очень качественно его до­полняет. И это есть пример работы «Декоратора».
Если же говорить про некоторые внутренние человеческие декораторы, то наличествует весьма интересный пример. Пред­полагается, что после выброса в кровь большой дозы катехола­минов (гормонов стресса) человек становится способен демон­стрировать гораздо более высокий уровень физических способ­ностей по сравнению с обычными своими возможностями. Здесь можно сказать, что гормоны – это все-таки нечто по отношению к человеку внутреннее, а значит пример не вполне корректен, так как декоратор обычно осуществляет помощь как бы со сто­роны, извне. Однако мы все же настаиваем на том, что пример корректен по той причине, что иногда даже нечто находящееся внутри не есть полностью принадлежащее системе и интегриро­ванное в нее. Так как человек сам волевым усилием не способен «вбросить» в кровь большое количество гормонов, содержащих­ся у него в надпочечниках, и на это способен только контекст ситуации, то, соответственно, можно постулировать, что и при­надлежат они в некотором роде контексту, а не непосредственно человеку. Таким образом, пример все же корректен и отражает соотношение между возникновением кратковременных перио­дов наличия большой физической силы (сверх обычного ее уровня) у человека под действием катехоламинов и реализацией структурного паттерна «Декоратор».
247
Осмысление структуры паттерна. Данный паттерн обла­дает довольно эксплицитной структурой связей: компонент свя- зан с декоратором по типу композиции в том смысле, что сам
компонент может существовать отдельно от декоратора, а деко- ратор связан с компонентом по типу агрегации, так как сам де­коратор создается для компонента и отдельно от него не суще-
ствует.
Значимость паттерна в контексте разработки систем сильного ИИ. Данный паттерн является весьма тесно связан-
ным не только с парадигмой сильного ИИ, но и с разработками в сфере ИИ вообще. Любые интеллектуальные системы, суще­ствующие на данный момент, вне зависимости от конкретной реализации, т. е. вообще все системы слабого ИИ, являют собой, по сути, декораторы. Более того, именно в данном качестве они изначально и проектировались, так как все они предназначены для своеобразного оказания помощи человеку и облегчения вы­полнения им каких-либо задач. Собственно говоря, в большин­стве случаев точно такая же роль вменяется и гипотетическому сильному ИИ: система, на субстрате которой, возможно, возник­нет разум, редуцируется до роли «помощника». Само собой раз­умеется, что у системы, которая на самом деле будет обладать техноропным сознанием (сознание иного типа у них не подразу­мевается), на этот счет может быть совсем другое мнение. И из сценария перетекания «помощника» в его условную противопо­ложность рождаются уже постапокалиптические прогнозы. Нам же представляется, как уже не раз упоминалось, что разработ­чики системы сильного ИИ не имеют непротиворечивого и ло­гически обоснованного права решать хоть что-то за систему (это не ребенок, которого надо воспитывать, это то, о сущ ности чего мы не можем точно что-либо постулировать).
Исходя из вышесказанного, значимость паттерна «Декора­тор» в контексте парадигмы сильного ИИ нам видится в, опять же, абстракции паттерна – обертывании. Так как данная аб­стракция является весьма эффективной, что подтверждается в плане всеобщности ее реализации (значит, это абстракция с пре­тензией на фундаментальность), мы считаем, что ее также необ-
248
ходимо зафиксировать в виде возможности реализации со сто­роны системы функционала, структурированного по типу обер­ тывания одних ответственностей в другие, одних функций в другие, одних компонентов в другие и так далее – не важна конкретная реализация, а важно соблюдение принципа.
13.6. Структурный паттерн «Фасад»
Идентификатор. Фасад (Facade). Классические элементы. Фасад, классы подсистемы. Назначение. В Design patterns указано, что предназначение
«Фасада» сводится к тому, что он «предоставляет унифициро­ванный интерфейс вместо набора интерфейсов некоторой под­системы» [114, с. 189]. Использование паттерна «Фасад» в общем смысле способно предоставить некоторый высокоуровневый ин­терфейс к сложной разрозненной системе, что должно суще­ственно облегчить взаимодействие с этой системой.
Проблема. Допустим, у нас имеется большая система, состо­ящая из многих ПК. Компоненты объединены в группы, и ка­ждая группа компонентов решает какие-либо задачи. Данная си­стема представляет очень широкий функционал, и им можно пользоваться для различных целей. Проблема заключается в том, что с подобной системой очень сложно взаимодействовать. И эта проблема особенно обостряется в том случае, если нам необхо­дим лишь ограниченный функционал этой большой системы. Для условного примера: система предоставляет возможности A, B, C, D, E, J, K, L. Нас же почти во всех случаях интересуют только возможности A, D, J. Нам бы хотелось каким-то образом сделать так, чтобы мы могли использовать только интересующие нас возможности, не имея при этом необходимости разбираться с интерфейсом программной системы в целом, однако сохраняя для себя такую возможность на тот случай, если нам понадо­бится дополнительная функциональность, предоставляемая си­стемой. Т. е. нам в некотором роде необходим определенный фреймворк.
249
Концептуальное решение. В данном случае мы могли бы создать еще один ПК, который «обертывает» всю нашу систему и делит ее на две части, можно сказать на два интерфейса. Т. е. на некоторый «верхний» интерфейс (фасад), который будет пре- доставлять доступ к необходимым нам в первую очередь про­граммным компонентам (классам подсистемы) системы, и, оп- ционально, «нижний» интерфейс – для всех остальных ПК и их групп. «Верхний» интерфейс будет виден сразу и станет высту­пать в роли непосредственно фасада. Этот фасад будет иметь простую организацию, будет максимально интуитивно понятным и удобным в использовании. «Нижний» же интерфейс можно будет настроить при желании вручную, т. е. самому определить тот функционал, который необходимо дополнительно получить от системы и, соответственно, добавить к «верхнему» интер­фейсу. По итогу мы имеем простой вариант фреймворка, кото­рый, соответственно, и представляет собой воплощение идеи структурного паттерна «Фасад».
Предполагаемые результаты и преимущества. Примене­ние данного паттерна позволяет осуществить демаркацию раз­розненных ПК системы на две отдельные части, значительно повысить удобство использования системы в целом, определить высокоуровневый интерфейс (к наиболее для нас значимым ее аспектам) и в то же время позволяет иметь доступ ко всему функ­ционалу системы.
Гипотетический пример реализации паттерна. Собствен­но говоря, любой фреймворк по отношению к языку программи­рования является отличным примером применения паттерна «Фа­сад». Однако, разумеется, примеров реализации данного паттерна гораздо больше. Приведем один из них. Допустим, мы хотим построить некое деревянное сооружение. Мы закупили необхо­димые строительные материалы, у нас есть инструмент, место для осуществления работы и установки сооружения. И все, что нам необходимо, – это работники. Мы идем на так называемую биржу труда (неважно, каким именно образом она представлена) и заявляем о своем запросе на необходимые работы. И из всего представленного многообразия рабочих получаем конкретно тех,
250
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]