Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 178
Текст из файла (страница 178)
Часто для этого нужно класс, от которого зависят множество других классов и функций, делать абстрактным классом, предоставляющим самые общие операции. Детали лучше оставить более специализированным производным классам, от которых зависят существенно меньше классов и функций. Чем больше классов зависят от данного класса, тем более общим он должен быть и тем меньше деталей он должен раскрывать. Глава 23.
Общий взгляд на разработку программ. Проектирование Существует сильный соблазн — добавлять и добавлять все новые операции (и данные) в класс, используемый многими. Часто это выглядит, как попытка сделать класс более полезным и менее подверженным необходимости в будущих модификациях. Результатом такого образа мыслей является класс с так называемым жирным интерфейсом (324.4.3) и с полями данных, поддерживающими слабо связанные между собой функции. Это опять-таки подразумевает, что при значительных изменениях в зависимых классах, этот класс также придется переделывать. А это порождает необходимость изменений и в других пользовательских и производных классах. Вместо усложнения основного класса проекта лучше делать его как можно более общим и абстрактным.
Особые возможности при необходимости могут быть предоставлены производными классами. Примеры см. в [Мап!и, 1995[. При этом порождается иерархия абстрактных классов, в которой классы, более близкие к вершине иерархии, являются более общими, и от которых зависят большинство других классов и функций системы. Классы-листья представляют собой самые специализированные классы, и от них непосредственно зависит лишь мапая толика кода. В качестве примера рассмотрите окончательную версию иерархии ага! Ьох (э12.4.3, 912.4.4).
23.4.3.6. Использование модельных образцов Собираясь написать статью, я обычно стараюсь подыскать подходящую модель, которой можно было бы следовать. То есть вместо того, чтобы сразу набирать текст, я просматриваю предыдущие статьи на эту тему и прочие публикации, чтобы выбрать из них что-нибудь, что можно взять за начальный образец будущей статьи. Если выбранным образцом (моделью) является моя собственная статья на схожую тему, я могу даже оставить в ней многое в неизменном виде, что-то подправить и добавить лишь что-то новое только там, где этого требует логика новой статьи. Например, данная книга написана на основе первого и второго (предыдуших) изданий. Крайней степенью такой формы работы являются шаблоны писем — я просто заполняю имя и, может быть, добавляю пару строк, чтобы персонализировать послание. По сути дела, в таких письмах я лишь вношу необходимые отличия от стандартного модельного образца.
Такое использование предыдущих систем (наработок) в качестве моделей для новых разработок есть скорее правило, чем исключение в любых видах творческой деятельности. Всюду, где только возможно, проектирование и программирование также должны опираться на ранее выполненные работы. Это позволяет дизайнеру сузить «горизонтыл (фронт работ) и сосредоточиться лишь на нескольких новых вопросах.
Начинать новый проект с чистого листа — это может быть и вдохновляющий старт, но при попытке все точно специфицировать вы попадаете в ловушку множества альтернатив проектирования, среди которых блуждаете как пьяный. Отталкиваться от существующей модели не столь уж и ограничительно, так как не требуется, чтобы вы перед ней раболепствовали; она лишь освобождает дизайнера от необходимости думать обо всем сразу и позволяет ему рассматривать по одному аспекту системы за раз. На самом деле, любой проект неявным образом использует модели (предыдущий опыт задействованных проектировщиков).
Но явный сознательный выбор конкретной модели делает явными предпочтения, предположения, набор терминов, предоставляет начальную среду разработки и увеличивает вероятность того. 23 4 Процесс разработки 833 что разные проектировщики будут работать согласованно на базе одного и того же подхода. Естественно, сам выбор модели является ответственным проектным решением и его следует делать ~олько после тщательного поиска, изучения и отбора имеющихся альтернатив. Более того, во многих случаях модель подходит только в том случае, когда необходимые изменения соответствуют лишь адаптации основных идей к специфике нового приложения. Проектирование программ — сложная работа, и нам нужна любая помощь, которую только можно получить; мы не должны отвергать применение моделей из-за неуместного презрения к «подражательству».
Подражание (имитация) есть наиболее искренняя форма лести, и применение моделей и результатов ранее выполненных работ для вдохновения (конечно, без нарушения авторских прав и прав собственности) является допустимым приемом творческой работы во всех областях: что было хорошо для Шекспира, то хорошо и для нас. Иногда такое применение моделей в проектировании называется повторным использованием проектов (Йезудп геизе). Документирование общих элементов множества проектов совместно с описанием решаемых ими проблем проектирования, а также условий, в которых они применимы, является отличной идеей.
Задокументированные таким образом наиболее общие и особо полезные элементы проектов называют образцами или паттернами (раггегпз), и существует литература по документированию образцов и их использованию (например, [Оапппа, !994[ и [Сор[)еп, [995[). Проектировщику неплохо познакомиться с наиболее известными проектными образцами его предметной области. Как программист, я предпочитаю такие проектные образцы, которые сопровождаются примерами кода. Как и большинство людей, я лучше понимаю основную идею (в данном случае это проектный образец), когда я имею конкретный пример ее применения (здесь это фрагмент кода, иллюстрирующий используемый образец).
Люди, интенсивно использующие проектные образцы, применяют специальную терминологию, помогающую им точнее понимать друг друга. К сожалению, это же может превратиться в закрытый язык, отсеиваюший непосвященных, а ведь, как всегда, очень важно установить тесное общение между разными людьми, участвующими в проекте (323.3) и, в первую очередь, между проектировщиками и программистами. Каждый успешный программный проект является результатом перепроектирования некоторых работающих программных систем меньшего размера. Я не знаю исключений из этого правила.
Можно привести множество примеров неудачных проектов, над которыми работали годами, потратили огромные средства, и, наконец, добились успеха, но много позже первоначальных сроков. Как правило, в таких проектах сначала строилась (непреднамеренно и неосознанно) неработающая система, которая затем трансформировалась в систему работающую, и, наконец, эта система перепроектировалась и реорганизовывалась так, что начинала удовлетворять первоначально заявленным целям. Это говорит о том, что наивно пытаться разрабатывать большие системы «с нуля», лишь следуя новейшим принципам. Чем больше и амбициознее проект, за который вы беретесь, тем важнее для него подобрать исходную модель, с которой можно спокойно начать работу. Для больших систем в качестве моделей следует выбирать нечто меньшее, но уже работающее.
8Э4 Глава 23. Общий взгляд на разработку программ. Проектирование 23.4.4. Экспериментирование и анализ Начиная разрабатывать крупный амбициозный проект, мы не знаем лучшего способа его построения. Часто мы даже не до конца понимаем, что именно система должна делать, поскольку частности проявляются лишь после построения системы, ее тестирования и эксплуатации. Как же нам все-таки получить информацию, необходимую лля понимания того, какие проектные решения важнее всего для разрабатываемой системы, и какие последствия могут быть у проектных решений? Нужно проводить эксперимент.
Нужно сразу же анализировать проект и реализацию, как только мы получаем хоть что-то для анализа. Часто большую пользу дает обсуждение альтернативных проекта и реализации. Во всех случаях, кроме редчайших, проектирование — это коллективная деятельность, в рамках которых проекты представляются и анализируются. Часто важнейшим инструментом визуализации концепций программы является классная доска — без нее они пребывают втуне. Похоже, что самая распространенная форма эксперимента состоит в построении лрототипа (ргогогуре), то есть уменьшенной версии всей системы или некоторой ее части.
Прототипу не предъявляют жестких требований к быстродействию и ресурсам системы (они полагаются априорно достаточными). В результате в кратчайшие сроки получается работающая версия, с которой можно исследовать проект более предметно и выбирать разные реализации. При хорошем исполнении этот подход может принести много пользы. Его также можно использовать и для оправдания небрежности. Трудность состоит в том, что цель прототипа может сместиться от исследования проектных альтернатив просто к получению «хоть какой-то работающей реализации системы как можно скорее». В результате может потеряться интерес к внутренней структуре прототипа («в конце концов, это всего лишь прототип») и возникнуть пренебрежение к проектным усилиям, когда все сведется к возне вокруг реализации прототипа.
Серьезная опасность таится в том, что все может выродиться в худший образец пожирателя ресурсов и кошмар для сопровождения, при этом создавая иллюзию «по пи завершенной» системы. По определению, прототип не имеет ясной внутренней структуры, эффективности и инфраструктуры сопровождения, допускающих его разумное постепенное масштабирование до уровня конечного продукта. Поэтому прототип, превращенный в конечный продукт, лишь впустую отнимает время и энергию у разработчиков. Существует соблазн для проектировщиков и менеджеров превратить прототип в конечный продукт и оставить вопросы эффективности до следующего выпуска. Столь порочная тактика перечеркивает все принципы проектирования. Другая проблема состоит в том, что разработчики прототипа влюбляются в использованные ими ограниченные приемы программирования и забывают, что этого не может позволить себе вся группа программистов и проектировщиков, н что свобода их маленькой группы от ограничений и формальностей не выдержит столкновения с суровой реальностью жестких временных графиков и взаимозависимостей внутри большой группы разработчиков.