← Назад в библиотеку

Источник: Воробьёв Л.О. Анализ специфики реализации объектного подхода в современных технологиях программирования / Л.О. Воробьёв, А.В. Григорьев . // Программная инженерия: методы и технологии разработки информационновычислительных систем (ПИИВС-2018): сборник научных трудов II научно-практической конференции (студенческая секция) . — Донецк : ДонНТУ , 2018. — Том 2. — С. 27–32. — URL: http://pi.conf.donntu.ru/coll... .


Анализ специфики реализации объектного подхода в современных технологиях программирования

Л.О. Воробьёв, А.В. Григорьев
Донецкий национальный технический университет

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

Введение

Исследованию вопроса объектной ориентированности разработки программного обеспечения посвящёно много научных работ [1-5] на протяжении нескольких десятилетий. Однако до сих пор нет точного определения объектной ориентированности программного обеспечения [6]. В данной статье сделана попытка унифицировать знания об объектном подходе с целью использования их для совершенствования методов разработки программного обеспечения.

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

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

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

1. Объектно-ориентированный подход

Существуют разные подходы к определению объектно-ориентированного подхода (ОО-подхода).

Согласно Лафоре, ОО-подход изолирует данные и алгоритмы из разнородных фрагментов программы.

Согласно Флоренсову [5], ОО-подход основан на динамическом определении данных.

В целом, определения ОО-подхода имеют следующие противоречия:

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

Не исключено, что назначение и трактовка ОО-похода в будущем изменится непредвиденным образом благодаря прогрессу в области технологий программирования.

2. Технологии программирования

Технологиями реализации ОО-подхода являются парадигма объектно-ориентированного программирования и паттерны (приемы) ОО-проектирования.

Согласно Б. Страуструпу, парадигмой программирования является указание программисту, что делать, при написании программы. Например: решите, какие процедуры нужны, используйте наилучшие алгоритмы.

Согласно Бердоносову [6] и теории ТРИЗ, парадигма программирования возникает в результате разрешения противоречий, и сохраняет некоторые признаки предшествующих парадигм.

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

Паттерном является решение общей задачи проектирования в конкретном контексте [7].

В сущности, паттерны ОО-проектирования используют композицию, наследование и протокол взаимодействия объектов для решения часто возникающей задачи проектирования [7,8].

3. Тиражирование типов

Тиражирование типов — создание новых типов данных из образца.

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

Реализация полиморфизма типов в разных языках программирования различны. Приведем пример: создаем функцию, которая вычисляет квадрат числа. Необходимо обеспечить возможность использования созданной функции для всех видов чисел: целые, вещественные, комплексные. Реализация на C++14 (см.рис. 1).

template ::value>>
inline T square(T x) { return x*x; }

Рис. 1 — Реализация обобщенной функции square на C++14

На рис. 1 приведен пример обобщенного программирования с использованием шаблонов. Шаблоны функций и классов на современном C++ подробно рассмотрены в литературе [9] и ISO IEC 14882.

Для реализации этой функции на языке Си раньше использовались макроопределения.

Реализация на языке Haskell выглядит короче (см. рис. 2).

square :: Num a => a -> a
square = (^2)

Рис. 2 — Запись функции square на языке Haskell

Тип функции в первой строке означает, что входом и выходом функции являются числа одного типа. На самом деле, в данной ситуации определение типа функции является необязательным, поскольку компилятор использует алгоритм Хиндли-Милнера автоматического вывода типов. Разница в размере исходного кода обусловлена необходимостью указывать типы входных и выходных значений в статически типизированных языках, а также наличием механизма вывода типов в функциональных языках.

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

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

template 
struct is_arithmetic> : public true_type{};

Рис. 3 — Расширение класса арифметических типов данных на языке C++

Однако этого можно не делать, если убрать проверку типа в шаблоне функции.

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

В динамически типизированных языках за счет динамического определения типов функция может обрабатывать любые числа (см. рис. 4,5,6). Аналогичного результата в статически типизированных языках можно достигнуть с использованием шаблонов или вывода типов.

def square(x):
    return x*x;

Рис. 4 — Реализация функции square на языке Python

def square(x) x**2 end

Рис. 5 — Реализация функции square на языке Ruby

sub square { return $_[0] ** 2; }

Рис. 6 — Реализация функции square на языке Perl

Реализация на Python (см. рис. 4) отличается от реализации на Perl наличием имен параметров и отсутствием фигурных скобок. То же самое утверждение относится к реализации на Ruby (см. рис. 5).

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

Существует также прототипная модель ООП, в которой объекты являются прототипами (см. рис. 7,8).

function square(x) return x^2 end

Рис. 7 — Реализация функции square на языке Lua

Number square := method (**2)

Рис. 8 — Реализация функции square на языке Io

В прототипных ОО-языках полиморфизм типов обеспечивается тем, что все числа порождаются от Number, которому был добавлен метод square. Однако, при определении нового типа, например, комплексных чисел, необходимо переопределить его операторы.

Полиморфизм типов с помощью шаблонов реализован в Java (см. рис. 9), C#, D (рис. 10,11).

public static  T square (T x) {
    return x*x;
}

Рис. 9 — Реализация функции square на языке Java

public static T square (T x) { return x*x; }

Рис. 10 — Реализация функции square на языке C#

T square(T)(T x) { return x*x; }

Рис. 11 — Реализация функции square на языке D

