учебники, программирование, основы, введение в,

 

Основные понятия объектно-ориентированного подхода: объекты, классы и методы

Изложим понятийный аппарат объектно-ориентированного подхода к программированию.
Прежде чем будут изложены математически строгие определения (в том числе в терминах теории дескрипций), попытаемся сформировать предварительное представление об основных сущностях данного подхода.
Сформулируем на интуитивном уровне определения таких основополагающих для объектно-ориентированного подхода к программированию понятий, как объект, класс, свойство и метод.
Под объектом будем понимать математическое представление сущности реального мира (или предметной области), которое используется для моделирования.
Классом будем называть весьма общую сущность, которая может быть определена как совокупность элементов (нужно заметить, что класс при объектно-ориентированном подходе к программированию – это, как правило, первичное, неопределяемое понятие, до некоторой степени аналогичное теоретико-математическому понятию множества, или, точнее, домена).
Под свойством (или атрибутом) будем понимать пропозициональную функцию, определенную на произвольном типе (данных).
Методом (или функцией) назовем операцию, которая определена над объектами того или иного класса.
Заметим, что класс при объектно-ориентированном подходе является аналогом понятия типа в том смысле, что к нему относят лишь объекты, отобранные по определенному правилу. Это правило можно формализовать математически посредством предикатной функции, т.е. функции, область значений которой совпадает со значениями истинности: «истина» и «ложь». При этом тот или иной объект относится к классу, если значение аппликации функции к данному объекту истинно, и не относится в противном случае.
Функцию такого рода принято называть индивидуализирующей функцией. Индивидуализирующая функция фактически является моделью экспертной классификации.
Важным условием при исследовании объектно-ориентированного подхода к программированию является установление взаимосвязей фундаментальных сущностей. Отметим в этой связи, что понятие класса является изначально более общим, чем понятие объекта. Точнее, говорят, что объект является экземпляром (instantiation) класса.
Таким образом, класс может рассматриваться как совокупность объектов (подобно тому как множество или домен есть совокупность элементов).
В рамках объектно-ориентированного подхода к программированию произвольный класс может быть элементарным либо подразделяться на подклассы (подобно тому как множество или домен подразделяется на подмножества или субдомены).
Например, более общий класс PERSON может содержать внутри себя подкласс STUDENT, который, в свою очередь, содержит конкретный объект John_Smith.
Как отмечалось во вступительной лекции, в 90-е годы В.Э. Вольфенгагеном (Vyatcheslav E. Wolfengagen) была создана так называемая двухуровневая схема концептуализации, основанная на двукратном применении постулата свертывания, до известной степени аналогичного операции ламбда-абстракции.
Рассмотрим более подробно основные аспекты данной формализации объектно-ориентированного подхода к программированию. В общих чертах схема построения модели выглядит следующим образом.
Основу модели составляет типизированный вариант ламбда-исчисления, семантика которого моделируется посредством полных и непрерывных решеток Д. Скотта.
Для описания объектов произвольной сложности вводятся аппликативные структуры с приписыванием типов. Последнее обстоятельство необходимо для формализации иерархии классов, в которые объединяются объекты.
Для формализации определений используются определенные дескрипции Скотта-Фурмана вида:
IxФ,
что означает «тот единственный объект x, для которого значение индивидуализирующей функции Ф истинно».
При таком подходе произвольный объект моделируется упорядоченной тройкой элементов вида
<концепт, индивид, состояние>,
составляющие которой соединены соотнесениями.
Основным соотношением формальной схемы двухуровневой концептуализации является так называемый принцип концептуализации, подобный принципам свертывания, которые (в той или иной форме) присутствуют практически во всех математических теориях, исследованных ранее в рамках курса (в частности, в исследованных ранее в рамках курса ламбда-исчислении и комбинаторной логике).
Формальная запись принципа концептуализации посредством определенных дескрипций выглядит следующим образом:
||Ix(x)Ф(x)||i = d <=>
_
{d} = {d  D| ||Ф(d)||i=true}
Приведем словесную интерпретацию формулы:
Значением индивидного концепта
является функция
из соотнесений в индивиды.
С точки зрения рассматриваемой формальной теории, произвольный объект d предметной области D может быть единственным образом индивидуализирован посредством функции Ф (где i означает соотнесение).
Заметим, что при соотнесении общей теории с языками программирования домен D можно также интерпретировать как класс, а элемент домена d – как объект языка программирования.

Рассмотрев интуитивное определение понятия класса, а также представив домены как формальную модель классов языков программирования в целом, остановимся более подробно на классах в языке объектно-ориентированного программирования C#.
По аналогии с другими известными языками объектно-ориентированного программирования (в частности, C++ и Java), под классом в языке C# понимается ни что иное, как ссылочный тип, определенный пользователем.
При этом для классов языка программирования C# допустимо только единичное наследование. В случае необходимости реализации множественного наследования возможно наследование посредством механизма интерфейсов, который будет подробнее рассмотрен далее в ходе курса.
Членами (или, иначе, элементами) класса языка программирования C# могут являться следующие конструкции:

  • константа, поле, метод, оператор, конструктор, деструктор;
  • свойство, индексатор, событие;
  • статические и инициализированные члены.

Доступ к членам класса определяется исходя из значения модификатора области действия идентификатора класса, который может принимать следующие значения: public, protected, private (данное значение используется по умолчанию), internal, protected internal.
Инициализация объекта класса языка программирования C# производится посредством оператора new, о котором будет рассказано ниже.
Рассмотрим манипулирование классами на примере следующих фрагментов программ на языке C#.
Прежде всего, приведем простейшее описание класса. Описание класса C c целочисленным полем value на языке C# имеет вид:
class C {
...
int value = 0;
...
}
Заметим, что в описании класса C на языке программирования C# кроме рассмотренного поля value могут присутствовать и другие поля (т.е. атрибуты объектов класса) допустимых в языке C# типов, а также методы (т.е. способы манипулирования объектами данного класса).
В языке программирования C# инициализация поля (т.е. связывание его с начальным значением) не является обязательной. Для обеспечения безопасности программного кода и в силу реализации принципа инкапсуляции, инициализация поля некоторого класса C не должна открывать возможностей для доступа к полям и методам данного типа. При этом доступ к элементам класса внутри класса реализуется посредством обращения и не требует полного имени объекта:
... value ...
В отличие от предыдущего случая, доступ из сторонних классов требует указания полного имени объекта (в примере последовательно производятся инициализация и обращение):
C c = new C();
... c.value ...
Рассмотрим более развернутый пример описания классов и манипулирования их элементами.
Приведем описание класса Rectangle, моделирующего прямоугольник с полями origin, width и height, моделирующими, соответственно, начальную точку (с парой координат), ширину и высоту, а также методом MoveTo, моделирующим перемещение начальной точки в заданную:
class Rectangle {
Point origin;
public int width, height;
public Rectangle(){
origin = new Point(0,0);
width=height=0;
}
public Rectangle (
Point p, int w, int h){
origin = p;
width = w;
height = h;
}
public void MoveTo (Point p) {
origin = p;
}
}
Заметим, что модификатор области видимости для данного класса и его элементов разрешает общедоступное применение (public). Рассмотрим пример использования класса Rectangle:
Rectangle r = new Rectangle(
new Point(10,20),5,5);
int area = r.width * r.height;
r.MoveTo(new Point(3,3));
Заметим, что в данном примере последовательно осуществляются инициализация объекта класса Rectangle с начальной точкой (10,20), шириной и высотой в пять единиц (т.е. квадрата), подсчет его площади area и перемещение начала отсчета в точку с координатами (3,3).
В результате анализа рассмотренных примеров становится очевидным, что объект является принципиально динамическим и изменяет состояние в зависимости от соотнесения (времени и внешних воздействий).
В этой связи исследуем более подробно простейший, статический случай полей объекта, который в языке программирования C# выделен в самостоятельный синтаксический элемент, характеризующийся независимостью от состояния объекта (и потому условно принадлежащий к классу). Приведем модифицированный пример предыдущего класса для случая статических полей:
class Rectangle {
static Color defaultColor;
// для каждого класса
static readonly int scale;
// для каждого класса
int x, y, width,height;
// для каждого объекта
...
}
Заметим, что статические поля defaultColor и scale остаются неизменными внутри класса, тогда как динамические поля x, y, width и height индивидуально изменяются в зависимости от состояния каждого из объектов класса. Доступ изнутри класса осуществляется посредством обращения:
... defaultColor ... scale ...
а из внешних классов – посредством обращения:
... Rectangle.defaultColor
... Rectangle.scale ...
с указанием полных имен объектов. Поскольку статические поля являются неизменными со временем, они реализуются выделением памяти из статической области.

