[ <<< | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Источники | >>> ]


© 2001 А.И. Легалов

Объектно-ориентированное агрегирование

Объектно-ориентированное программирование предлагает следующие варианты композиции для создания агрегатов:

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

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

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

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

Пример использования объектно-ориентированного агрегирования

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

//----------------------------------------------------------------------
// Простейший контейнер на основе одномерного массива
//----------------------------------------------------------------------
// Контейнер должен знать о фигуре
#include "shape_atd.h"
//----------------------------------------------------------------------
// Описание контейнера
class container
{
    enum {max_len = 100}; // максимальная длина
    int len; // текущая длина
    shape *cont[max_len];
public:
    void In();     // ввод фигур в контейнер из входного потока
    void Out();    // вывод фигур в выходного потока
    double Area(); // подсчет суммарной площади
    void Clear();  // очистка контейнера от фигур
    container();    // инициализация контейнера
    ~container() {Clear();} // утилизация контейнера перед уничтожением
};
//----------------------------------------------------------------------

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

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

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

//----------------------------------------------------------------------
// Необходимо знать описание контейнера и методов фигуры,
// доступных через container_atd.h
#include "container_atd.h"
//----------------------------------------------------------------------
// Прототип обычной внешней функции, формирующей фигуру при вводе
shape *In();
//----------------------------------------------------------------------
// Инициализация контейнера
container::container(): len(0) { }
//----------------------------------------------------------------------
// Очистка контейнера от элементов (освобождение памяти)
void container::Clear()
{
    for(int i = 0; i < len; i++)
    {
      delete cont[i];
    }
    len = 0;
}
//----------------------------------------------------------------------
// Ввод содержимого контейнера
void container::In() 
{
    cout 
      << "Do you want to input next shape"
         " (yes=\'y\', no=other character)? " 
      << endl;
    char k;
    cin >> k;
    while(k == 'y')
    {
      cout << len << ": ";
      if((cont[len] = simple_shapes::In()) != 0)
      {
        len++;
      }

      cout 
        << "Do you want to input next shape"
           " (yes=\'y\', no=other character)? " 
        << endl;
      cin >> k;
    }
}
//----------------------------------------------------------------------
// Вывод содержимого контейнера
void container::Out() 
{
    cout << "Container contents " << len << " elements." << endl;
    for(int i = 0; i < len; i++) {
      cout << i << ": ";
      cont[i]->Out();
    }
}
//----------------------------------------------------------------------
// Вычисление суммарной площади для фигур, размещенных в контейнере
double container::Area() 
{
    double a = 0;
    for(int i = 0; i < len; i++) {
      a += cont[i]->Area();
    }
    return a;
}
//----------------------------------------------------------------------

Указанные функции использованы в примере, расположенном в архиве oop_examp1.zip.


[ <<< | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Источники | >>> ]