Страницы

вторник, 27 июля 2010 г.

Непрограммные примеры шаблонов проектирования программного обеспечения

Перевод статьи Michael Duell, “Non-Software Examples of Software Design Patterns”,

Оригинал.
Перевод взят отсюда.

Аннотация

Шаблоны проектирования программного обеспечения уходят корнями в архитектурные шаблоны Кристофера Александера, и в вопросы перехода к объектам. Согласно Александеру, шаблоны повторяют самих себя, поскольку они являются обобщенным решением для задаваемой системы сил. Вопросы перехода к объектам рассматривается в реальном мире для того, чтобы проникнуть в суть взаимоотношений при моделировании программного обеспечения. С такими двойственными корнями, вполне логичным будет найти повторяемость шаблонов проектирования программного обеспечения в объектах реального мира. В этой статье представлен реальный мир, не программные экземпляры каждого шаблона проектирования из книги "Приемы объектно-ориентированного проектирования. Паттерны проектирования" [13]. В статье также приводятся выводы о не программных примерах как эффективной основе языка шаблонов для взаимообщения и обучения проектированию шаблонов.

 

1. Введение

В индустрии программного обеспечения существует растущее сообщество сторонников применения шаблонов. Корни перехода к шаблонам можно найти в работах архитектора Кристофера Александера, который описывал шаблоны как обобщенное решение для задаваемой системы сил в мире [1]. Шаблоны Александера можно обнаружить в повседневных структурах. Каждый из шаблонов в "Языке шаблонов" [2], включает в себя картину архетипического примера шаблона.

Поскольку объекты были преобладающим взглядом на мир в то время, когда мир программного обеспечения знакомился с шаблонами, они тоже имеют корни в переходе к объектам [9]. К сожалению примеров шаблонов моделирования программного обеспечения было не так много как у Александера, а они представляли собой более элегантные модели, в отличие от моделей, что люди генерировали в самом начале [13]. Доступ к элегантным моделям часто ограничивался в связи с проприетарным характером большей части программного обеспечения, разработанного сегодня.

Согласно Александеру, реальный мир шаблонов всегда повторяет самого себя, поскольку в соответствии с заданным набором обстоятельств, всегда существует определенные поля взаимосвязей, которые являются наиболее хорошо приспособленными к силам, которые уже существуют [1]. В программном обеспечении, задачи реального мира либо моделируются целиком, либо объекты реального мира сводят к аппаратному программному обеспечению, а программы выводят результаты реального мира [5]. Поскольку шаблоны моделирования программного обеспечения имеют корни как в шаблонах Александера, так и в вопросах перехода к объектам, представляется вполне логичным, что шаблоны моделирования программного обеспечения могут быть найдены и в объектах реального мира. Это не означает, что шаблонам моделирования программного обеспечения необходимы модели объектов реального мира, но взаимосвязи между объектами, которые приспособлены для работы с определенными силами, могут быть обнаружены как в "реальном мире", так и в объектах программного обеспечения. Чтобы проверить эту гипотезу, были найдены примеры из реального мира для каждого из 23 шаблонов "Банды Четырех" [13]. Эти примеры приводятся далее в разделах со 2 по 4.

2. Порождающие шаблоны

Пять порождающих шаблонов были задокументированы группой авторов, называвших себя "Бандой Четырех". Примеры таких порождающих шаблонов могут быть найдены в обрабатывающей промышленности, на предприятиях быстрого питания, в биологии и в политических институтах.

2.1 Пример "Абстрактной фабрики"

Целью "Абстрактной фабрики" является предоставление интерфейса для создания семейств связанных объектов, без указания конкретных классов. Этот шаблон можно соотнести с оборудованием для штамповки из листового металла, используемого при производстве японских автомобилей. Штамповочное оборудование является "Абстрактной фабрикой", которая создает части корпуса автомобиля. Один и тот же механизм используется для штамповки правых дверей, левых дверей, правых передних крыльев, левых передних крыльев, капота и т.п. у различных моделей машин. С помощью роликов для изменения формы штампа, конкретные классы производятся механизмами, которые могут изменяться за три минуты [16].


Рис.1. Пример штамповки "Абстрактной фабрикой".

2.2 Пример "Строителя"

Шаблон "Строитель" отделяет построение сложного объекта от его представления так, что одно и то же построение процесса может создавать различные представления. Этот шаблон применяется ресторанами быстрого питания для комплектования детского меню. Детское питание обычно состоит из главного блюда, гарнира, напитка и игрушки (например, гамбургер, картофель фри, кока-кола и автомобильная игрушка). Заметьте, что в содержание детского меню могут вводиться вариации, но процесс комплектования остается одинаковым. Заказывает ли потребитель гамбургер, чизбургер или курицу — процесс один и тот же. Работник за прилавком указывает команде собрать главное блюдо, гарнир и игрушку. Эти предметы помещаются в пакет. Напиток наливается в чашку и ставится рядом с пакетом. Этот же самый процесс используется и конкурирующими ресторанами.


Рис.2. Диаграмма взаимодействий объектов для "Строителя" на примере комплектования детского меню.

2.3 Пример "Фабричного метода"

"Фабричный метод" задает интерфейс для создания объектов, но оставляет подклассам решать, какие именно классы будут создавать экземпляры. Отливка формовочного пресса демонстрирует такой шаблон. Производители пластмассовых игрушек подвергают обработке пластмассовый формовочный порошок, и заливая пластмассу в пресс, придают ей желаемую форму [15]. Класс игрушки (автомобиль, фигурка и т.п.) определяется прессом.


Рис.3. Объектная диаграмма для "Фабричного метода" на примере отливки формы.

2.4 Пример "Прототипа"

Шаблон "Прототип" задает вид создаваемых объектов, используя прототипичный экземпляр. Прототипы новых продуктов часто собирают еще до полноценного производства, но в таком примере прототип является пассивным, и он не участвует в копировании самого себя. Митотическое деление клетки, которое порождает две одинаковых клетки, является примером прототипа, играющего активную роль в копирования себя самого и, таким образом, демонстрирует шаблон "Прототип". Когда клетка делится, в результате появляются две клетки идентичного генотипа. Другими словами, клетка клонирует саму себя.


Рис.4. Объектная диаграмма для "Прототипа" на примере деления клетки.

2.5 Пример "Одиночки"

Шаблон "Одиночка" гарантирует, что класс имеет лишь один экземпляр, и обеспечивает глобальную точку доступа к этому экземпляру. Шаблон "Одиночка" назван в честь одиночного множества, которое определяется множеством, содержащим один элемент. Офис Президента Соединенных Штатов является "Одиночкой". Конституция Соединенных Штатов определяет механизмы, посредством которых избирается президент, ограничивает срок его пребывания в должности и задает порядок преемственности. В результате, в любой момент времени не может оказаться более одного президента. Независимо от конкретной личности действующего президента, звание Президента Соединенных Штатов является глобальной точкой доступа, которое конкретизирует личность в офисе.

Рис.5. Объектная диаграмма для "Одиночки" на примере Института Президентства.

3. Структурные шаблоны

Семь структурных шаблонов были задокументированы "Бандой Четырех". Примеры таких шаблонов могут быть найдены в ручных инструментах, проводке в зданиях, математике, праздновании традиций, торговых каталогах и в банковском деле.

3.1 Пример "Адаптера"

Шаблон "Адаптер" позволяет в случае несовместимых классов работать им вместе, преобразуя интерфейс одного класса в интерфейс, ожидаемый клиентом. Гнездовой ключ представляет собой такой пример "Адаптера". Гнездо присоединенное к храповому механизму, обеспечивает чтобы размер насадки был точно таким же. Типичные размеры гнезд в Соединенных Штатах — 1/2" или 1/4". Очевидно, что 1/2" насадка ключа не подойдет к 1/4" насадке гнезда, если не пользоваться адаптером. 1/2" — 1/4" адаптер имеет 1/2" гнездовой контакт ("мама") для 1/2" насадки ключа, и 1/4" штыревой контакт ("папа") для 1/4" гнезда.

Рис.6. Объектная диаграмма для "Адаптера" на примере гнездового адаптера.

3.2 Пример "Моста"

Шаблон "Мост" отделяет абстракцию от ее реализации так, чтобы они оба могли изменяться независимо. Домашний переключатель, управляющий освещением, потолочным вентилятором и т.п. является примером "Моста". Назначением переключателя является включение или выключение устройства. Действующий переключатель может быть реализован как замыкатель цепи, как простой двухпозиционный переключатель или как переключатель реостатного типа.


Рис.7. Объектная диаграмма для "Моста" на примере электрического переключателя.

3.3 Пример "Компоновщика"

"Компоновщик" сводит объекты в древовидную структуру, и позволяет клиентам обращаться к отдельным объектам и их группам одинаковым образом. "Компоновщиками" являются арифметические выражения, хотя и такой пример является абстрактным. Арифметическое выражение состоит из операнда, оператора (+-*/), и другого операнда. Операнд может быть числом или другим арифметическим выражением. То есть, 2+3 и (2+3)+(4*6), — оба выражения являются правильными.


Рис.8. Объектная диаграмма "Компоновщика" на примере арифметического выражения.

3.4 Пример "Декоратора"

"Декоратор" динамически подключает к объектам дополнительные функции. Хотя картины могут быть повешены на стену как в рамке, так и без, рамками пользуются часто, и как раз за рамку картину вешают на стену. Перед тем как вешать, картина могут быть украшена багетом или установлены в рамку так, чтобы и картина, и багет, и рамка образовали единую визуальную композицию.


Рис.9. Объектная диаграмма для "Декоратора" на примере обрамленной картины.

3.5 Пример "Фасада"

"Фасад" задает единообразный, высокоуровневый интерфейс для подсистем, что делает его применение проще. Заказчики сталкиваются с "Фасадом", когда заказывают товар по каталогу. Заказчик набирает единый номер и разговаривает с обслуживающим клиентов персоналом. Обслуживающий клиентов сервис действует как "Фасад", обеспечивая интерфейс к подразделению исполнения заказов, подразделению финансовых расчетов и подразделению доставки.


Рис.10. Объектная диаграмма для "Фасада" на примере заказа по телефону.

3.6 Пример "Приспособленца"

"Приспособленец" эффективно использует большое количество объектов совместно. Примером "Приспособленца" является общая коммутируемая телефонная сеть. Имеется несколько устройств, таких как тоновые генераторы звонка, импульсные генераторы и цифровые приемники, которые могут использоваться абонентами совместно. Абонент не знает сколько устройств объединены в пул, когда он поднимает трубку, совершая вызов. Все, что имеет значение для абонента — что тоновый набор работает, сигнал отзыва получен и тогда вызов совершен.


Рис.11. "Приспособленец" на примере тонового генератора звонка.

3.7 Пример "Заместителя"

"Заместитель" вводит заменителя или обладающего полномочиями для обеспечения доступа к объекту. Чек или банковское поручение является заменителем денежных средств на счету. Чек может использоваться вместо наличных денег для совершения покупок и первичного контроля доступа к суммам на текущем счету.


Рис.12. Объектная диаграмма для "Заместителя" на примере банковского поручения.

4. Поведенческие шаблоны

"Бандой Четырех" были задокументированы одиннадцать поведенческих шаблонов. Примеры таких шаблонов можно найти в сортировке монет в банке, в ресторанных заказах, в музыке, на транспорте, в автомастерской, в торговых автоматах и в жилищном строительстве.

4.1 Пример "Цепочки ответственности"

Шаблон "Цепочка обязанностей" избегает прямого запроса отправителя к получателю, давая возможность обработать запрос более чем одному объекту. Механическая сортировка монет в банке использует "Цепочку ответственности". В отличие от отдельной щели для монеты каждого достоинства с накопителем, используется единственная щель. Когда монета падает, она автоматически направляется механизмом в соответствующий накопитель внутри банка.


Рис.13. Объектная диаграмма для "Цепочки ответственности" на примере сортировки монет.

4.2 Пример "Команды"

Шаблон "Команда" позволяет запросам быть инкапсулированными в виде объекта, тем самым позволяя клиентам указывать параметры к различным запросами. Обеденный "счет" является шаблоном "Команды". Официант или официантка принимает заказ, или указания от потребителя, и инкапсулирует этот заказ, записывая его на чеке. Затем заказ на короткое время попадает в очередь на кухню. Заметьте, что "счета" заполняются для разных обедающих и не зависят от меню, а потому они могут обслуживаться командой для приготовления множества различных блюд.


