|
Программирование >> Обобщенные обратные вызовы
Задача 17. Инкапсуляция Сложность: 4 Что именно представляет собой инкапсуляция в применении к программированию на С+ + ? В чем именно смысл инкапсуляции и управления доступом для членов-данных - должны ли они иногда быть открытыми или защищенными? В этой задаче мы получим ответы на приведенные вопросы и узнаем, как эти ответы могут повлиять на надежность кода. Вопрос для новичка 1. Что такое инкапсуляция? Насколько она важна в объектно-ориентированном проектировании и программировании? Вопрос для профессионала 2. В каких случаях (если таковые имеются) нестатические члены данных должны быть сделаны открытыми (public), защищенными (protected) и закрытыми (private)? Выразите ват ответ в виде рекомендации программисту. 3. Шаблон класса std::pair использует открытые члены-данные, поскольку он не инкапсулирует никаких данных, а просто позволяет их группировать. Представим щаблон класса наподобие std::pai г, но с тем отличием, что у него дополнительно имеется флаг deleted, который может быть установлен и опрошен (но не сброшен). Ясно, что такой флаг должен быть закрытым для защиты от непосредственного изменения пользователем. Если остальные члены-данные будут открытыми, как в std; :pai г, в конечном итоге мы получим примерно следующий код. template<class т, class и> class couple { publiс: Основные члены-данные открыты... Т fi rst; и second; .. .но есть еще нечто, делающее его более классоподобным , а также закрытая реализация coupleO : deleted (false) {. void MarkDeleted() { deleted = true; ] bool isDeletedO { return deleted ; } private: bool deleted ; Должны ли в этом случае остальные члены-данные быть, как показано в коде, открытыми? Почему? Если да, то является ли этот код хорошим примером того, почему иногда одновременное наличие открытых и закрытых данных в одном классе может быть удачным решением? Решение 1. Что такое инкапсуляция? В словаре Вебстера приведено следующее определение инкапсуляции: окружать, упаковывать или защищать, или находиться в капсуле, оболочке. Инкапсуляция в программировании имеет тот же смысл - защита внутренней реализации класса путем ее сокрытия за внешним интерфейсом, видимым внешнему миру. Определение слова капсула , в свою очередь, дает нам указания о том, каким должен быть хороший интерфейс класса (здесь приведены не все возможные значения этого слова): капсула - 1. структура наподобие мембраны или мешка, окружающая часть органа или орган в целом; 2. закрытый контейнер, содержащий споры или семена; ... 4. желатиновая оболочка вокруг лекарственного препарата; ... металлическая пломба;... 6. оболочка вокруг некоторых микроскопических организмов; ... 9. небольшое герметизированное помещение для летчика или космонавта. ... Обратите внимание на однотипность определений - охватывает, окружает, упаковывает, запечатывает... Хороший интерфейс класса скрывает внутренние детали его реализации, представляя внешнему миру только лицо , которое отделено от внутренностей . Поскольку капсула охватывает одну связанную фуппу подобъектов, се интерфейс также должен быть связанным - все его части должны иметь непосредственное отношение друг к другу. Хороший интерфейс класса должен быть полным и не показывать вовне никаких деталей внутренней реализации класса. Он работает как герметичная оболочка или как брандмауэр (времени компиляции, времени выполнения или и того, и другого одновременно), так что внешний код не может зависеть от внутренней реализации класса, и любые изменения внутреннего строения и реализации класса никак не влияют на внешний используюший этот класс код. Бактерия, оболочка которой не замкнута, проживет недолго... Хороший интерфейс класса защищает его внутренности от неавторизованного доступа и манипуляций. В частности, главная зааача интерфейса - гарантировать, что любое обращение к внутренним структурам класса и работа с ними сохраняют инварианты класса. Основной способ убить бактерию (как и, скажем, человека) - использование устройств, которые нарушают целостность ее внешней и/или внутренней капсул. На микроуровне это могут быть химические реактивы, ферменты или организмы (возможно, даже наномеханизмы), способные проделать в оболочке соответствующие отверстия. На макроуровне предпочтение отдается ножам и автоматам... Место инкапсуляции в объектно ориентированном программировании Насколько оиа важна в обьектно-ориешированном проектировании и программировании? Инкапсуляция -- основная концепция объектно-ориентированного профаммиро-вания. Точка. Прочие объс ктн о - о ри с нти ро ван и ые методы - такие как сокрытие данных, наследование и полиморфизм - важны в первую очередь потому, что они выражают частные случаи инкапсуляции. Инкапсуляция практически всегда влечет за собой сокрытие данных. Полиморфизм времени выполнения, использующий виртуальные функции, более полно отделяет интерфейс (представленный базовым классом) от реализации (которая представляется производным классом, который может даже не существовать в тот момент, когда разрабатывается код, который будет его использовать). Полиморфизм времени компиляции, использующий шаблоны, полностью отделяет интерфейс от реализации, так как любой класс, удовлетворяющий некоторым требованиям, может быть использован шаблоном. Используемые классы не обязаны быть связаны наследованием или каким-либо иным отношением. Инкапсуляция - не всегда сокрытие данных, но сокрытие данных - частный случай инкапсуляции. Инкапсуляция - не всегда полиморфизм, но полиморфизм - всегда форма инкапсуляции. Объектная ориентированность часто определяется следующим образом: связывание в единое целое данных и функций, которые оперируют с этими данными. Такое определение справедливо с определенными допущениями - поскольку оно исключает свободные функции (не являющиеся членами), которые являются логической частью класса (такие как оператор С++). Кроме того, данное определение не подчеркивает другой существенный аспект объектной ориентированности, а именно одновременное отделение данных от вызывающего кода посредством интерфейса, представляющего собой набор функций, которые работают с этими данными. Этот дополнительный аспект подчеркивает слабое связывание внешнего кода и данных, а также то, что предназначение собранных функций - формирование интерфейса, защищающего данные. Кратко можно сказать, что объектно-ориентированное п ро грам мировая и с состоит в отделении интерфейсов от реализации, что обеспечивает, с одной стороны, высокую степень единства кода и данных, и низкую степень связывания - с другой. Разработчики программного обеспечения сталкивались с задачей обеспечения такой связи функций и данных задолго до открытия объектов. Эти концепции относятся к управлению зависимостями, которое представляет собой одно из ключевых понятий в современном проектировании профаммного обеспечения, в особенности для больших систем (см. [Martin95] и другие статьи Мартина (Martin), датированные 1996 годом в [ObjectMentor], в особенности те из них, в заголовке которых есть слово Principle ). Открытые, закрытые или за1дищенные данные? 2. В каких случаях (если таковые имеются) иестатические члены данных должны быть открыты.ми (public), защишенны.чи (protected) и закрытыми (private)? Выразите ваш ответ в виде рекомендации программисту. Обычно мы начинаем с того, что рассматриваем правило, а уже затем - исключения из него. Давайте в этот раз нарушим порядок и сначала рассмотрим исключения, а потом перейдем к правилу. Единственное исключение из общего правила (которое будет приведено далее) - это когда все члены класса (как функции, так и данные) открытые, как в случае структуры в С. В этом случае класс -- не вполне полноценный класс со своим интерфейсом, поведением и инвариантами - словом, это не класс, а набор данных. Такой класс - просто удобное объединение объектов в единое целое, и это вполне нормальное явление, в особенности с точки зрения обратной совместимости с программами С, которые работают со структурами. За исключением этого частного случая, все члены-данные должны быть закрытыми. Открытые данные - нарушение инкапсуляции, поскольку они позволяют вызывающему коду непосредственно работать со внутренними объектами. Это требует высокой степени доверия! В конце концов, в реальной жизни я вряд ли разрешу кому-либо иметь дело непосредственно с моими внутренностями (скажем, позволив копаться внутри живота), поскольку при этом очень легко, пусть даже непреднамеренно, допустить ошибку, которая может, мягко говоря, повредить моему организму. Другое дело - косвенная работа через открытый интерфейс, когда я могу сам решить, что и как делать (например, получив бчтылку с этикеткой Выпей меня , я сам. опираясь на собственные ощущения от содержимого бутылки и свой здравый смысл, решу, пить ли содержимое бутылки или все же с его помощью вымыть машину). Конечно, есть люди, достаточно квалифицированные, чтобы копаться в моих внутренностях
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |