Эволюция технологий и языков программирования

Рассмотрение исторических этапов развития технологий и языков программирования. Характеристика языков объектно-ориентированного программирования. Реализация основных объектов и концепций объектно-ориентированной технологии программирования на языке С++.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 25.05.2018
Размер файла 1,0 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Так в чем же принципиальная разница ?

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

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

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

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

Реализация массивов, структур, объединений и классов

Очень часто перед трейдером стоит задача сохранения массивов данных (список тикеров позиций, открытых этим экспертом, и т.д.) в глобальных переменных.

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

Функции для работы с такими массивами:

AddItem()

DeleteItem()

GetItem()

Count()

Search()

BSearch

Sort()

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

Предположим, что наш глобальный массив имеет имя, которое содержится в переменной global_array_name.

Тогда:

Количество элементов массива будет находится в глобальной переменнойglobal_array_name+"Count".

Глобальная переменная с именем global_array_name+"Lock" используется в качестве критической секции при вызове функций для работы с этим массивом.

Элементы массива будут находится в переменных global_array_name+"1",global_array_name+"2" и т.д.

Если в переменной global_array_name+"IsSorted" находится ненулевое значение, то массив отсортирован. В противном случае - неотсортированный.

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

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

Можно рассматривать проблему и с другой стороны. Попытайтесь разделить некую систему по признаку принадлежности ее элементов различным абстракциям данной проблемной области.

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

Encapsulation (сокрытие данных) - ключевое понятие при работе с объектами. Формально инкапсуляцией считается объединение данных и операций над ними в одном пакете и сокрытие данных от других объектов. Данные в объекте называются instance fields (поля экземпляра), а функции и процедуры, выполняющие операции над данными - methods (методы). Конкретный объект (экземпляр класса) имеет определенные значения полей. Множество этих значений называется текущим состоянием (state) объекта. Применение любого метода к некоторому объекту может изменить его состояние.

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

В определении класса на языке C++ и атрибуты, и методы называются членами этого класса; их определения могут следовать в тексте определения класса в произвольном порядке. Члены класса могут быть общедоступными (public), или приватными (private); вне класса определен доступ только к его общедоступным членам, а приватные члены доступны только методам своего класса. В рассматриваемом примере все атрибуты являются приватными, а все методы (кроме метода add_to_selections) - общедоступными, так что прочитать или изменить значение каждого атрибута можно только с помощью соответствующего метода; это рекомендуемая, хотя и не обязательная дисциплина программирования на языке C++ (определение всех атрибутов класса как приватных называется инкапсуляцией данных).

Реализация концепции полиморфизма

Формализуем понятие полиморфизма применительно к объектно-ориентированному подходу. Под полиморфизмом будем иметь в виду возможность оперирования объектами без однозначной идентификации их типов.

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

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

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

С точки зрения практической реализации концепции полиморфизма в языке программирования C# в форме полиморфных функций особое значение для исследования имеет механизм интерфейсов.

Напомним, что реализация полиморфизма при функциональном подходе к программированию основана на оперировании функциями переменного типа.

Для иллюстрации исследуем поведение встроенной SML-функции hd (от слова «head» - голова), которая выделяет «голову» (первый элемент) списка, вне зависимости от типа его элементов. Применим функцию к списку из целочисленных элементов:

hd [1, 2, 3];

val it = 1: int

Получим, что функция имеет тип функции из списка целочисленных величин в целое число:

int list -> int

В случае списка из значений истинности та же самая функция

hd [true, false, true, false];

val it = true: bool

возвращает значение истинности, т.е. имеет следующий тип:

bool list -> bool

Наконец, для случая списка кортежей из пар целых чисел

hd [(1,2)(3,4),(5,6)];

val it = (1,2) : int*int

получим тип

((int*int)list -> (int*int))

В итоге можно сделать вывод, что функция hd имеет тип

(type list) -> type

где type - произвольный тип, т.е. функция hd полиморфна.

Проиллюстрируем сходные черты и особенности реализации концепции полиморфизма при функциональном и объектно-ориентированном подходе к программированию следующим фрагментом программы на языке C#:

void Poly(object o) {

Console.WriteLine(o.ToString());

}

Как видно, приведенный пример представляет собой описание полиморфной функции Poly, которая выводит на устройство вывода (например, на экран) произвольный объект o, преобразованный к строковому формату (o.ToString()).

Рассмотрим ряд примеров применения функции Poly:

Poly(25);

Poly(“John Smith”);

Poly(3.141592536m);

Poly(new Point(12,45));

Заметим, что независимо от типа аргумента (в первом случае это целое число 25, во втором - символьная строка “John Smith”, в третьем - вещественное число =3.141592536, в четвертом - объект типа Point, т.е. точка на плоскости с координатами (12,45)) обработка происходит единообразно и, как и в случае с языком функционального программирования SML, функция генерирует корректный результат.

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

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

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

Еще одним значимым механизмом, сопряженным с полиморфизмом, является так называемое отложенное связывание (или, иначе, «ленивые» вычисления), в ходе которых значения присваиваются объектам (т.е. связываются с ними) по мере того как эти значения требуются во время выполнения программы.

При вычислении с вызовом по значению (call-by-value) все выражения должны быть означены до вычисления операции аппликации. Заметим, что формализация стратегии вычислений с вызовом по значению возникла в числе первых моделей computer science в виде абстрактной SECD-машины П.Лендина.

При вычислении с вызовом по имени (call-by-name) до вычисления операции аппликации необходима подстановка термов вместо всех вхождений формальных параметров до означивания. Стратегию вычислений с вызовом по значению иначе принято называть вызовом по ссылке (call-by-reference).

Наконец, при вычислении с вызовом по необходимости (call-by-need) ранее вычисленные значения аргументов сохраняются в памяти компьютера только в том случае, если необходимо их повторное использование. Именно эта стратегия лежит в основе «ленивых» (lazy), «отложенных» (delayed) или «замороженных» (frozen) вычислений, которые принципиально необходимы для обработки потенциально бесконечных структур данных.

Рассмотрим более подробно особенности стратегии вычислений с вызовом по значению (call-by-value, CBV).

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

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

Проиллюстрируем особенности использования стратегии вызова по значению следующим фрагментом программы на языке C#:

void Inc(int x) {

x = x + 1;

}

void f() {

int val = 3;

Inc(val);

// val == 3

}

Как видно из приведенного примера, фрагмент программы на языке C# реализует ввод значений val посредством функции f. Функция Inc является функцией следования (т.е. прибавления единицы для целых чисел).

Отметим, что, несмотря на применение функции Inc к аргументу val, значение переменной val, как явствует из комментария // val == 3,

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

Рассмотрим более подробно особенности стратегии вычислений с вызовом по имени, или, иначе, по ссылке (call-by-reference, CBR).

Прежде всего, в случае вызова по имени формальный параметр является подстановкой (alias)фактического параметра и не занимает отдельной области в памяти компьютера. При реализации данной стратегии вычислений вызывающей функции передается адрес фактического параметра.

Кроме того, фактический параметр в случае вызова по имени должен быть не выражением, а переменной. При этом формальный параметр является копией фактического.

Проиллюстрируем особенности использования стратегии вызова по имени следующим фрагментом программы на языке C#:

void Inc(ref int x) {

x = x + 1;

}

void f() {

int val = 3;

Inc(ref val);

// val == 4

}

Как видно из приведенного примера, фрагмент программы на языке C# реализует преобразование значений val посредством функции f. Функция Inc является функцией следования.

Отметим, что вследствие применения функции Inc к аргументу val, значение переменной val, как явствует из комментария // val == 4,

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

Рассмотрим более подробно особенности стратегии вычислений с вызовом по необходимости (call-by-need, CBN).

В целом, данная стратегия вычислений сходна с вызовом по имени (или ссылке, call-by-reference, CBR), однако ее реализация имеет две характерные особенности.

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

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

Проиллюстрируем особенности использования стратегии вызова по необходимости следующим фрагментом программы на языке C#:

void Read (out int first, out int next) {

first = Console.Read();

next = Console.Read();

}

void f() {

int first, next;

Read(out first, out next);

}

Как видно из приведенного примера, фрагмент программы на языке C# реализует ввод значений first иnext посредством функции Read со стандартного устройства ввода. Функция f может быть означена по необходимости, по мере поступления аргументов.

Исследовав особенности реализации различных стратегий вычислений в языке программирования C#, рассмотрим концепцию полиморфизма в соотнесении с механизмом так называемых абстрактных классов.

Абстрактные классы при объектно-ориентированном подходе (в частности, в языке программирования C#) являются аналогами полиморфных функций в языках функционального программирования (в частности, в языке SML) и используются для реализации концепции полиморфизма. Методы, которые реализуют абстрактные классы, также называются абстрактными и являются полиморфными.

Перечислим основные особенности, которыми обладают абстрактные классы и методы в рамках объектно-ориентированного подхода к программированию.

Прежде всего, отметим то обстоятельство, что абстрактные методы не имеют части реализации(implementation).

Кроме того, абстрактные методы неявно являются виртуальными (т.е. как бы оснащенными описателем virtual).

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

Наконец, в языке программирования C# запрещено создание объектов абстрактных классов (как конкретизаций или экземпляров).

Проиллюстрируем особенности использования абстрактных классов следующим фрагментом программы на языке C#:

abstract class Stream {

public abstract void

Write(char ch);

public void WriteString(string s)

{

foreach (char ch in s)

Write(s);

}

}

class File : Stream {

public override void Write(char ch)

{

...

write ch to disk

...

}

}

Как видно из приведенного примера, фрагмент программы на языке C# представляет собой описание абстрактных классов Stream и File, реализующих потоковую запись (метод Write) данных в форме символьных строк ch.

Заметим, что описание абстрактного класса Stream реализовано явно посредством зарезервированного слова abstract. Оператор foreach ... in реализует последовательную обработку элементов.

Необходимо обратить внимание на то обстоятельство, что поскольку в производных классах необходимо замещение методов, метод Write класса File оснащен описателем override.

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

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

Кроме того, важным практическим следствием реализации концепции полиморфизма для экономики программирования является снижение стоимости проектирования и реализации программного обеспечения.

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

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

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

Реализация концепций наследования

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

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

Теоретическая концепция наследования удовлетворительно моделируется посредством отношения(или, точнее, иерархии) частичного порядка. Существует целый ряд формализаций наследования, но наиболее адекватными и концептуально ясными являются графические модели. Среди них следует выделить уже упомянутые ранее подходы: фреймовую нотацию Руссопулоса и диаграммы Хассе.

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

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

Другой важной особенностью отношения частичного порядка является транзитивность. Суть транзитивности состоит в том, что если существует цепочка из (трех) объектов, связанных отношением частичного порядка, то первый и последний элементы этой цепочки можно связать тем же отношением. Это свойство гарантирует построение на множестве графа отношения частичного порядка в виде «решетки». Формальная запись свойства транзитивности для отношения частичного порядка выглядит следующим образом: a,b,c: a ISA b, b ISA c a ISA c.

Наконец, еще одним фундаментальным свойством отношения частичного порядка как модели наследования является анти симметричность. Это свойство разрешает наследование только в одном направлении (и запрещает его в противоположном). Формальная запись свойства анти симметричности для отношения частичного порядка выглядит следующим образом: a,b : a ISA b NOT (b ISA a).

По завершении исследования свойств отношения частичного порядка, перейдем к рассмотрению формализаций, моделирующих наследование. Проиллюстрируем графическую интерпретацию отношения частичного порядка на примере фреймовой нотации Руссопулоса. Рассмотрим следующий фрейм, который связывает отношением частичного порядка понятия «сущность» (THING), «юридическое лицо» (LEGAL.PERSON), «учреждение» (INSTITUTION), «работодатель» (EMPLOYER), «кадровое агентство» (RECRUITER), «физический объект» (PHYSICAL.OBJECT), «одушевленный объект» (ANIMATE.OBJECT), «человек» (PERSON), «мужчина» (MALE.PERSON) и «женщина» (FEMALE.PERSON).

Пример фрейма.

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

Другой продуктивной формализацией, моделирующей, в частности, наследование, является диаграмма Хассе. Проиллюстрируем использование диаграмм Хассе для графической интерпретации отношения между элементами класса или домена.

Пример диаграммы Хассе.

Диаграмма Хассе состоит из точек, которые представляют элементы множества (точнее, домена или класса), а также из соединяющих их линий, которые представляют собой отношения между элементами класса или домена (в данном случае интерпретируется отношение частичного порядка).

Данный пример иллюстрирует отношение IS IN («является подмножеством») между множествами {},{1}, {2}, {3}, {1,2}, {1,3}, {2,3} и {1,2,3}.

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

Исследовав основные свойства отношения наследования и способы его наглядной формализации, рассмотрим, каким образом эта теоретическая концепция реализуется в языках объектно-ориентированного программирования, и, в частности, в языке C#.

В простейшем случае язык программирования C# поддерживает единичное наследование. Проиллюстрируем реализацию механизма единичного наследования фрагментом программы на языке C#.

class A {

// базовый класс

int a;

public A() {...}

public void F() {...}

}

class B : A {

// подкласс (наследует свойства класса A,

// расширяет класс A)

int b;

public B() {...}

public void G() {...}

}

Применительно к языку программирования C# наследование есть отношение между классами. Данный пример содержит описание более общего (находящегося выше по ISA-иерархии) класса A и его подкласса - класса B. Заметим, что находящийся выше по ISA-иерархии класс принято называть базовым, а находящийся ниже - производным (или подклассом).

Подкласс B наследует свойства класса A, и, кроме того, возможно, расширяет его новыми (по сравнению с классом A) свойствами.

Приведенный фрагмент программы на языке C# иллюстрирует простейший случай наследования, а именно, единичное наследование.

Рассмотрим подробнее, каким образом производится реализация механизма наследования.

Производный класс B наследует свойство a и метод F() базового класса A. Кроме того, к свойствам производного класса B добавляется новое по сравнению с базовым классом A свойство b, а к методам- новый по сравнению с базовым классом A метод G().

Заметим, что операторы конкретизации элементов базовых классов (которые в языке C# называют конструкторами) не наследуются производными классами. Отметим также, что некоторые из наследуемых методов могут игнорироваться. В ходе единичного наследования производный подкласс может наследовать свойства единственного базового класса. Множественное наследование, демонстрирующее гибкость механизмов наследования в языке C#, реализуется на основе интерфейсов. Хотя производный класс в языке программирования C# может наследовать свойства базового класса, он не может наследовать свойств структуры. Реализация механизма наследования (в том числе множественного) для структур в языке программирования C# осуществляется (как и в случае с классами) посредством интерфейсов.

В случае неявного задания базового класса производный класс наследует свойства наиболее общего класса Microsoft .NET, известного как объект (object) и аналогичного концепту THING («сущность») в рассмотренном ранее примере фреймовой нотации.

Для иллюстрации множественного наследования приведем фрагмент программы на языке C#, содержащей описание интерфейса:

public interface IList :

ICollection, IEnumerable

{

int Add (object value);

// методы

bool Contains (object value);

bool IsReadOnly {

get;

}

// свойство

object this [int index]{

get;

set;

}

// индексатор

}

Из приведенного примера видно, что фрагмент программы на языке C# представляет собой описание общедоступного интерфейса IList, наследующего в иерархии элементы интерфейсов ICollection и IEnumerable, а также содержащего методы Add и Contains, свойство IsReadOnly и объект-индексатор.

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

Интерфейсом называется чисто абстрактный класс (с поддержкой полиморфизма), содержащий только описания без реализации.

Концепция множественного наследования предполагает возможность наследования одним концептом языка свойств сразу нескольких языковых концептов. При этом в языке программирования C# принципиально допустимо множественное наследование, но область действия его ограничена интерфейсами. Множественное наследование классов в языке программирования C# недопустимо, однако неявно реализуемо посредством интерфейсов. Так, классы и структуры языка программирования C# могут реализовывать множественные интерфейсы.

Интерфейсы могут содержать методы, свойства, индексаторы и события. Однако интерфейсы не могут содержать полей, констант, конструкторов, деструкторов, операторов, а также вложенных типов.

Элементы интерфейса неявно являются виртуальными (т.е. общедоступными и абстрактными) объектами и описываются в языке C# как public abstract (или virtual).

Интерфейсы, будучи принципиально полиморфными (т.е. динамически означиваемыми) объектами, не могут содержать статических элементов.

Наконец, свойства одного интерфейса могут быть расширены посредством другого интерфейса.

Рассмотрим более подробно важнейшие свойства интерфейсов как механизма реализации концепции и множественного наследования в языке программирования C#.

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

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

При этом произвольный элемент интерфейса, будь то метод, свойство или индексатор, должен непременно быть либо реализован непосредственно в базовом классе, либо унаследован от него.

Кроме того, заметим, что реализованные в языке программирования C# методы интерфейса могут быть описаны либо как виртуальные (virtual), либо как абстрактные (abstract). Таким образом, интерфейс может быть реализован посредством абстрактного класса. В то же время не допускается реализация замещенных интерфейсов по аналогии с замещенными в производных классах методами, которые описываются посредством ключевого слова override языка программирования C#.

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

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

Как видно из схемы, описывающей основные пространства имен Microsoft .NET Framework, организация их является вполне иерархической и реализует классическую схему единичного наследования.

Наиболее общим концептом иерархии является пространство имен System, характеризующее конфигурацию среды Microsoft .NET Framework и содержащее, в частности, параметры среды выполнения приложений, удаленной обработки данных, процессов, безопасности, ввода-вывода, системной конфигурации и др.

Среди подпространств пространства имен System можно выделить такие пространства имен, как System.Web, System.Windows.Forms, System.Data, System.Drawing и System.Xml, которые описывают такие характеристики среды Microsoft .NET Framework, как конфигурации веб-сервисов, формы ввода-вывода данных, форматы представления данных, графических подсистем и т.д.

Данная схема иллюстрирует перечень классов Common Type System среды проектирования и реализации программного обеспечения Microsoft .NET применительно к языку программирования C#.

Иерархия классов .NET Framework.

В частности, все многообразие типов можно разделить на предопределенные (заранее заданные системой программирования) и определенные пользователем (user defined) типы.

К последним относятся перечисления, массивы, классы, интерфейсы и делегаты (указатели на функцию).

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

Напомним, что все без исключения типы языков программирования SML и C# однозначно отображаются в систему типизации Microsoft .NET, верхним иерархическим элементом которой является пространство имен System.

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

Прежде всего, концепция наследования устраняет необходимость многократного явного указания свойств и методов для производных объектов. Одного взгляда на схему пространств имен Microsoft .NET Framework достаточно, чтобы понять значимость этого свойства. Заметим, что на схеме показана лишь часть верхних «этажей» многоуровневой иерархии Кроме того, следует отметить, что наследование открывает возможности для гибкого определения уровня абстракции предметной области. Можно оперировать единственным, достаточно абстрактным, концептом System (или THING, и, спускаясь по ISA-иерархии, обращаться к терминам все более конкретных концептов и сущностей (или, в терминологии языка программирования C#, классов и объектов).

Таким образом, концепция наследования предоставляет возможность моделирования сколь угодно сложной предметной области посредством ISA-иерархии концептов (или классов языка программирования C#), моделирующих объекты реального мира.

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

Заметим, что в языке программирования C# допустимо наследование свойств и методов как от единственного класса (единичное), так и от нескольких классов (множественное). Последний вид наследования реализуется посредством механизма интерфейсов.

Реализация концепций инкапсуляции

Формализуем понятие инкапсуляции в рамках объектно-ориентированного подхода к программированию.

В неформальной постановке вопроса под инкапсуляцией будем понимать доступность объекта исключительно посредством его свойств и методов.

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

Иначе говоря, свойствами объекта можно оперировать исключительно посредством его методов. Это замечание касается как свойств, явно определенных в описании объекта, так и свойств, унаследованных данным объектом от другого (других).

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

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

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

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

Рассмотрев определение понятия инкапсуляции (пока на интуитивном уровне), перейдем к описанию формализаций этой фундаментальной для объектно-ориентированного программирования концепции на основе уже известных нам формальных теорий computer science.

Оказывается, что понятие инкапсуляции вполне адекватно формализуется посредством таких теоретических формальных систем, как ламбда-исчисление А.Черча и комбинаторная логика Х.Карри.

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

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

Поясним более подробно реализацию механизма сокрытия информации посредством концепции инкапсуляции.

Рассмотрим в достаточно обобщенном виде схему взаимодействия объекта и данных.

Вначале представим схему такого рода для традиционного императивного языка программирования (например C и Pascal). При этом в нашем рассуждении под термином «объект» будем понимать произвольный объект языка программирования, безотносительно к концепции объектно-ориентированного программирования.

В этом случае объявления данных и процедуры обработки данных отделены друг от друга. Зачастую в ранних языках программирования описания языковых объектов и процедуры манипулирования ими выделены в особые разделы.

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

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

Прежде всего, определение (или описание свойств классов) и процедуры манипулирования этими свойствами (или методы) для каждого объекта языка программирования при объектно-ориентированном подходе хранятся совместно.

Кроме того, среда проектирования и реализации программного обеспечения (например, Microsoft Visual Studio .NET) не предоставляет иных возможностей доступа к объекту, кроме как посредством методов, изначально предназначенных для манипулирования данным объектом.

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

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

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

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

Применительно к языку программирования C# области видимости объектов подразделяются на следующие виды.

Общедоступные объекты описываются с помощью зарезервированного слова public и характеризуются доступностью из произвольного места программы, для которого определено пространство имен с описанием рассматриваемого объекта. При этом элементы интерфейсов и перечислений являются общедоступными (public) объектами по умолчанию.

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

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

Проиллюстрируем обсуждение использования модификаторов областей видимости объектов (public иprivate) следующим содержательным примером фрагмента программы на языке C#:

public class Stack{

private int[] val;

// private используется

// и по умолчанию

private int top;

// private используется

// и по умолчанию

public Stack(){

...

}

public void Push(int x){

...

}

public int Pop(){

...

}

}

Как видно из приведенного примера, фрагмент программы на языке C# содержит описание класса стека Stack, реализованного на основе массива целочисленных элементов (поле val). Голова стека представляет собой целочисленное значение (поле top). Над стеком определены операции инициализации (метод Stack), а также вставки (метод Push) и удаления (метод Pop) элемента.

Как явствует из примера, класс Stack и все манипулирующие его объектами методы (Stack, Push и Pop) являются общедоступными (public), тогда как поля являются доступными локально (private), т.е. только из описания данного класса.

Заметим, что в приведенном выше примере фрагмента программы с описанием областей видимости использовались только базовые возможности модификаторов видимости языка программирования C#.

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

Рассмотрим более подробно особенности основных типов расширенных областей видимости объектов в языке программирования C#.

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

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

Наконец, для описания доступности языкового объекта непосредственно из класса с описанием данного объекта, его производных классов, а также из сборки с описанием данного объекта используется зарезервированное слово protected internal.

Проиллюстрируем обсуждение использования модификаторов расширенных областей видимости объектов (protected и internal) следующим содержательным примером фрагмента программы на языке C#:

class Stack {

protected int[] values =

new int[32];

protected int top = -1;

public void Push(int x) {

...

}

public int Pop() {

...

}

}

class BetterStack : Stack {

public bool Contains(int x) {

foreach (int y in values)

if(x==y)

return true;

return false;

}

}

class Client {

Stack s = new Stack();

...

s.values[0];

...

// ошибка при компиляции!

}

Как видно из приведенного примера, фрагмент программы на языке C# содержит описание класса стека Stack (для хранения 32 целочисленных элементов и значением -1 в вершине), а также реализованного на его основе усовершенствованного класса стека BetterStack, дополнительно реализующего повторяющиеся элементы стека. В отличие от предыдущего примера, все поля класса стека Stack доступны как из данного класса, так и из классов, производных от него, поскольку описаны посредством ключевого слова protected.

После обсуждения использования (степеней) инкапсуляции применительно к классам в целом, рассмотрим особенности приложения данной концепции к таким фундаментальным объектам языка программирования C# как поля и константы.

Инициализация не является безусловно необходимой для полей в языке программирования C#. Тем не менее, доступ к полям и методам изначально запрещен (что соответствует использованию по умолчанию модификатора доступа private). В случае структуры поля инициализации не подлежат.

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

class C {

int value = 0;

}

В случае константы инициализация также не является необходимым требованием. Тем не менее, значение константы должно быть вычислимым в процессе компиляции.

Простейшей иллюстрацией описания константы в языке программирования C# является следующий пример, содержащий определение константы size, представляющей собой целочисленное значение двойной длины (long):

const long size = ((long)int.MaxValue+1)/4;

Заметим, что фрагмент

...(long) ...

в правой части присваивания представляет собой явное преобразование типов языковых объектов.

Особым случаем реализации концепции инкапсуляции в языке объектно-ориентированного программирования C# является механизм полей, предназначенных только для чтения. Для описания такого рода полей в языке C# используется зарезервированное слово readonly.

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

Проиллюстрируем основные свойства полей, предназначенных только для чтения, следующими примерами фрагментов программ на языке C#. Описание поля выглядит следующим образом: readonly DateTime date;

Доступ к полю изнутри класса организуется по краткому имени объекта:... value ... size ... date ...

Доступ к полю из других классов (на примере объекта c как конкретизации класса C) реализуется с указанием полного имени объекта:

c = new C();

... c.value ... c.size ... c.date ...

Рассмотрим подробнее особенности реализации механизмов доступа к статическим полям и константам в языке программирования C#.

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

Проиллюстрируем это высказывание следующим фрагментом программы на языке C#:

class Rectangle {

static Color defaultColor;

//однократно для класса

static readonly int scale;

//однократно для класса

//статические константы

//недопустимо использовать

int x, y, width,height;

//однократно для объекта

...

}

Как видно из приведенного примера, при описании класса Rectangle со статическими полями Color иscale и динамическими полями x, y, width и height, статическими являются поля, инвариантные по отношению к классу, а динамическими - представляющие собой «неподвижную точку» относительно объекта.

Доступ к статическим полям изнутри класса по краткому имени и из других классов по полному имени соответственно реализуется по аналогии с полями только для чтения:

... defaultColor ... scale ...

... Rectangle.defaultColor ...

Rectangle.scale ...

Продолжим иллюстрацию механизмов реализации концепции инкапсуляции в языке программирования C# следующим примером фрагмента программы:

class C {

int sum = 0, n = 0;

public void Add (int x){

// процедура

sum = sum + x; n++;

}

public float Mean() {

// функция

// (возвращает значение)

return (float)sum / n;

}

}

Приведенный пример представляет собой описание класса C, содержащего целочисленные поля sum иn, а также методы Add и Mean для суммирования и вычисления среднего значения, реализованные в форме процедуры и функции, соответственно.

Заметим, что методы Add и Mean класса C описаны как общедоступные и, следовательно, могут быть доступны из любого места программного проекта при указании полного имени, тогда как поля sum и n, в силу умолчаний, принятых в языке программирования C#, являются доступными локально (private).

Заметим попутно, что функция (в терминологии языка C#) отличается от процедуры тем, что обязательно возвращает значение. Для определения процедуры, не возвращающей значения, в C# используется зарезервированное слово void.

Проиллюстрируем сказанное об областях видимости объектов языка программирования C# фрагментами программ.

Предположим, что в предыдущем примере, описывающем общедоступный класс C, содержащий целочисленные поля sum и n, а также методы Add и Mean, необходимо организовать доступ к элементам класса изнутри, а также из других классов.

Очевидно, что в силу общедоступности реализации класса C такое задание принципиально осуществимо.

При реализации доступа к элементам класса C изнутри данного класса достаточно указать краткие имена объектов:

this.Add(3);

float x = Mean();

В то же время, при реализации механизма доступа к элементам класса C из других классов (внешних по отношению к данному) необходимо указывать полные имена объектов:

C c = new C();

c.Add(3);

float x = c.Mean();

Манипулирование статическими полями и методами в языке программирования C# осуществляется аналогично рассмотренным выше случаям статических полей и констант.

Например, в случае, если класс, содержащий статические элементы данных, определяется посредством следующего описания:

class Rectangle {

static Color defaultColor;

public static void ResetColor(){

defaultColor = Color.white;

}

}

доступ к элементам данных изнутри класса осуществляется посредством указания краткого имени объекта класса, например:

ResetColor();

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

Rectangle.ResetColor();

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

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

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

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

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

Глава 4. Безопасность жизнедеятельности

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

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

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

4.1 Характеристика условий труда программиста

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

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

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


Подобные документы

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

    курсовая работа [2,6 M], добавлен 17.11.2014

  • Понятие объектно-ориентированного программирования, характеристика используемых языков. Практическая разработка средств объектно-ориентированного программирования в задачах защиты информации: программная реализация на языке С++, а также Turbo Pascal.

    курсовая работа [275,9 K], добавлен 22.12.2011

  • Использование объектно-ориентированного программирования - хорошее решение при разработке крупных программных проектов. Объект и класс как основа объектно-ориентированного языка. Понятие объектно-ориентированных языков. Языки и программное окружение.

    контрольная работа [60,1 K], добавлен 17.01.2011

  • Развитие и классификация языков программирования. Методические рекомендации по изучению языков программирования. Основные понятия объектно-ориентированного программирования. Создание электронного учебного пособия с помощью языка гипертекстовой разметки.

    курсовая работа [331,1 K], добавлен 06.09.2011

  • Рассмотрение общих сведений и уровней языков программирования. Ознакомление с историей развития, использования языков программирования. Обзор достоинств и недостатков таких языков как Ассемблер, Паскаль, Си, Си++, Фортран, Кобол, Бейсик, SQL, HTML, Java.

    курсовая работа [759,5 K], добавлен 04.11.2014

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

    презентация [873,4 K], добавлен 23.01.2013

  • Обзор основных используемых языков программирования (С++, Java, Pascal). Анализ существующих методов шифрования паролей. Основные понятия объектно-ориентированного программирования. Реализация приложения для генерирования паролей на языке Object Pascal.

    курсовая работа [822,4 K], добавлен 07.07.2012

  • Основные этапы развития языков программирования. Характеристика машинно-ориентированной, проблемно-ориентированной и процедурно-ориентированной систем программирования. Ознакомление с системами программирования Delphi, Visual Basic и Visual C++.

    курсовая работа [102,4 K], добавлен 21.07.2012

  • Оценка современного этапа развития компьютерных технологий. История развития, классификации, сведения и уровни языков программирования. Обзор современных языков программирования: Си, его разовидности, Паскаль, Фортран, Бейсик - тенденция их развития.

    курсовая работа [46,5 K], добавлен 22.12.2010

  • Языки программирования низкого и высокого уровней и среды реализации. Особенности процедурных, логических, объектно-ориентированных языков. Состав системы программирования: трансляторы, библиотеки и отладчик программ, компоновщик, средства редактирования.

    презентация [11,9 K], добавлен 23.10.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.