Файл: Применение объектно-ориентированного подхода при проектировании информационной системы (Методы и средства).pdf
Добавлен: 23.04.2023
Просмотров: 12092
Скачиваний: 1
Таким образом, при использовании наследования можно описать объект путём определения того общего класса (или классов), к которому он относится, с теми специальными чертами, которые делают объект уникальным. Наследование играет очень важную роль в OOP.
2. ОСНОВНЫЕ ПОНЯТИЯ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ
2.1 Полиморфизм
Полиморфизм (polymorphism) (от греческого polymorphos) - это свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач.
Целью полиморфизма, применительно к объектно-ориентированному программированию, является использование одного имени для задания общих для класса действий. Выполнение каждого конкретного действия будет определяться типом данных [1].
Например для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует трёх различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В С++ каждая из этих функций может быть названа abs().
Тип данных, который используется при вызове функции, определяет, какая конкретная версия функции действительно выполняется. В С++ можно использовать одно имя функции для множества различных действий. Это называется перегрузкой функций (function overloading) [4].
В более общем смысле, концепцией полиморфизма является идея «один интерфейс, множество методов». Это означает, что можно создать общий интерфейс для группы близких по смыслу действий.
Преимуществом полиморфизма является то, что он помогает мнижать сложность программ, разрешая использование того же интерфейса для задания единого класса действий.
Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор. Программисту, не нужно делать этот выбор самому. Нужно только помнить и использовать общий интерфейс. Пример из предыдущего абзаца показывает, как, имея три имени для функции определения абсолютной величины числа вместо одного, обычная задача становится более сложной, чем это действительно необходимо.
Полиморфизм может применяться также и к операторам. Фактически во всех языках программирования ограниченно применяется полиморфизм, например, в арифметических операторах.
Так, в Си, символ + используется для складывания целых, длинных целых, символьных переменных и чисел с плавающей точкой [3]. В этом случае компилятор автоматически определяет, какой тип арифметики требуется. В С++ можно применить эту концепцию и к другим, заданным типам данных. Такой тип полиморфизма называется перегрузкой операторов (operator overloading).
Таким образом, ключевым в понимании полиморфизма является то, что он позволяет манипулировать объектами различной степени сложности путём создания общего для них стандартного интерфейса для реализации похожих действий.
2.2 Инкапсуляция
Инкапсуляция (encapsulation) - это механизм, который объединяет данные и код, манипулирующий этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования.
В объектно-ориентированном программировании код и данные могут быть объединены вместе; в этом случае говорят, что создаётся так называемый «чёрный ящик» [4].
Когда коды и данные объединяются таким способом, создаётся объект (object). Другими словами, объект - это то, что поддерживает инкапсуляцию.
Внутри объекта коды и данные могут быть закрытыми (private). Закрытые коды или данные доступны только для других частей этого объекта. Таким образом, закрытые коды и данные недоступны для тех частей программы, которые существуют вне объекта. Если коды и данные являются открытыми, то, несмотря на то, что они заданы внутри объекта, они доступны и для других частей программы [5]. Характерной является ситуация, когда открытая часть объекта используется для того, чтобы обеспечить контролируемый интерфейс закрытых элементов объекта.
Таким образом, объект является переменной определённого пользователем типа. Может показаться странным, что объект, который объединяет коды и данные, можно рассматривать как переменную. Однако применительно к объектно-ориентированному программированию это именно так. Каждый элемент данных такого типа является составной переменной.
2.3 Абстракция
Абстракция данных означает предоставление только важной информации внешнему миру и скрытие их фоновых данных, т. е. Представление необходимой информации в программе без предоставления деталей.
Абстракция данных - это метод программирования (и проектирования), который основан на разделении интерфейса и реализации [2]. Возьмем один реальный пример телевизора, который можно включить и выключить, изменить канал, отрегулировать громкость и добавить внешние компоненты, такие как динамики, видеомагнитофоны и проигрыватели DVD,
Но, не известны его внутренние детали, не известно как он получает сигналы по воздуху или по кабелю, как он их переводит, и, наконец, отображает их на экране.
Таким образом, мы можем сказать, что телевизор четко отделяет внутреннюю реализацию от внешнего интерфейса, и можно играть с его интерфейсами, такими как кнопка питания, сменщик каналов и регулятор громкости, не имея нулевого знания о его внутренних компонентах.
В C ++ классы обеспечивают отличный уровень абстракции данных. Они обеспечивают достаточные общественные методы внешнему миру, чтобы играть с функциональностью объекта и манипулировать объектными данными, то есть состоянием, не зная, каким образом класс был реализован внутри страны [7].
Например, программа может сделать вызов функции sort (), не зная, какой алгоритм фактически использует функция для сортировки данных значений. Фактически, базовая реализация функции сортировки может меняться между версиями библиотеки, и пока интерфейс остается прежним, ваш вызов функции будет работать. В C ++ используем классы для определения наших собственных абстрактных типов данных (ADT). Можно использовать объект cout класса ostream для потоковой передачи данных на стандартный вывод следующим образом:
#include <iostream>
using namespace std;
int main() {
cout << «Hello C++»<<endl;
return 0;
}
Здесь не нужно понимать, как cout отображает текст на экране пользователя. Нужно знать только открытый интерфейс, а базовая реализация «cout»может быть изменена.
В C ++ используем метки доступа для определения абстрактного интерфейса для класса. Класс может содержать ноль или более ярлыков доступа. Члены, определенные с помощью общедоступного ярлыка, доступны для всех частей программы.
Представление абстракции данных типа определяется его публичными членами. Члены, определенные с помощью частного ярлыка, недоступны для кода, который использует класс. Частные разделы скрывают реализацию от кода, который использует этот тип. Нет ограничений на то, как часто может появляться метка доступа [9]. Каждая метка доступа указывает уровень доступа следующих определений элементов. Указанный уровень доступа остается в силе до тех пор, пока не встретится следующая метка доступа или не увидит закрытие правой скобки тела класса.
Абстракция данных обеспечивает два важных преимущества -
- Внутренние элементы класса защищены от непреднамеренных ошибок на уровне пользователя, что может привести к повреждению состояния объекта.
- Реализация класса может развиваться со временем в ответ на изменение требований или отчетов об ошибках без изменения кода пользователя.
Определяя члены данных только в приватном разделе класса, автор класса может вносить изменения в данные. Если реализация меняется, необходимо изучить только код класса, чтобы увидеть, что может повлиять на изменение.
Если данные общедоступны, то любая функция, которая напрямую обращается к элементам данных старого представления, может быть нарушена. Любая программа на C++, где реализуется класс с общедоступными и частными членами, является примером абстракции данных [6].
Таким образом, абстракция разделяет код на интерфейс и реализацию. Поэтому при разработке компонента нужно поддерживать независимый интерфейс от реализации, чтобы при изменении базовой реализации интерфейс оставался неповрежденным.
3. РАЗРАБОТКА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ С ПРИМЕНЕНИЕМ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ
3.1 Паттерны проектирования
Паттерн (от англ. Pattern) - образец, шаблон. Шаблоны не связаны с каким-либо конкретным языком программирования. Это просто подход к проектированию чего-то. Если заглянуть глубже, то многие ООП-паттерны были созданы на основе реальных жизненных ситуаций при проектировании вполне осязаемых объектов в нашем мире [5]. Именно на таких метафорах и описаниях будет построена следующая экспозиция.
1. Порождающие паттерны
Паттерны которые создают новые объекты, или позволяют получить доступ к уже существующим. То есть те шаблоны, по которым можно создать новый автомобиль и как это лучше сделать.
Singleton (одиночка)
Одна из самых известных и, возможно, самых противоречивых моделей. Представьте себе, что в городе нужно организовать общение между жителями. С одной стороны, мы можем соединить всех жителей друг с другом, протянув между ними телефонные линии, но эта система неверна.
Например, как дорого было бы добавить еще одного резидента к соединению (чтобы продлить еще одну линию для каждого резидента). Чтобы избежать этого, мы создаем телефонную станцию, которая будет нашим «одиночкой». Она всегда одна, и если кому-то нужно связаться с кем-то, они могут сделать это через эту телефонную станцию, потому что все обращаются только к ней.
Соответственно, чтобы добавить нового резидента, вам нужно будет только изменить записи на самой телефонной станции. Как только вы создадите телефонную станцию, ею сможет пользоваться каждый и только один из нее, в свою очередь, эта станция помнит все, что с ней произошло с момента ее создания и каждый может воспользоваться этой информацией, даже если он только что прибыл в город.
Registry (реестр, журнал записей)
Как следует из названия, этот шаблон предназначен для хранения записей, помещенных в него, и, соответственно, возврата этих записей (по имени), если они требуются. В примере с телефонной станцией это регистр по отношению к телефонным номерам жителей.
Multiton (пул «одиночек»)
Как следует из названия паттерна, он по существу является «реестром», содержащим несколько «одиночек», каждая из которых имеет свое собственное «имя», по которому к ней можно получить доступ.
Object pool (пул объектов)
По аналогии с «пулом одиночек» данный паттерн также позволяет хранить уже готовые объекты, однако они не обязаны быть «одиночками».
Factory (фабрика)
Суть паттерна почти полностью описана его названием. Когда вам нужно получить некоторые предметы, такие как пакеты сока, вам не нужно знать, как они сделаны на заводе. Дается команда «сделай мне пакет апельсинового сока», и «фабрика» возвращает нужный пакет. Главное назначение «фабрики»- иметь возможность при необходимости изменить процесс «внешнего вида» упаковки сока, а самому потребителю не нужно было об этом сообщать, чтобы он запросил ее, как и раньше.
Builder (строитель)
Этот паттерн очень тесно переплетается с «фабричным» паттерном. Главное отличие заключается в том, что «конструктор »внутри себя обычно содержит все сложные операции по созданию объекта (сок-пакет). Дается команда «я хочу сок», и строитель начинает целую цепочку различных операций (создание пакета, печать на нем изображений, наполнение его соком, учет количества созданных пакетов и т. д.).). Если вам нужен другой сок, например ананасовый, то точно так же это как раз то, что вам нужно, и «Строитель» позаботится об остальном (некоторые процессы повторятся, некоторые сделают снова и т. д.). В свою очередь процесс в «Строителе» можно легко изменить (например, изменить рисунок на упаковке), но потребители знают, что сок не требуется, легко требовать пакет сока по тому же запросу.
Prototype (прототип)
Этот паттерн чем-то похож на «фабрику», он также служит для создания объектов, но с несколько иным подходом. Представьте себе, что у вас есть пустой пакет (из-под сока), а вам нужен полный с апельсиновым соком. На пакет дается команда «я хочу пакет апельсинового сока», он в свою очередь создает свою собственную копию и наполняет ее тем соком, который был запрошен. Немного «сказочный пример», но в программировании это часто случается. В этом случае пустой пакет является «прототипом», и в зависимости от того, что требуется, он создает на его основе необходимые объекты (пакеты сока). Клонирование не обязательно должно выполняться на самом «пакете», это также может быть какой-то другой объект, главное, что этот прототип «позволяет получить его экземпляры.