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


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

Как объектно-ориентированная альтернатива лишилась признака

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

Рассмотрим специфику различных способов группировки на простом примере. Предположим, что нам необходимо выполнить множество обобщающих процедур, доступных через множество их сигнатур F(D):

F(D) = {F1(D), F2(D), … , Fm(D)},

D = {D1, D2, … , Dn} - обобщающий аргумент одного из типов:

type(Dj) = tj, где tj T и T ={t1, t2, … , tn}.

При этом для выполнения процедуры Fi, обрабатывающей аргумент типа tj, используется специализированная процедура fij(Dj). Процессор, обрабатывающий такую полиморфную процедуру, может использовать два различных варианта последовательного доступа к альтернативным параметрам. В первом случае обработка может начаться с определения значения процедуры, а лишь затем будет осуществляться анализ типа операнда. На некотором C-подобном языке такой вариант анализа можно представить в виде следующей схемы:

switch(F) {
  case F1:
    switch(type(D)) {
      case t1: f11(D1); break;
      case t2: f12(D2); break;
      ...
      case tn: f1n(Dn); break;
    }
  case F2:
    switch(type(D)) {
      case t1: f21(D1); break;
      case t2: f22(D2); break;
      ...
      case tn: f2n(Dn); break;
    }
    ...
  case Fm:
    switch(type(D)) {
      case t1: fm1(D1); break;
      case t2: fm2(D2); break;
      ...
      case tn: fmn(Dn); break;
    }
}

Тот же самый результат на выходе можно получить, если в начале проанализировать тип аргумента, а лишь затем – значение процедуры:

switch(type(D)) {
  case t1:
    switch(F) {
      case F1: f11(D1); break;
      case F2: f21(D1); break;
        ...
      case Fm: fm1(D1); break;
    }
  case t2:
    switch(F) {
      case F1: f12(D2); break;
      case F2: f22(D2); break;
      ...
      case Fm: fm2(D2); break;
    }
    ...
  case tn:
    switch(F) {
      case F1: f1n(Dn); break;
      case F2: f2n(Dn); break;
      ...
      case Fm: fmn(Dn); break;
    }
}

Первый способ анализа задает зависимость данных от исполняемых процедур. Именно таким образом происходит группировка внутри процедурных программ. Группировка процедур в зависимости от типов данных является спецификой объектного программирования. Эта специфика практически не проявляется, если мы имеем дело с некоторым процессором, занимающимся анализом произвольных комбинаций процедур и данных, поступающих на его вход.

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

В ОО программах методы классов тоже размещаются в местах, определенных алгоритмом обработки данных. Но их привязка к типам обрабатываемых данных осуществляется во время кодирования и в декларативной манере посредством механизма виртуализации. В программе не требуется создание экземпляров конкретных объектов, но заготовки отношений между типами данных и процедурами уже хранятся в виде векторов отношений, в каждом из классов Сi С:

С1 = (t1, f11, f 11, f m1),
С2 = (t2, f 12, f 22, f m2), Сn = (tn, f 1n, f 2n, f mn).

Поэтому, когда в ходе выполнения программы формируется экземпляр объекта Di типа ti, создается и экземпляр отношения Ci, которое содержит и процедуры, обеспечивающие требуемую обработку созданного объекта.

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


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