Как функции, не являющиеся методами, улучшают инкапсуляцию

на главную - закладки

Жанры

Поделиться:

Как функции, не являющиеся методами, улучшают инкапсуляцию

Шрифт:

Предпосылка

Когда, в 1991 г., я писал первое издание "Эффективное использование C++" (Effective C++ [1]), я изучал проблему определения функций, связанных с классом. Для заданного класса C и функции f, связанной с C, я разработал следующий алгоритм:

if (f необходимо быть виртуальной) сделайте f функцией-членом C;

else

 if (f – это operator›› или operator‹‹) {

сделайте f функцией – не членом;

if (f
необходим доступ к непубличным членам C) сделайте f другом C;

 }

 else if (в f надо преобразовывать тип его крайнего левого аргумента) {

сделайте f функцией – не членом;

if (f необходимо иметь доступ к непубличным членам C) сделайте f другом C;

 } else сделайте f функцией-членом C;

Этот алгоритм хорошо служил мне многие годы, и когда я правил "Эффективное использование C++" для второй издания в 1997 г. [2], я не сделал никаких изменений в этот алгоритм.

Однако, в 1998 году, когда я проводил презентацию в Actel, где Аран Канду (Arun Kundu) заметил, что мой алгоритм диктовал, что функции должны быть методами даже тогда, когда они могли бы быть реализованы как не члены, которые использовали только открытый интерфейс класса C. "Это действительно, что-нибудь означает?" – спросил он меня? Другими словами, если f могла бы быть реализован как функция-член (метод) или как функция не являющаяся не другом, не членом, я действительно защищал, что ее надо реализовать как метод класса? Я немного подумал об этом и решил, что это не то, то, что я подразумевал. Поэтому я изменил алгоритм [3]:

if (f необходимо быть виртуальной) сделайте f функцией-членом C;

else if (f – это operator›› или operator‹‹) {

 сделайте f функцией – не членом;

 if (f необходим доступ к непубличным членам C) сделайте f другом C;

} else if (f необходимо преобразовывать тип его крайнего левого аргумента) {

 сделайте f функцией – не членом;

 if (f необходимо иметь доступ к непубличным членам C) сделайте f другом C;

} else if (f может быть реализована через доступный интерфейс класса) сделайте f функцией – не членом;

else сделайте f функцией-членом C;

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

Но они ошибаются.

Инкапсуляция

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

реализация (я думаю, что мы все согласимся) не является инкапсулированной:

struct Point {

 int x, y;

};

Слабостью этой структуры является то, что она не обладает гибкостью при ее изменении. Как только клиенты начнут использовать эту структуру, будет очень тяжело изменить ее. Придется изменять слишком много клиентского кода. Если бы мы позднее решили, что хотели бы вычислять x и y вместо того, чтобы хранить эти значения, мы были бы обречены на неудачу. У нас возникли бы аналогичные проблемы при запоздалом озарении, что программа должна хранить x и y в базе данных. Это реальная проблема при недостаточной инкапсуляции: имеется препятствие для будущих изменений реализации. Неинкапсулированное программное обеспечение негибко, и, в результате, оно не очень устойчиво. При изменении внешних условий программное обеспечение неспособно элегантно измениться вместе с ними. Не забывайте, что мы говорим здесь о практической стороне, а не о том, что является потенциально возможным. Понятно, что можно изменить структуру Point. Но, если большой объем кода зависит от этой структуры, то такие изменения не являются практичными.

Перейдем к рассмотрению класса с интерфейсом, предлагающим клиентам возможности, подобные тем, которые предоставляет выше описанная структура, но с инкапсулированной реализацией:

class Point {

public:

 int getXValue const;

 int getYValue const;

 void setXValue(int newXValue);

 void setYValue(int newYValue);

private:

… // прочее…

};

Этот интерфейс поддерживает реализацию, используемую структурой (сохраняющей x и y как целые), но он также предоставляет альтернативные реализации, основанные, например, на вычислении или просмотре базы данных. Это более гибкий замысел, и гибкость делает возникающее в результате программное обеспечение более устойчивым. Если реализация класса найдена недостаточной, она может быть изменена без изменения клиентского кода. Принятые объявления доступных методов остаются, неизменными, что ведет к неизменности клиентского исходного текста. (Если необходимые провести изменения [4], то клиенты не нуждаются даже в перетрансляции.)

Инкапсулированное программное обеспечение более гибко, чем неинкапсулированное, и, при прочих равных условиях, эта гибкость делает его предпочтительнее при выборе метода проектирования.

Степень инкапсуляции

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

Комментарии:
Популярные книги

Адвокат Империи 3

Карелин Сергей Витальевич
3. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 3

Кротовский, может, хватит?

Парсиев Дмитрий
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Кротовский, может, хватит?

Дурная жена неверного дракона

Ганова Алиса
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Дурная жена неверного дракона

Вонгозеро

Вагнер Яна
1. Вонгозеро
Детективы:
триллеры
9.19
рейтинг книги
Вонгозеро

Ведьма Вильхельма

Шёпот Светлана
Любовные романы:
любовно-фантастические романы
8.67
рейтинг книги
Ведьма Вильхельма

Папина дочка

Рам Янка
4. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Папина дочка

Законы Рода. Том 6

Flow Ascold
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 6

Как я строил магическую империю 7

Зубов Константин
7. Как я строил магическую империю
Фантастика:
попаданцы
постапокалипсис
аниме
фантастика: прочее
5.00
рейтинг книги
Как я строил магическую империю 7

Лучший из худший 3

Дашко Дмитрий
3. Лучший из худших
Фантастика:
городское фэнтези
попаданцы
аниме
6.00
рейтинг книги
Лучший из худший 3

Штурмовик из будущего 3

Политов Дмитрий Валерьевич
3. Небо в огне
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Штурмовик из будущего 3

Последний попаданец 2

Зубов Константин
2. Последний попаданец
Фантастика:
юмористическая фантастика
попаданцы
рпг
7.50
рейтинг книги
Последний попаданец 2

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Вдова на выданье

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Вдова на выданье