Рис.14. Диаграмма взаимодействия объекта "Команды" на примере обедающего.

4.3 Пример "Интерпретатора"

Шаблон "Интерпретатор" задает грамматическое представление для языка и интерпретатора для интерпретирования грамматики. Музыканты являются примерами "Интерпретатора". Высота звука и его продолжительность может быть представлена в музыкальной нотации на нотном стане. Эта нотация представляет собой музыкальный язык [14]. Музыканты, играя музыку с нот, способны воспроизвести оригинальную высоту и продолжительность каждого записанного в нотации звука.


Рис.15. Объектная диаграмма для "Интерпретатора" на музыкальном примере .

4.4 Пример "Итератора"

"Итератор" предоставляет последовательный доступ к элементам составного объекта, не раскрывая нижележащей структуры этого объекта. У телевизоров первого поколения, для переключения каналов использовался циферблат. При переходе к нужному каналу, телезрителю требовалось двигать переключатель через каждую позицию канала, независимо от того, есть ли вещание по текущему каналу или нет. В современных телевизорах используются кнопки "Next" и "Prev". Когда телезритель нажимает кнопку "Next", будет показан следующий канал. Если вы смотрите телевизор в отеле незнакомого города и ищете интересную передачу или фильм, номер канала вас не интересует. Если содержание вас не устраивает — вы будете пользоваться кнопкой "Next", при этом номер канала не так важен.


Рис.16. Объектная диаграмма для "Итератора" на примере переключателя каналов.

4.5 Пример "Посредника"

"Посредник" задает объект, который управляет взаимодействием множества объектов. Взаимодействующие объекты избавляются от прямых связей друг с другом, эти функции передаются отдельному объекту — "Посреднику". Этот шаблон очень хорошо представляет диспетчерская вышка аэропорта. Пилоты самолетов, покидая или приближаясь к терминалу связываются с вышкой, а напрямую не друг с другом. Разрешения тем, кто может совершить посадку или взлет, выдаются из вышки. Важно отметить, что на вышке не контролируется весь полет в целом. Там отслеживают и управляют поведением самолетов только в пределах терминала.


Рис.17. "Посредник" на примере диспетчерской вышки аэропорта.

4.6 Пример "Хранителя"

"Хранитель" делает снимок и облекает в конкретную форму внутреннее состояние объекта, с тем чтобы восстановить это его состояние позднее. Такой шаблон широко распространен в "сделай сам" механике восстановления автомобильных барабанных тормозов. Барабаны снимаются с обеих сторон, открывая вид как левого, так и правого тормозов. Разбирается только одна сторона, а другая используется в качестве "Хранителя" того, как детали тормозов соединены вместе [8]. Только когда работа с одной стороны полностью завершена, разбирается вторая сторона. Когда разбирается вторая сторона, первая служит в качестве "Хранителя".


Рис.18. Объектная диаграмма "Хранителя" на примере ремонта тормозов.

4.7 Пример "Наблюдателя"

"Наблюдатель" задает отношение "один ко многим" так, чтобы когда один объект меняет свое состояние, другие получают уведомления и автоматически обновляются. Некоторые аукционы представляют собой такой шаблон. Каждый участник торгов имеет карточку с номером, которая используется для указания ставки. Аукционист начинает торги, и "наблюдает" когда карточка будет поднята, подтверждая ставку. Подтверждение ставки изменяет цену предложения, которая передается всем участникам торгов в форме новой ставки.


Рис.19. "Наблюдатель" на примере аукциона.

4.8 Пример "Состояния"

Шаблон "Состояние" позволяет объекту менять свое поведение, когда его внутреннее состояние изменилось . Этот шаблон можно наблюдать в торговом автомате. Торговые автоматы определяют свое состояние основываясь на реестре товаров, количестве полученных денег, возможности вносить изменения и т.д. Когда деньги приняты и выбор сделан, торговый автомат либо выдаст товар и не изменит свое состояние, либо выдаст продукт и изменит свое состояние, либо не выдаст продукт из-за недостаточного количества денег или исчерпания запасов продукта.


Рис.20. Объектная диаграмма для "Состояния" на примере торгового автомата.

4.9 Пример "Стратегии"

