11.1. Что такое тотальное ООП?

    1. Тотальное объектно-ориентированное программирование 11.1. Что такое «тотальное» ООП? Инженер знает, как разработать прибор, но не знает, кому продать и где взять на это деньги. Финансовый директор знает, где взять деньги, но не знает, что с ними делать. Коммерческий директор знает, кому продать прибор, но не знает, как его сделать. Менеджер знает, как организовать работу инженера, но не знает, чем инженеру следует заниматься. И, наконец, генеральный директор не знает ничего перечисленного, но может заставить работать всех вместе.

    Приведенный образец «разделения труда» как нельзя лучше отражает основной принцип ООП: каждый класс моделирует отдельную сущность и работает в пределах своей компетенции. С точки зрения этого подхода программа выглядит как система взаимодействующих объектов различных классов. При этом основной элемент традиционной технологии программирования – поток управления (последовательность команд) как бы «исчезает». На самом деле он никуда не девается, просто его становится сложно отследить в тексте программы, которая, как единое синтаксическое целое, «распадается» на систему взаимодействующих объектов. Перечислим синтаксические и технологические компоненты, «ответственные» за такое представление программы.

    Синтаксическая последовательность «объект-метод-объект». Объектно-ориентированный подход заключается в первичности данных (объектов) по отношению к алгоритмам (методам) их обработки. Причем любая сущность, с которой программист сталкивается при написании программы, должна являться объектом (меню, файл, таблица, строка, вплоть до самой main). Цепочка вызовов функций («функция-функция») в такой программе заменяется на последовательность «объект-метод-объект», которая уже не всегда является строго древовидной.

    Рис. 111-1. Цепочка «объект-метод-объект»

    Объект aa класса A вызывает метод F, в котором создается локальный объект bb класса B, для которого вызывается метод G. Здесь мы имеем некоторый эквивалент цепочки вызовов функций: объект во время работы порождает объект, во время работы с ним порождается объект и т.д..

    class B{

    public: void G(){ … }

    };

    class A{

    public: void F(){ B bb; bb.G(); … }

    };

    void main(){ A aa; aa.F(); }

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

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

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

    Потоки. Поток представляет собой поток управления (вызов функции, метода, последовательность команд), выполняемых независимо (физически параллельно или в режиме переключения ядром операционной системы (ОС)) от основного потока управления (main) и других потоков. Каждый поток имеет собственный локальный контекст – локальные данные и «историю вызовов», т.е. стек. В технологии ООП потоки реализуются в виде класса, имеющего объявленный метод (run), выполняемый в каждом объекте в виде независимого потока. К сожалению, в Си++ концепция потоков не поддерживается. Потоковое программирование весьма плодотворно при программировании систем, в которых имеется множество идентичных независимо исполняемых работ. Реализация потоков обычно поддерживается на уровне ОС.

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