Компилируемые в байт-код языки (Java, C#) на самом деле используют обобщения вместо шаблонов. Это означает, что типом параметра T может быть только класс. При этом, для использования шаблонных функций с базовыми типами используются механизм упаковки переменных в обертки.

Примечательно, что в языке D для указания списка параметров шаблона используются круглые скобки. Эту особенность авторы обосновывают упрощением синтаксического анализатора [10].

4. Абстракции типов

Абстракция типов — это отделение интерфейса от классов от его реализации. Разные языки программирования предоставляют механизмы для этого вида абстрагирования. В качестве примера приведем общую задачу создания абстрактного интерфейса (см. рис. 12).

struct ISimple {
    virtual int touch() = 0;
}
class Simple : public ISimple {
    int touch() override { return 0; }
}

Рис. 12 — Отделение интерфейса от реализации средствами C++

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

На языке Haskell для выделения абстрактных интерфейсов используются классы типов (см. рис. 13).

class Simple a where
    touch :: Int
instance Simple Int where
    touch = 0

Рис. 13 — Отделение интерфейса от реализации на Haskell

В Haskell классы типов являются одновременно средством абстрагирования и вывода типов.

На языке Perl классами являются программные модули (см. рис. 14).

package ISimple;
sub new { return bless { }, shift; }
package Simple;
@ISA = qw/ISimple/;
sub touch { return 1; }
1;

Рис. 14 — Определение иерархии классов на Perl

В Perl методы класса и объекта определяются, как функции модуля. Поскольку в Perl нет абстрактных методов (функций без реализации нет), реализация интерфейса классом только подразумевается.

На Ruby, для реализации классов используются соответствующие выразительные средства (см. рис. 15).

require ‘interface’
ISimple = interface{ required_methods :touch }
class Simple
    def touch 0 end
    implements ISimple
end

Рис. 15 — Отделение интерфейса от реализации на Ruby

На языке D реализация абстракции типов похожа на C++ , но проще (см. рис. 16).

interface ISimple {
    int touch();
}
class Simple : ISimple {
    void touch() { return 0; }
}

Рис. 16 — Отделение интерфейса от реализации на языке D

Отличие состоит в отсутствии необходимости указания чистоты и виртуальности методов интерфейса.

5. Создание объектов

ОО-подход — описание программы в терминах объектов и операций над ними. Для создания объектов определенного типа в разных языках программирования используются разные инструкции (см. рис. 17,18,19,20).

auto object = new Object;

Рис. 17 — Создание объекта C++

do object <- Object; object

Рис. 18 — Определение объекта Haskell

my $object = Object->new;

Рис. 19 — Создание объекта Perl

object = Object.new

Рис. 20 — Создание объекта Ruby

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

В языке Perl (см. рис. 19) объекты создаются с помощью определенной пользователем функции new (см. рис. 14). Эта функция содержит оператор bless, который связывает переменную с именем модуля. Таким образом переменная становится объектом.

В языке Ruby (см. рис. 20) операция new определена в недрах стандартной библиотеки.

В прототипных ОО-языках объекты создаются путем клонирования (см. рис. 21).

object := Object clone

Рис. 21 — Создание объекта Io

При клонировании новый объект получает копию старого объекта со всеми методами и данными. Аналогичный механизм реализован в Lua (см. рис. 22).

object = Object:new()

Рис. 22 — Создание объекта Lua

Где Obejct — определенный пользователем тип.

Кроме того, в языке Smalltalk объект класса создается путем посылки сообщения классу-объекту.

С созданием объектов связаны порождающие паттерны проектирования.

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

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

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

6. Взаимодействие объектов

В языке Smalltalk объекты взаимодействуют между собой путем посылки сообщений. Другие языки программирования по-разному реализуют модель посылки сообщений между объектами. В частности путем вызова методов, как подпрограмм. Подробнее об этом описано в литературе [2].

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

Выводы

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

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

Литература

  1. Бадд Т. Объектно-ориентированное программирование в действии [Электронный ресурс]. — СПб. : Питер , 1997. — URL: http://khizha.dp.ua/library/Ti... .
  2. Кирютенко Ю.А. Объектно-ориентированное программирование. Язык Smalltalk / Ю.А. Кирютенко, В.А. Савельев . — М. : Вузовская книга , 2003. — 358 с. — URL: http://www.mmcs.sfedu.ru/jdown... .
  3. Орлов С.А. Программная инженерия. Учебник для вузов. 5-е издание обновленное и дополненное. Стандарт третьего поколения / С.А. Орлов . — СПб. : Питер , 2016. — 640 с. : ил. — URL: https://www.litres.ru/s-a-orlo... .
  4. Логанов С.В. Ещё раз о принципах применения наследования / С.В. Логанов . // Труды НГТУ им. Р.Е. Алексеева . — Нижний новгород : НГТУ , 2017. — С. 28–37. — URL: https://elibrary.ru/item.asp?i... .
  5. Флоренсов А.Н. О внутренних процессах объектно-ориентированного программирования / А.Н. Флоренсов . // Научные труды SWorld . — Омск : ОмГТУ , 2015. — С. 56–64. — URL: https://elibrary.ru/item.asp?i... .
  6. Бердоносов В.Д. Применение ТРИЗ-эволюционного подхода к исследованию объектно-ориентированных языков программирования [Электронный ресурс]. — Комсомольск-на-Амуре : ФГБОУ ВПО КиАГТУ , 2014.
  7. Гамма Э. Приёмы объектно-ориентированного проектирования. Паттерны проектирования / Э. Гамма . // Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес . — СПб. : Питер , 2015. — 386 с. : ил. . Нестерук Д. Design Patterns in Modern C++: Reusable Approaches for Object-Oriented Software Design [Электронный ресурс]. — Apress , 2018. — URL: https://github.com/Apress/desi... .
  8. Вандевурд Д. Шаблоны С++. Справочник разработчика, 2-е изд.: Пер. с англ. / Д. Вандевурд, Н.М. Джонаттис, Д. Грегор . — СПб. : ООО Альфа-книга , 2018. — 848 с. — URL: http://diggerdnepr.ddns.net/wp... .
  9. Александреску А. Язык программирования D.: Пер. с англ / А. Александреску . — СПб. : Символ-Плюс , 2012. — 536 с.
← Назад в библиотеку