"Стратегия" задает набор алгоритмов, которые могут быть использованы как взаимозаменяемые. Вид доставки в аэропорт является примером "Стратегии". Существует несколько вариантов: на собственном автомобиле, вызвать такси, на межаэропортном спецтранспорте, на городском автобусе или лимузине. До некоторых аэропортов также можно добраться и на метро или даже на вертолете. Любой из этих видов доставки путешественников в аэропорт может стать взаимозаменяемым. Пассажир должен выбрать "Стратегию", основываясь на компромиссе между ценой, удобством и временем.


Рис.21. Объектная диаграмма для "Стратегии" на примере доставки в аэропорт.

4.10 Пример "Шаблонного метода"

"Шаблонный метод" задает каркас алгоритма в отдельных операциях, и уступает некоторые шаги субклассам. В жилищном строительстве "Шаблонный метод" используется при разработке новых типовых проектов. Типовой проект состоит из ограниченного количества планов помещений, с различными вариациями для каждого плана. Внутри такого плана, фундаменты, окна, сантехника и проводка будут для каждого дома идентичными. Вариации вводятся на последних стадиях разработки, для производства более широкого спектра моделей.


Рис.22. "Шаблонный метод" на примере базового типового проекта.

4.11 Пример "Посетителя"

Шаблон "Посетитель" представляет собой операцию, исполняемую на элементах объектной структуры, без изменения классов, с которыми он работает. Этот шаблон можно обнаружить в работе службы такси. Когда кто-либо звонит в службу такси, он становится частью списка заказчиков службы. Затем служба направляет машину заказчику (принимает посетителя). Садясь в такси, или становясь его Посетителем, заказчик уже не контролирует свое перемещение, это делает (водитель) такси.


Рис.23. Диаграмма взаимодействия объектов для "Посетителя" на примере вызова такси.

5. Выводы

Не программные примеры каждого шаблона проектирования программного обеспечения, каталогизированные "Бандой Четырех", показаны реально существующими. Можно теперь удивиться практическому смыслу этих примеров. Эти не программные примеры способствуют повышению коммуникативной способности языка шаблонов и полезны как средство обучения шаблонам.

5.1 Повышение коммуникативной способности языка шаблонов

Александер надеялся, что правильные шаблоны приведут к появлению общего языка, который будет поддержан всеми [2]. Внутри сообщества проектирования программного обеспечения, шаблоны рассматриваются как путь разработки набора языков для эффективной коммуникации между коллегами [4, 17]. Шаблоны, как ожидается, предоставят общий словарь для обсуждения структур, больших чем модули, процедуры и объекты [10].

Одним из важнейших элементов языка являются ментальные образы, связанные с символами языка. В языке, задаваемая конфигурация символов имеет смысл только тогда, когда можно легко понять ее содержание, которое включает и его ментальное представление [7]. Важность ментальных образов для языка шаблонов не отрицал и Александер. Он утверждал, что язык не является морфологически полным, пока типы построений, которые язык генерирует, не смогут быть визуализированы конкретным образом [1]. В проектировании программного обеспечения, Дирк Риле (Dirk Riehle) и Хайнц Цуллигхофен (Heinz Züllighoven) признают важность конкретных примеров в ознакомлении нашего восприятия с предметной областью [18].

Если шаблоны проектирования программного обеспечения станут всеобщим языком среди программистов, то станут важными и совместно используемые ими смысловые значения. Если проектные решения станут обсуждать, но не понимать, проектировщики будут вынуждены снимать с себя ответственность за завершение работы [19]. Обыденные примеры облегчают понимание, поскольку в ходе понимания чего-либо, люди должны найти в памяти ближайший предмет, с которым оно соотносится [20]. Проекты в AG Communication Systems, там где широко используются шаблоны проектирования, часто сопровождаются не программными примерами для иллюстрации связей в шаблонах. Примеры помогают прийти к общему пониманию между проектировщиками. Установив общее понимание на раннем этапе процесса проектирования, обсуждение между проектировщиками становится намного более эффективным на протяжении всего жизненного цикла проекта.

5.2 Не программные примеры как средство обучения шаблонам

