Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP / books / Osnovi objektno-orientirovannogo programmirovaniya.pdf
Скачиваний:
62
Добавлен:
03.03.2016
Размер:
9.04 Mб
Скачать

Рис. 3.14. Адаптация модуля к новым клиентам Благодаря механизму наследования ОО, разработчики могут осуществлять гораздо более

последовательный подход к разработке ПО, чем это было возможно при использовании прежних методов. Один из способов описания принципа Открыт-Закрыт и следующих из него ООметодов состоит в рассмотрении их как организованного хакерства. Под "хакерством" здесь понимается небрежный (slipshod) подход к компоновке и модификации программы (а вовсе не несанкционированное и, конечно, недопустимое проникновение в компьютерные сети). Хакера можно считать плохим человеком, но часто намерения его чисты. Он может разглядеть полезный фрагмент программы, который почти пригоден для реализации текущих потребностей, намного превосходящих потребности, предусмотренные при первоначальной разработке программы. Вдохновленный похвальным желанием не создавать повторно то, что можно повторно использовать, наш хакер начинает модифицировать исходный текст программы, дополняя его средствами для выполнения новых задач. Конечно, такой порыв неплох, но результатом часто оказывается "засорение" программы многочисленными выражениями вида: if(этот_частный_случай) then. После нескольких повторений, возможно, осуществляемыми разными хакерами, программа начинает походить на ломоть швейцарского сыра, оставленного слишком долго на августовской жаре (безвкусность этой метафоры оправдывается тем, что она хорошо воспроизводит появление в такой программе как "дырок", так и "наростов").

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

Небольшое предупреждение: здесь не предлагается неорганизованное хакерство. В частности:

*Если имеется возможность переписать исходную программу так, чтобы она, без излишнего усложнения, смогла удовлетворять потребности нескольких разновидностей клиентов, то следует это сделать.

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

Единственный Выбор

Последний из пяти принципов модульности можно считать следствием как принципа Открыт-Закрыт, так и правила Скрытия Информации.

Прежде чем подробно ознакомиться с принципом Единственного Выбора, рассмотрим типичный пример. Предположим, что создается система для работы с библиотекой (в непрограммистском смысле слова: с множеством книг и других изданий, а не модулей программы). Эта система будет обрабатывать структуры данных, представляющие различные публикации. Можно объявить соответствующий тип в синтаксисе языков Pascal-Ada:

type PUBLICATION =

record

author, title: STRING; publication_year: INTEGER

case pubtype:(book, journal, conference_proceedings) of book:(publisher: STRING);

journal:(volume, issue: STRING);

proceedings:(editor, place: STRING) -- Conference proceedings end

Здесь использован "тип записи с вариантами" (record type with variants) для описания наборов структур данных с полями, одни из которых (в этом примере author, title, publication_year ) являются общими во всех случаях, а другие - характерны для частных вариантов данных.

|Использование конкретной синтаксической конструкции здесь не является существенным. Языки программирования Algol 68 и C обеспечивают такую же возможность с помощью типа "объединение" (union). Тип union это тип T, определен как объединение ранее существовавших типов A, B,:: значение типа T это либо значение типа A, либо значение типа B,: . Достоинством типов записей с вариантами является то, что в них с каждым вариантом явно связан некоторый ярлык (tag), например book, journal, conference_proceedings. |

Пусть A - модуль, который содержит описанное выше объявление типа. Пока модуль A считается открытым, к нему можно добавлять поля или вводить в него новые варианты. Но когда модуль A передается клиентам, следует закрыть его, а это по умолчанию означает, что в нем уже перечислены все существенные поля и варианты. Итак, пусть B это типичный клиент модуля A. B будет манипулировать с публикациями через некоторую переменную, например:

p: PUBLICATION

Чтобы с помощью p осуществлять какие-либо полезные действия, необходимо явно выделить различные случаи:

case p of

book:... Instructions which may access the field p.publisher...

journal:... Instructions which may access fields p.volume, p.issue...

proceedings:... Instructions which may access fields p.editor, p.place...

end

Здесь оказалась удобной команда выбора case из языков Pascal и Ada; ее синтаксис воспроизводит определение типа записи с вариантами. В Fortran'е и C это может имитироваться многократным использованием команды безусловного перехода goto (switch в языке C). В этих и других языках такой же результат можно получить, используя вложенные команды условного перехода ( if ... then ... elseif ... elseif ... else ... end ).

Следует отметить, что, независимо от используемой синтаксической конструкции, для осуществления такого выбора каждый модуль-клиент должен знать полный список вариантов представления для публикации, поддерживаемых модулем A. Последствия этого нетрудно предвидеть. Наступит момент, когда потребуется новый вариант, например технические отчеты фирм и университетов. Тогда необходимо расширить определение типа PUBLICATION в модуле A, учитывающее новый случай. Это вполне логично и неизбежно: если было изменено определение понятия публикации, то следует обновить и соответствующее объявление типа.

Однако значительно труднее найти оправдание другому следствию: любой клиент модуля A, такой как B, также будет требовать обновления, если в нем использовалась рассмотренная выше структура, основанная на полном списке случаев для p. А это, очевидно, будет иметь место для большинства клиентов.

Итак, наблюдаются очень опасные изменения в программе: простое и естественное дополнение может вызвать цепную реакцию изменений во многих модулях-клиентах.

Эта проблема возникнет всякий раз, когда некоторое понятие допускает множество вариантов. Здесь таким понятием было "публикация" ("publication"), а его начальными вариантами были: книга (book), журнальная статья (journal article), труды конференции (conference proceedings); другими типичными примерами могут быть:

*В системе работы с графикой: понятие фигуры (figure), с такими вариантами как многоугольник (polygon), окружность (circle), эллипс (ellipse), отрезок (segment) и другие основные виды фигур.

*В текстовом редакторе: понятие команды пользователя (user command), с такими вариантами как вставка строки (line insertion), удаление строки (line deletion), удаление символа

(character deletion), глобальная замена (global replacement) одного слова другим.

*В компиляторе для языка программирования: понятие языковой конструкции (language construct), с такими вариантами как команда (instruction), выражение (expression), процедура

(procedure).

В любом таком случае необходимо допускать возможность того, что список вариантов, заданных и известных на некотором этапе разработки программы, может в последующем быть изменен путем добавления или удаления вариантов. Чтобы обеспечить реализацию такого подхода к процессу разработки программного обеспечения, нужно найти способ защитить структуру программы от воздействия подобных изменений. Отсюда следует принцип Единственного Выбора:

Принцип Единственного Выбора Всякий раз, когда система программного обеспечения должна поддерживать

множество альтернатив, их полный список должен быть известен только одному модулю системы.

Требование того, чтобы список выбора был известен лишь одному модулю, обеспечивает подготовку к последующим изменениям: при добавлении вариантов понадобится произвести обновление только того модуля, в котором содержится эта информация - такова сущность единственного выбора. А все остальные модули, в частности - его клиенты, смогут продолжать свою работу как обычно.

Таким образом, как показывает пример с библиотекой публикаций, традиционные методы не обеспечивают решения проблемы, в то время как объектные технологии позволят получить ее решение благодаря двум методическим приемам, связанным с наследованием: полиморфизмом (polymorphism) и динамическим связыванием (dynamic binding). Однако приведенного здесь предварительного обсуждения недостаточно; эти методические приемы можно будет понять лишь в контексте всего метода наследования. (См. "Динамическое связывание" лекция 4)

Принцип Единственного Выбора нуждается еще в нескольких комментариях:

*В соответствии с этим принципом, список возможных выборов должен быть известен одному и только одному модулю. Из целей модульного программирования следует, что

желательно иметь не более чем один модуль, располагающий этой информацией; но очевидно также, что ею должен обладать хотя бы один модуль. Невозможно составить программу текстового редактора, если по крайней мере один из компонентов не будет иметь списка всех

поддерживаемых этой программой команд, для графической программы - списка всех типов фигур, для компилятора - списка всех языковых конструкций.

*Подобно другим правилам и принципам, обсужденным в этой лекции, принцип Единственного Выбора касается распределения знаний (distribution of knowledge) в системе ПО. Этот вопрос является действительно решающим при поиске расширяемых, многократно используемых программных средств. Чтобы получить цельную, надежную архитектуру ПО, следует предпринять строго обдуманные шаги по ограничению объема информации, доступной каждому модулю. По аналогии с методами, используемыми некоторыми общественными организациями, можно назвать это принципом необходимого знания (need-to-know) : запретить каждому модулю доступ к любой информации, которая не является безусловно необходимой для его надлежащего функционирования.

*Можно рассматривать принцип Единственного Выбора как прямое следствие принципа Открыт-Закрыт. Обсудим пример с библиотекой публикаций в свете рисунка, иллюстрирующего необходимость в открытых и закрытых модулях: A это модуль, содержащий первоначальное описание типа PUBLICATION ; клиенты B, C это модули, зависящие от исходного списка вариантов; A' это усовершенствованная версия A, предлагающая дополнительный вариант - технические отчеты (technical reports). (См. второй рисунок в разделе "Открыт-Закрыт")

*Можно также понимать этот принцип как сильную форму принципа Скрытия Информации. Разработчик модулей-поставщиков, таких как A и A', стремится скрыть информацию (относительно точного списка вариантов для некоторого понятия) от модулейклиентов.

Соседние файлы в папке books