Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 185
Текст из файла (страница 185)
808 Глава 24. Проектирование и программирование вать код прямо из спецификаций высокого уровня. Вдругих областях код можно получить, манипулируя фигурами на экране. Например, удобный пользовательский интерфейс можно построить непосредственным манипулированием, и это займет малую толику того времени, которое было бы затрачено на построение этого интерфейса при написании традиционного кода. Аналогично, размещение баз данных и код для доступа к данным в соответствии с этим размещением можно сгенерировать из спецификаций, что гораздо проще, чем выражение этих операццй непосредственно на С++ или любом другом языке программирования общего назначения.
Конечные автоматы, которые будут проще, быстрее и правильнее, чем того способен добиться программист, можно сгенерировать из'спецификаций или непосредственным манипулированием. Подобные приемы хорошо работают в специфических областях, где есть либо крепкий теоретический фундамент (например, математика, конечные автоматы и реляционные базы данных), либо общий каркас, в который можно встраивать маленькие прикладные фрагменты (например, графические пользовательские интерфейсы, моделирование сетей и схемы баз данных). Очевидное удобство такого приема в ограниченных — и, как правило, принципиально ограниченных — областях может подтолкнуть кое-кого к мысли, что замена традиционного программирования такими приемами уже не за горами.
Но это не так. Причина здесь в том, что расширение техники спецификаций за области с крепким теоретическим фундаментом подразумевает, что в языке спецификаций проявится сложность языка программирования общего назначения. А это лишает язык спецификаций его основных преимушеств— ясности и хорошей обоснованности с прикладной точки зрения. Иногда забывают, что каркас, позволяющий ликвидировать традиционное программирование в какой-либо области — это система или библиотека, которая была спроектирована, запрограммирована и протестирована традиционным образом.
Фактически, С++ и описанные в данной книге приемы широко прнгяеняются именно при проектировании и построении подобных систем. Компромисс, обеспечивающий лишь малунэ часть той выразительности, какую имеет язык программирования общего назначения, при применении вне строго ограниченной специальной области, является наихудшим вариантом, Проектировщиков, привязавшихся к точке зрения моделирования высокого уровня, раздражает все возрастающая сложность, и они производят такие спецификации, из которых получается ужасный код.
Программисты, применяюгцие традиционные методы программирования, вынуждены бороться с трудностями, возникающими из-за отсутствия языковой поддержки, и улучшают код только путем чрезвычайных усилий и отказом от моделей высокого уровня. Лично я не вижу признаков, что программирование как род деятельности может быть успешно ликвидировано вне областей, тле имеется основательный теоретический базис, пли где основы программирования обеспечиваются средой разработки.
В обоих случаях применяемые приемы теряют эффективность, когда выходят за первоначальныее рамки н применяются к более универсальным задачам. Притворяться, что это не так — соблазнительно и опасно. И наоборот, может оказаться глупостью не принимать во внимание технику спецификаций высокого уровня п приемы прямой манипу.ляпин в тех областях, где это хорошо обосновано и опробовано. Средства проектирования, библиотеки и среды разработки являются олной из высших форм проектирования и программирования. Конструирование полезной математической модели прикладной области является одной из высших форм анализа.
807 24.2. Проектирование и язык программирования Таким образом, выработка инструментов, языка, среды разработки и т. п. — всего того, что делает результат подобной работы доступным тысячам людей — эта способ для программиста и проектировщика не стать ремесленниками, которые владеют лишь одним инструментом. Очень важно, чтобы система спецификаций или библиотека основных классов могла эффективно взаимодействовать с языком программирования общего назначения. Иначе этот подхол станет очень ограничительным. Это подразумевает, что системы спецификаций и прямого манипулирования, генерируюьцие код на достаточно высоком уровне в принятый язык программирования обьцего назначения, имеют огромное преимущество.
Собственный язык является долговременным преимуществом только для его поставщика. Если произведенный код получается такого низкого уровня, что добавляем ьш общий код приходится писать без выгод абстрагирования, это приводит к потере надежности и экономии, а также к ухудшению сопровождения. По сути дела, генерирующая система должна быть спроектирована так, чтобы сочетать достоинства спецификаций высокого уровня и языка программирования высокого уровня.
Исключить то или другое — значит пожертвовать интересами разработчиков системы ради интересов разработчика средства. Удачные большие системы являются многоуровневыми и модульными, кроме того они развиваются со временем. И потому успех попыток произвести такую систему подразумевает привлечение разнообразных языков, библиотек, инструментов и методов программирования. 24.2.5. Использование исключительно иерархий классов Когда мы обнаруживаем, что что-то новое действительно работает, мы часто «входим в раж» и применяем это новое без разбора.
Другими словами, удачное решение некоторой проблемы часто кажется удачным решением для почти всех проблем. Иерархии классов и операции, полиморфные по отношению к их (одному) объекту, предоставляют удачное решение многих проблем. Однако не любое понятие лучше всего выражается в виде части иерархии, и не любая компонента программы лучше всего представляется в виде иерархии классов. Почему? Иерархия классов выражает взаимоотношения между своими классами, а класс представляет понятие.
Теперь скажите, что общего между улыбкой, драйвером моего привода СО-КОМ, записью «Дои Жуанаь Рихарда Штрауса, строчкой текста, спутником, моей медицинской картой и часами реального времени? Помещение всех их в единую иерархию, когда их единственной общностью является лишь то, что все они — артефакты программирования (они все — «объектыь), имеет мало фундаментального смысла и может привести к путанице (~ 15,4.5). Загоняя все в единую иерархию, вы можете ввести искусственное сходство и затушевать реальное. Иерархию следует применять, только если анализ вскрыл концептуальную общность, или если проектирование и программирование обнаружили полезиукз общность в структурах, используемых для реализации понятий.
В последнем случае нужно очень осторожно различать истинную общность (которую следует отразить в виде подтипизации с использованием открытого наследования) и полезные упрощения реализации (которые следует отразить в виде закрытого наследования; з 24.3.2.1). Такой образ мыслей приводит к программе, которая имеет несколько несвязанных или слабо связанных иерархий классов, каждая из которых представляет множество 808 Глава 24. Проектирование и программирование тесно связанных мелгду собой понятий. Зто также приводит к понятию конкретного класса Я 25.2), который не входит в иерархию, поскольку помещение его в иерархию скомпрометирует его производительность и независимость от остальной системы.
Чтобы быть эффективными, большинство критических операций пад классом, входящим в иерархию, должны быть виртуальными функциями. Кроме того, многие данные класса нужно сделать защигценными, а не скрытыми. Зто делает класс уязвимым к изменениям в производных классах и может серьезно усложнить тестирование. Там, где с точки зрения проектирования имеет смысл более строгая инкапсуляция, нужно использовать невиртуальные функции и закрытые данные Я 24.3.2.1). Если один элемент операции (тот, что обозначает «объект») особый, это может привести к искажениям в проекте. Если с несколькими аргументами мы обращаемся одинаково, операцию лучше представить в виле функции-не-члена.
Зто не означает, что такие функции должны быть глобальными. Фактически, почти все такие «самостоятельные» функции должны быть членами пространства имен Я 24.4). 24.3. Классы Самое фундаментальное понятие объектно-ориентированного проектирования и программирования заключается в том, что программа является моделью некоторых аспектов реальности, Классы в программе представля>от собой фундаментальные понятия прикладной области в, в частности, фундаментальные понятия моделируемой «реальности». Объекты реального мира и артефакты реализации представляются объектами классов Анализ отношений между классами и внутри частей класса — это центральное место в проектировании системы. Следует учитывать: в 24.3.2 Отношения наследования з 24.3.3 Отношения включения 8 24.3.5 Отношения использования в 243,б Запрограммированныс отноп>ения 8 24З.7 Отношения внутри класса Поскольку класс в С++ — это тип, классы и взаимоотношения поддерживаются компилятором и в основном доступны статическому анализу.
Чтобы вписаться в проект, класс не просто должен представлять собой полезное понятие; он также должен обеспечить подходящий интерфейс. Идеальный класс имеет минимальную и строго определенную зависимость от остального мира и интерфейс, предоставляющий минимум информации о классе остальному миру Я 24.4,2). 24.3.1. Что представляют классы? Есть два основных вида классов: 11~ классы, прямо отражаюгцие прикладные понятия; то есть концепции, непосредственно используемые конечными пользователями для описания своих проблем и их ре>пений; [21 классы, являющиеся артефактами реализации; то есть они выражают концепции, использующиеся проектировщиками и программистами для описания своих приемов реализации. 24.3. Классы 809 Некоторые из классов, являющихся артефактами реализации, также представляют собой понятия реального мира.