Студентам требуются примеры, когда им представляют новые концепции. Это стало очевидным во время испытательного курса по изучению шаблонов проведенного в AG Communication Systems, и то же самое отмечалось другими [12]. Когда изучается что-то новое, студент естественно стремится использовать предыдущие знания в попытках понять новые концепции [6]. По этой причине, при первом знакомстве с шаблонами проектирования программного обеспечения нужно приводить больше примеров [12]. Конкретные примеры должны быть хорошо знакомы студентам, а не экспертам [3]. Приводя знакомые примеры мы не увеличиваем объем материала, который нужно будет изучить еще. В то же время, выбор примера вне компетенции студента, оставляет его за рамками вовлечения в приводимый пример и цель нового материала теряется. Поскольку шаблоны, в конечном счете, должны постоянно находиться в собственной голове [11], используйте те примеры, которые понятны и знакомы как можно большому количеству людей, а учебные материалы могут быть построены на уже закрепившихся в памяти примерах.

6. Заключение

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

7. Благодарности

Автор выражает глубокую благодарность Брэндону Голдфиддеру из "Dalmatian Group", Линде Райсинг из "AG Communication Systems", Алистеру Кокберну из "Humans and Technology" и Ральфу Джонсону из Иллинойского Университета в Урбане, за их полезные замечания для этой статьи.

8. Ссылки

1. Alexander, C. "The Timeless Way of Building", Oxford University Press, 1979.

2. Alexander, C., и др. "A Pattern Language", Oxford University Press, 1977.

3. Anthony, D. "Patterns for Classroom Education", в "Pattern Languages of Program Design II", Addison-Wesley, 1996.

4. Berczuk, S. "Finding solutions through pattern languages", Computer, Vol. 27, No. 12. December, 1994.

5. Booch, G. "Object Oriented Design" в "Tutorial on Software Design Techniques", стр. 420-437, IEEE Computer Society, 1984.

6. Carroll, J. "The Nurnberg funnel: Designing minimalist instruction for practical computer skill", MIT Press, 1990.

7. Chierchia, G. and McConnel-Ginnet, S., "Meaning and Grammar: An Introduction to Semantics", MIT Press, 1990.

8. Chilton, "Chilton's Auto Repair Manual", Chilton Book Company, 1985.

9. Coplien, J. "Broadening beyond objects to patterns and to other paradigms", Position statement for the ACM Workshop on Strategic Directions in Computing Research, MIT, June 14-15, 1996.

10. Coplien, J. "Idioms, Patterns, and Other Architectural Literature", IEEE Software, November, 1996.

11. Cunningham W., Johnson, R., "Introduction to Pattern Languages of Program Design", Addison-Wesley, 1995.

12. DeBruler, D. "A Generative Pattern Language for Distributed Processing", в "Pattern Languages of Program Design", Addison-Wesley, 1995.

13. Gamma, E., Helm, R., Johnson, R., Vlissides, J., "Design Patterns - Elements of Reusable Object-Oriented Software", Addison-Wesley, 1995. Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес "Приемы объектно-ориентированного проектирования. Паттерны проектирования", СПб: «Питер», 2007.

14. Leonhardt, C. "Discovering Music Together 7", California State Department of Education, 1967.

15. President and Fellows of Harvard College, "Good Time Toy Company", Publishing Division, Harvard Business School, 1986.

16. Hill, C.W.L. "Toyota: The Evolution of Toyota's Production System" в "Cases in Strategic Management", Houghton Mifflin, 1993.

17. OOPSLA '95 "Patterns: Cult to Culture?", Panel Discussion in the Addendum to the Proceedings, ACM Press, 1996.

18. Richle, D, Züllighoven, H. "A Pattern Language for Tool Construction and Integration Based on the Tools and Materials Metaphor", in Pattern Languages of Program Design, Addison-Wesley, 1995.

19. Ross, D., and Schoman Jr., K. "Structured Analysis for Requirements Definition," IEEE Transactions on Software Engineering, Vol. SE3, No 1., January, 1977.

20. Schank, R. "Tell Me a Story: A New Look at Real and Artificial Memory", Charles Scribner's Sons, 1990.

"Non-Software Examples of Software Design Patterns," Object Magazine, Vol. 7, No. 5, July 1997, pp. 52-57.

Комментариев нет:

Отправить комментарий