Познакомившись с особенностями реализации полей как элементов классов с учетом динамики и статики их реализации, перейдем к рассмотрению способов манипулирования объектами классов, которые в объектно-ориентированном программировании принято называть методами, и которые, по сути, являются функциями. Как и поля, методы описываются в блоке описания класса.
Рассмотрим особенности использования методов на примере следующей программы на языке C#, представляющей описание класса C с полями sum и n и методами Add и Mean:
class C {
int sum = 0, n = 0;
public void Add (int x){
sum = sum + x; n++;
//процедура
}
public float Mean(){
return(float)sum/n;
//функция(должна возвратить
//значение)
}
}
Прежде всего, отметим, что методы в языке программирования C# делятся на функции (которые обязаны возвращать значение) и процедуры (которые могут и не возвращать значения, на что указывает тип void). В данном примере Add – процедура, а Mean – функция, в которой возврат значения явно указывается оператором return. Доступ к методу, как и к полю, можно получить изнутри класса:
this.Add(3);
float x = Mean();
а также из других классов, с явным указанием полного имени:
C c = new C();
c.Add(3);
float x = c.Mean();
Заметим, что оператор this представляет собой указатель на текущий объект.
Продолжая аналогию между полями и методами как элементами классов, мы приходим к понятию статического метода. Рассмотрим особенности реализации статических методов в языке программирования C# на следующем примере:
class Rectangle {
static Color defaultColor;
public static void ResetColor() {
defaultColor = Color.white;
}
}
Как явствует из приведенного примера, под статическим методом понимается операция, определенная над статическими элементами классов (т.е. над статическими полями).
В данном примере описания класса Rectangle статическим является метод ResetColor (заметим, что он не возвращает значения, т.е. ResetColor – это статическая процедура).
По аналогии с предыдущими случаями, для доступа к статическому методу изнутри класса достаточно указать только краткое имя данного метода:
ResetColor();
В случае доступа из сторонних классов необходимо указать полное имя статического метода:
Rectangle.ResetColor();
Исследовав особенности описания и управления поведением основных элементов классов, объектов и методов для динамического и статического случаев, кратко остановимся на особенностях наследования свойств (полей и методов) классов объектов языка программирования C#. Для иллюстрации приведем следующий пример фрагмента программы на языке C#:
class Stack {
int[] values;
int top = 0;
public Stack(int size){
...
}
public void Push(int x){
...
}
public int Pop(){
...
}
}
В данной программе приведено (с сокращениями) описание класса, моделирующего стек (аналогичный стеку КАМ) посредством массива элементов values с вершиной top, функциями создания стека Stack размером size и «выталкивания» Push элемента x из стека, а также «вталкивания» Pop элемента в стек.
Аналогично объектам ссылочных типов, объекты классов (как принципиально динамические) хранятся в динамической области памяти (или так называемой «куче»). В силу ограничений безопасности программного кода любой объект языка программирования C# до использования необходимо инициализировать оператором new, например:
Stack s = new Stack(100);
Заметим, что наследование классами свойств других классов может быть как единичным, так и множественным. Последнее реализуется посредством множественных интерфейсов (что приводит к множественному наследованию типов).
Подводя итоги обсуждения основных понятий объектно-ориентированного подхода к программированию (классов, объектов и методов) применительно к языку программирования C#, кратко отметим достоинства и недостатки подхода.
К преимуществам объектно-ориентированного подхода следует отнести:

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

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

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика