17327

ПАРАДИГМИ ПРОГРАМУВАННЯ

Конспект

Информатика, кибернетика и программирование

ПАРАДИГМИ ПРОГРАМУВАННЯ Конспект лекцій 8.080401: Інформаційні управляючі системи та технології Освітньокваліфікаційний рівень – магістр ТЕМА 1. ПАРАДИГМА ІМПЕРАТИВНОГО ПРОГРАМУВАННЯ Лекція 1. Огляд парадигм програмування 1.1 Базові поняття і визначення Перш ...

Украинкский

2013-06-30

3.17 MB

79 чел.

ПАРАДИГМИ ПРОГРАМУВАННЯ

Конспект лекцій

8.080401: Інформаційні управляючі системи та технології

Освітньо-кваліфікаційний рівень – магістр

ТЕМА 1. ПАРАДИГМА ІМПЕРАТИВНОГО ПРОГРАМУВАННЯ

Лекція 1. Огляд парадигм програмування 

1.1 Базові поняття і визначення

Перш ніж почати вивчення парадигм, визначимо саме поняття «парадигма програмування».

В програмування цей термін ввів Роберт Флойд ще в 1987 році [1] в своїй лекції про виникнення і вплив на програмістів парадигм програмування, під парадигмою він розумів основну концептуальну ідею або комплекс ідей, які визначають характерні риси технологій програмування.

Інтернет-енциклопедія Вікіпедія дає таке визначення парадигми:

Парадигма (грец. paradeigma - приклад, зразок).

Паради́гма програмування — основні принципи програмування (не плутати з розробкою програм), або, парадигмне програмування.

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

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

Одні парадигми розвиваються незалежно, інші з'являються в результаті поєднання різних концептуальних ідей.

На сьогоднішній час існує велика кількість парадигм, серед яких можна виділити чотири парадигми, які відіграють основну роль у всіх напрямках і стилях сучасного програмування і називаються основними. Це – процедурна, функціональна, алгебраїчна і логічна. Вони відрізняються допустимими засобами представлення даних і алгоритмів у програмах, моделями обчислень, і в поєднанні з іншими ідеями, використовуються для утворення всієї множини парадигм.

Процедурне програмування часто використовують як синонім імперативного і навпаки.

Іноді до основної парадигми відносять також і паралельне програмування.

Розвиток парадигм пов'язаний з двома основними взаємозв'язаними причинами:

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

2. зростанням складності програм і систем, зростанням вимог до їхньої якості та надійності.

Таким чином - перша причина розвитку парадигм – неповнота мов програмування.

Друга причина – боротьба за ефективність обчислень і якість програм.

Окрім цих причин, є ще одна причина, яка стимулює появу нових парадигм – це обмежені ресурси, такі як: пам'ять, швидкість обчислень і продуктивність праці програмістів.

Обмеження оперативної пам'яті перших комп'ютерів стимулювало розвиток процедурної парадигми. Недостатня швидкість обчислень для вирішення складних обчислювальних задач призвела до появи паралельного програмування. Низька продуктивність праці програмістів і складність пошуку помилок у програмах сприяла розвитку мов програмування високого рівня і технологій програмування (структурного, об'єктно-орієнтованого, компонентного). Ця ж причина стимулювала і розвиток парадигми візуального програмування і проектування.

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

1.2 Класифікація парадигм програмування

Крім чотирьох основних парадигм таких як: процедурна, функціональна, алгебраїчна і логічна, які принципово відрізняються способами представлення даних і алгоритмів в програмах, існує багато похідних від них парадигм.

Перш ніж ми перейдемо до обговорення конкретних парадигм, розглянемо різні підходи до їхньої класифікації [2] (рис.1.1).

На самому вищому рівні виділяють:

  •  парадигми прикладного і теоретичного програмування;
  •  парадигми основні (Процедурна, Функціональна, Алгебраїчна і Логічна) і вищі, які базуються на основних (Паралельного, Об'єктно-орієнтованого, Агентного програмування);
  •   парадигми, які відрізняються способом декомпозиції задачі (Імперативного, Декларативного, Об'єктно-орієнтованого, Сценарного програмування);
  •  парадигми, які відрізняються глибиною і спільністю опрацьовування технічних деталей організації процесів комп'ютерної обробки інформації (Машинно-орієнтоване, Системне, Логічне, Трансформаційне, Високопродуктивне /паралельне програмування) тощо.

Стислі визначення парадигм, які ще не повністю сформувалися:

Узагальнене програмування (generic) – парадигма програмування, яка полягає в написанні алгоритмів, які можна застосовувати до різних типів даних.

В C++ - базується на понятті шаблону (template).

В Javaконтейнери, 

С#- узагальнення (generic, обобщения).

Метапрограмування (meta-programming) створення програм, які породжують інші програми як результат своєї роботи. Інша назва парадигми – програмування за шаблоном (шаблони проектування). 

Реалізації – препроцесор С та шаблони C++ , мова R# - на платформі  .Net.

Рис. 1.1. Парадигми і стилі програмування


Парадигми

Возможность

Язык

Ada

C

C++

C#

D

Eiffel

Erlang

Prolog

F#

Groovy

Java

JavaScript

Haskell

Common Lisp

Nemerle

Perl

PHP

Python

Ruby

Scala

Smalltalk

Tcl

VB.NET

Delphi

OCaml

PureBasic

Императивный

+

+

+

+

+

+

-

-

+

+

+

+

+
[1]

+

+

+

+

+

+

+

+

+

+

+

+

+

Объектно-ориентированный

+

-

+

+

+

+

-
[2]

-

+

+

+

+
[4]

-
[5]

+

+

+

+

+

+

+

+

+

+

+

+

-/+

Функциональный

-

-

-/+

+/-

+/-

+/-

+

+

+

+

-

+

+

+

+

+

+/-

+/-

+

+

+

+

+/-

-/+

+

+/-

Рефлексивный

-

-

-

-/+

-

 ?

+

+

-/+

-/+

-/+

+

-

+

-/+

+/-

+

+

+

-/+

+

+

-/+

-/+

-

 ?

Обобщенное программирование

+

-

+

+

+

+/-

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

-

+

+

+

-/+

Логический

-

-

-

-

-

-

-

+

-

-

-

-

+/-
[6]

+/-
[7]

+/-

-

-

-

-

 ?

+/-

-

-

-

-

 ?

Декларативный

-

-

-

-/+ [8]

-/+

 ?

+

+

+

+

-

-

+

+ [9]

+

-/+
[10]

+

+

+

+

+/-

-

+/-

-

+

+/-

Распределенный

+
[11]

+/-
[12]

+/-
[12]

-/+
[13]

-

+

+

+

-

-/+

+

-

+
[14]

+/-

-

-

-

-/+

-/+

 ?

+/-

 ?

-

-

-

-

Ada

C

C++

C#

D

Eiffel

Erlang

Prolog

F#

Groovy

Java

JavaScript

Haskell

Common Lisp

Nemerle

Perl

PHP

Python

Ruby

Scala

Smalltalk

Tcl

VB.NET

Delphi

OCaml

PureBasic

Объектно-ориентированные возможности

Возможность

Язык

Ada

 C 

C++

C#

 D 

Eiffel

Erlang

F#

Groovy

Java

JavaScript

Haskell

Common Lisp

Nemerle

Perl

PHP

Python

Ruby

Scala

Smalltalk

VB.NET

Delphi

OCaml

PureBasic

Интерфейсы

 ?

-

+/-

+

+

 ?

x

+

 ?

+

 ?

x

x [128]

+

+/- [129]

+

+

 ?

 ?

 ?

+

+

+

x

Мультиметоды

-

-

-

-/+ [130]

-

-

x

-

 ?

-
[131]

-

x

+

-

-
[131] [132]

-

-
[131]

-
[131]

-

-

-

-

-

x

Mixins

 ?

-

-

-

+

 ?

x

 ?

 ?

-

 ?

x

+

 ?

 ?

 ?

 ?

+

+

+

 ?

+ [133]

 ?

x

Переименование членов при наследовании

 ?

x

-

-

 ?

+

x

-

-

-

 ?

x

-

-

-/+

-

-

 ?

 ?

-

-

-

 ?

x

Множественное наследование

 ?

x

+

-

-

+

x

-

-

-

 ?

x

+

-

+

-

+

 ?

 ?

-

-

-

+

x

Решение конфликта имен при множественном наследовании

 ?

x

-/+
[134]

x

x

+
[135]

x

x

 ?

x

 ?

x

+[136]

x

+

x

+

 ?

 ?

x

x

x

 ?

x

Функциональные возможности


1.3 Огляд парадигми імперативного програмування

Процедурна парадигма відноситься до парадигми імперативного програмування, в яку входять і інші.

Що таке Імперативне програмування?

Імперативне програмування (наказове) засновано на машині Тюрінга - абстрактному обчислювальному пристрої, що виконує послідовність інструкцій (команд) програми, яка, таким чином, переходить з одного стану в інший. Існує поняття «поточного кроку виконання» і «поточного стану», який змінюється з часом.

Оскільки практично всі сучасні комп'ютери орієнтовані на послідовні обчислення, імперативне програмування явно виграє в ефективності реалізації прикладних задач, для яких важлива швидкість виконання.

В імперативних мовах програма це послідовність виконуваних операторів. Якщо розглядати стан комп'ютера як стан елементів пам'яті, то імперативна мова – це послідовність операторів, що змінюють значення однієї або декількох змінних.

Машинно-орієнтоване програмування характеризується апаратним підходом до організації роботи комп'ютера, націленим на доступ до будь-яких можливостей устаткування. В центрі уваги - конфігурація устаткування, стан пам'яті, команди, передачі управління, черговість подій, виключення, час реакції пристроїв і успішність реагування. Основна мова програмування – асемблер.

Системне програмування довгий час розвивалося під пресом сервісних і замовних робіт. Властивий таким роботам виробничий підхід спирається на перевагу виробничих процесів і стабільних програм, що розробляються для багаторазового використання. Для таких програм виправдана схема компіляції обробки, статичний аналіз властивостей, автоматизована оптимізація і контроль. У цій області домінує імперативно-процедурний стиль програмування, що є безпосереднім узагальненням операторного стилю прикладного програмування. Він допускає деяку стандартизацію і модульне програмування, але обростає досить складними побудовами, специфікаціями, методами тестування, засобами інтеграції програм і тому подібне.  

Неструктурне програмування Самий ранній стиль програмування і повна відсутність технології.

Весь код програми представлено єдиним безперервним блоком. Переходи до потрібних секцій програми виконуються за допомогою умовних операторів і операторів переходу (звичайно, goto або jump).

Приклади мов: перші мови скриптів, Fortran, Basic, Асемблери.

Проблеми забезпечення якості: утворення «спагетті-коду», складність перевірки і тестування коду.

Процедурне програмування

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

У процедурному програмуванні визначаються механізми передачі даних між процедурами (за значенням чи за посиланням), область дії змінних (локальні, глобальні), а також моделі пам'яті: статична і динамічна.

Приклади мов програмування: всі імперативні мови 2-го і 3-го поколінь підтримують цю парадигму. C/С++, Кобол, Паскаль тощо.

При цьому виключається дублювання коду, поліпшується супровід програми.

Недоліки. При компіляції формується єдиний виконуваний файл, часто великий, тобто зв'язки між процедурами статичні.

Модульне програмування.

Модульне програмування з'явилося, як розвиток процедурного програмування і пов'язане із зростанням об'єму і складності програм. Виникла потреба в розділенні програм на частини, які:

- можна окремо розробляти (різними людьми);

- можна окремо зберігати і компілювати.

При модульному програмуванні виконується окрема компіляція модулів, збирання і формування виконуваного модуля роблять редактори зв'язків і компонувальники. До механізму раннього звязування (статичного) додається механізм пізнього звязування (динамічний виклик модулів).

Усередині модулів організація коду може бути як при процедурному програмуванні. Встановлено чіткі механізми введення-виведення даних – через аргументи (на вході) і результати (на виході) процедури; визначено сферу дії змінних. Забезпечується можливість автономної реалізації і зберігання коду (в бібліотеках модулів), а також збирання програм з модулів.

При модульному програмуванні полегшується тестування і повторне використання коду; допускається розподілена розробка програм (розробка автономних модулів окремими програмістами), а також розподілене виконання. 

Модульний принцип покладено в основу практично всіх стилів програмування, особливо об'єктно-орієнтованого і компонентного. Він також пов'язаний з підходом до проектування «зверху-вниз» і структурним програмуванням.

Збіркове програмування. Базується на збиранні програми з готових  модулів, які розміщуються в бібліотеках.   

Модулі можуть зберігатися як у бінарному вигляді, так і початковому. Забезпечується багаторазове використання модулів. Ідея збіркового програмування отримала розвиток у парадигмі компонентного програмування. На відміну від компонентного – збіркове програмування не потребує компонентної моделі (каркасу).

Структурне програмування 

Структурне програмування — це технологія створення програм, що дозволяє шляхом дотримання певних правил скоротити час розробки і зменшити кількість помилок, а також полегшити можливість модифікації програми.

Теоретично доведено (незалежно Дейкстрой і Глушковим В.М.), що будь-який алгоритм можна реалізувати лише з трьох структур, які називаються базовими конструкціями структурного програмування: це послідовність, розгалуження і цикл.

Послідовністю називається конструкція, що реалізовує послідовне виконання двох або більше операторів (простих або складних).

Розгалуження задає виконання того чи іншого оператора залежно від виконання якої-небудь умови. Реалізується за допомогою операторів if та switch.

Цикл реалізує багатократне виконання операторів. Реалізується за допомогою операторів циклу.


Рис. 1.2. Базові конструкції структурного програмування

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

Метою використання базових конструкцій є спрощення структури програми. Таку програму легко читати, відлагоджувати і, при необхідності, вносити до неї зміни. У більшості мов високого рівня існує декілька реалізацій базових конструкцій;

у С# їм відповідає чотири види циклів (while, do, for, foreach) і два види розгалужень (if та switch).

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

Розробка програм виконується зверху-вниз.

Обмеження - скорочення (або заборона) використання оператора goto; одна точка входу в секцію (блок), але декілька можливих точок виходу. Структурне програмування часто асоціюється з розробкою «зверху-вниз».

При структурному програмуванні текст програми трохи подовжується, але значно поліпшується її зрозумілість.

Парадигма структурного програмування домінувала у 70-і 80-і роки минулого сторіччя до появи об'єктно-орієнтованої парадигми.

Структурний підхід до проектування застосовується в ORACLE, SSADM і ін. та добре підходить для ієрархічних систем.

Приклади мов: у всі сучасні мови імперативного програмування введені елементи і обмеження структуризації, наприклад, Pascal, Ada, Fortran, Cobol, Basic.

У C# ідеї структурного програмування використовуються на найнижчому рівні — при написанні методів класів.

Приклади конструкцій структурного програмування на мові C#

Послідовність:

static void Main(string[] args)

       {

           Console.WriteLine("Введите x- угол в радианах");

           double x = double.Parse(Console.ReadLine());

           Console.WriteLine("Введите показатель степени n");

           int n = int.Parse(Console.ReadLine());

         //вызов метода вычисления sin(x) через ряд

           double my_sinus = Calc_sin(x,n);

           //вызов метода из класса Math

           double sinus = Math.Sin(x);

           double delta = sinus - my_sinus;

           Console.WriteLine("my_sinus= {0},sin={1},delta={2}", my_sinus, sinus, delta);

           Console.ReadKey();

       }

Розгалуження

if (!IsNumeric(s1))

               {

                  throw new Exception("Перший член виразу - не число");

                   

               }

switch (op)

               {

                   case ("+"):

                       result = digit1 + digit2;

                       break;

                   case ("-"):

                       result = digit1 - digit2;

                       break;

                   case ("/"):

                       result = digit1 / digit2;

                       break;

                   case ("*"):

                       result = digit1 * digit2;

                       break;

                   default:

                       throw new Exception("Невідома операція");

                       

               }//switch

Цикл

for (int i = 0; i < n; i++)

           {

            result=result+(Math.Pow((-1),i)*Math.Pow(x,(2*i+1)))/F(2*i+1);

           }

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

1.4 Програмування, кероване подіями

Перш ніж перейти до розгляду парадигми об'єктно-орієнтованого програмування, розглянемо стисло основні принципи програмування, керованого подіями, яке тісно з ним зв'язано.

Як ми з'ясували, стилі програмування, засновані на імперативній парадигмі, ґрунтуються на послідовній організації «внутрішнього» потоку управління виконанням інструкцій програми, не пов'язаного з настанням подій поза нею. Проте існує багато задач, вирішуваних в реальному часі, а також задач, вирішуваних в інтерактивному режимі, які очікують, приймають і оброблюють команди і набори даних. Для ефективної реалізації таких задач використовуються стилі програмування, засновані на концепції організації циклу обробки зовнішніх подій (повідомлень).

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

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

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

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

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

Будь-який сучасний інтерфейс користувача побудований на основі обробки подій (onClick, onMouseMove, onMouseOver і т.д.).

Приклад (C#)

public partial class Form1 : Form

   {

       public Form1()

       {

           InitializeComponent();

       }

       private void button1_Click(object sender, EventArgs e)

       {

          double x = double.Parse(txt_x.Text);

          int n = int.Parse(txt_n.Text);

          //вызов метода вычисления sin(x) из библиотеки

          double my_sinus = MySin.MySin.Sin(x, n);

          //вызов метода из класса Math

          double sinus = Math.Sin(x);

          txt_y1.Text = my_sinus.ToString();

          txt_y2.Text = sinus.ToString();

       }

       private void button2_Click(object sender, EventArgs e)

       {

           this.Close();

       }

   }

В цьому фрагменті є два методи обробки подій: button1_Click і button2_Click, які викликаються при натисненні програмних кнопкок.

Базовим поняттям програмування керованого подіями, що відрізняє його від імперативного є поняття процесу.

Процес - це абстракція достатньо високого рівня. В якій обчислювальній моделі працює кожний окремий процес - не принципово. Важливо, що вони можуть працювати паралельно, і можуть обмінюватися між собою результатами своїх обчислень через "канали зв'язку".

Семантично взаємодію паралельних процесів краще всього представляти як роботу мережі деяких пристроїв, зєднаних "каналами" передачі даних.

Кожний обчислювач виробляє типові для його обчислювальної моделі операції (наприклад, імперативний обчислювач буде переходити із стану в стан). Коли процес зустрічає інструкцію "Прийняти значення (з каналу)", він входить у стан очікування, поки канал порожній. Як тільки в каналі з'являється значення, процес його прочитує і продовжує роботу.

Поширеним є також і таке розуміння паралелізму: в системі паралельних процесів кожний окремий процес оброблює події. Ці події можуть бути як спільними для всієї системи, так і окремими для одного або декількох процесів. В таких термінах достатньо зручно описувати, наприклад, елементи графічного інтерфейсу користувача, або моделювання яких-небудь реальних процесів - оскільки поняття події є для таких задач природнім.

В програмуванні керованому подіями окремі процеси максимально автономні, єдиний спосіб спілкування між ними - обмін повідомленнями.

Програмування кероване подіями – найбільш поширена сучасна парадигма прикладного програмування, підтримувана операційними системами (ОС) і реалізована в мовах програмування (С++, Visual Basic, C#) та інших.

До стилю програмування, керованого подіями, відносять і паралельне програмування. Ця парадигма, звичайно, потребує окремого вивчення і відповідної техніки. Ми лише стисло оглянемо основні положення цієї теми.

1.5 Узгоджене програмування і паралельні обчислення

Природний резерв підвищення продуктивності комп'ютерів –розпаралелювання потоку команд або потоку даних. Розпаралелювання даних передбачає застосування однієї операції відразу до кількох елементів масиву даних, а паралелізм задач — розбиття обчислювального процесу на декілька процесів, кожний з яких виконується на своєму процесорі.

Досить швидко були розроблені супер-ЕОМ, які мали «векторну» або «матричну» архітектуру процесорів (трансп'ютери), автономних, але здатних обмінюватися між собою результатами своїх обчислень через канали зв'язку.

Хорошим наближенням до такої архітектури є мережі комп'ютерів з можливістю розподілених обчислень. Окрім цього, практично всі сучасні мікропроцесори максимально використовують у своїй архітектурі можливості паралельного виконання окремих операцій. Таким чином, паралелізм можна розбити на два рівні: паралелізм рівня мікрооперацій і паралелізм рівня процесів - простих (послати, прийняти значення або процеси обчислювальної моделі) або структурних (послідовних або паралельних). Коли процес виконує інструкцію «Прийняти значення (з каналу)», він входить у стан очікування, поки канал порожній. Як тільки в каналі з'являється значення, процес його прочитує і продовжує роботу. В системі паралельних процесів кожний окремий процес обробляє події.

Можна виділити такі основні види паралелізму:

- паралелізм багатопроцесорних систем;

- паралелізм операцій введення-виведення;

- паралелізм взаємодії з користувачем;

- паралелізм розподілених систем.

Перший з них є справжнім паралелізмом, тому що у багатопроцесорних системах інструкції виконують декілька процесорів одночасно. Інші види паралелізму можуть виникати і в однопроцесорних системах тоді, коли для продовження виконання програмного коду необхідні певні зовнішні дії (переривання).

Активне впровадження нової апаратної архітектури потребувало зміни парадигми програмування - переходу від послідовного програмування до узгодженого програмування (concurrent programming), зокрема, паралельного програмування (parallel programming або паралельних обчислень - parallel computing), пов'язаного з паралельними процесами, породженням і обробкою асинхронних подій і ін.

Узгоджене (паралельне) програмування - це програмування в термінах взаємодії деяких одночасно працюючих обчислювачів (декількох процесорів або багатоядерного процесора).

При розробці паралельних програм використовуються спеціалізовані мови, як, наприклад, мова високого рівня Occam, а також сучасні бібліотеки і системи паралельного програмування PVM, LAM, CHMP і ін.

Три основні підходи до реалізації цих систем розрізняються методами взаємодії паралельних задач.

Перший підхід базується на концепції обміну повідомленнями,

Другий — на використанні розділення пам'яті,

Третій спирається на стандарт POSIX і об'єднує обидва підходи.

Найбільш відомою реалізацією першого підходу є специфікація MPI (Message Passing Interface) для мов С і Fortran, а другого підходу - специфікація OpenMP для Fortran, С, C++. OpenMP — це набір спеціальних директив компілятору (pragma), а також бібліотечних функцій і змінних середовища. Компілятор, що підтримує OpenMP, перетворює початковий код програми - вставляє відповідні виклики функцій для паралельного виконання фрагментів коду, виділених за допомогою спеціальних директив компілятору. Підтримка специфікації OpenMP є у всіх компіляторах Intel, починаючи з шостої версії, в Microsoft С і C++, починаючи з Visual Studio 2005. В третьому підході використовується специфікація POSIX (Portable Operating System interface for unIX), введена як міжнародний стандарт ISO/IEC 9945-1:1990. В рамках POSIX можна реалізувати паралельні обчислення на основі обміну повідомленнями (аналогічно MPI), або розділення пам'яті (як в OpenMP). В POSIX допустима і будь-яка комбінація цих методів.

Можливості розподілених і паралельних обчислень є в мовах Java, C#.

На сьогодні головними елементами програм провідних компаній–розробників мікропроцесорів стали багатоядерні процесори.

Наприклад, корпорація Intel розробляє відразу 17 багатоядерних процесорів і в найближчому майбутньому зможе поставляти їх для всіх сімейств своєї продукції на різних платформах, включаючи клієнтські, серверні і комунікаційні системи. До складу багатоядерного серверного процесора входять два або більше ядра на кожний фізичний процесор, що дозволяє серверним платформам одночасно обробляти більше завдань, програмних потоків або застосувань. Очікується, що ці можливості відкриють нову еру зростання продуктивності і гнучкості серверів [3].

Двоядерні процесори Intel – лише перший крок на цьому шляху. Перший двоядерний процесор Intel для настільних ПК був випущений в квітні 2005 року; зараз корпорація Intel вже працює над багатоядерною архітектурою, яка, дозволить об'єднати десятки і навіть сотні процесорних ядер на одному кристалі. Розробляються також плани створення спеціалізованих ядер, які забезпечать оптимальну продуктивність для найважливіших задач майбутнього, таких як аналіз інформації в базі даних і вдосконалена обробка зображень і природної мови.

Сьогодні вважається, що багатоядерні процесори – цей єдиний перспективний напрям для подальшого розвитку комп'ютерної індустрії.

Провідний експерт корпорації Microsoft Херб Саттер в статті «Програмне забезпечення і революція узгодження» (ACM QUEUE, September 2005) називає те, що відбувається революцією за масштабами суттєво більш могутньою, ніж поширення об'єктно-орієнтованого програмування на початку 90-х років. Тоді причиною змін стало ускладнення програмних систем, нинішня ж революційна ситуація викликана необхідністю виконувати програми на багатоядерних процесорах».

1.6. Підтримка різних парадигм програмування в MS.Net

процедурне, структурне – методи класів усіх мов C++,C#,VB

модульне – DLL, модулі класів

ООПкласи C#, власні класи

кероване подіями – обробники подій (модель Windows)

паралельне - .Net Framework 4.0, MC#

візуальне VisualStudio

метапрограмування (за шаблоном) – VisualStudio (шаблони проектів)

узагальнене програмування – узагальнені класи C# (generic)

компонентне – основа платформи .Net Framework

сценарне - .Net Framework 3.5 (підтримка JavaScript та AJAX)

сервісно-орієнтоване – Web-сервіси, WCF

функціональне програмування – C# (делегати, LINQ, лямбда-вирази)



WPF (Windows Presentation Foundation) – технологія для створення презентацій: складних графічних інтерфейсів з можливостями анімації, 2D і 3D графіки.  Використовується векторна графіка для 2D, тому інтерфейси будуть максимально незалежні від роздільної здатності екрану і розміру вікна.

WCF (Windows Communication Foundation) - створення сервіс-орієнтованих систем і звичайних розподілених систем.

Windows CardSpaceнова метасистема ідентифікації від Microsoft. (замість .NetPassport).

Windows Workflow Foundation (WF) – технологія для визначення, виконання і управління робочими процесами (англ. workflow).

ADO.NET Entity Framework (EF) - об'єктно-орієнтована технологія доступу до даних. Надає можливість взаємодії з об'єктами як за допомогою LINQ у вигляді LINQ to Entities, так і з використанням Entity SQL.

Parallel LINQ (PLINQ) – паралельне виконання запитів LINQ 

Task Parallel Library (TPL) – розпаралелювання задач

Висновки

1. Загальні парадигми програмування, що склалися на самому початку ери комп'ютерного програмування, - парадигми прикладного, теоретичного і функціонального програмування мають найбільш стійкий характер.

2. Прикладне програмування підпорядковане проблемній спрямованості, що відображає комп'ютеризацію інформаційних і обчислювальних процесів чисельної обробки, досліджених задовго до появи ЕОМ. Саме тут швидко виявився явний практичний результат.

3. Домінуючі парадигми прикладного програмування за роками розвитку:

60-і роки 20 ст. – процедурне програмування;

70-і 80-і роки 20 ст – структурне програмування;

90-і роки 20 ст – об'єктно-орієнтоване програмування;

кінець 90-х – початок 21 ст. – компонентне програмування;

10-і – 20-і роки – функціональне?

3. Сучасні мови програмування підтримують одночасно декілька парадигм, тобто є мультипарадигменними.

4. Парадигми програмування склалися у міру зростання складності вирішуваних завдань. Відбулося розшарування засобів і методів програмування залежно від глибини і спільності опрацювання технічних деталей організації процесів комп'ютерної обробки інформації.

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

Запитання

1. Що означає поняття “парадигма програмування”?

2. Які парадигми відносяться до основних?

3. Які основні причини, обумовлюють появу нових парадигм?

4. В чому різниця між передачею параметра за значенням та за посиланням?

5. Чим відрізняється підпрограма від функції?

6. Яку концепцію, покладено в основу парадигми процедурного програмування?

7. Які мови програмування підтримують процедурну парадигму? 

8. Які основні риси модульного підходу?

9. До якої основної парадигми відноситься структурне програмування?

10. Що таке “область дії змінної” ?

11. Що таке “модуль” і чим він відрізняється від процедури чи методу?

12. У чому суть структурного підходу?

13. Які основні ознаки визначають парадигму паралельного програмування?

14. Які основні ознаки визначають парадигму програмування, орієнтовану на обробку подій?

15. Що таке “розподілені обчислення”?

16. Що таке події, оброблювачі подій і як вони пов’язані між собою?

17. Які основні підходи використовуються для організації паралельних обчислень?


Тема 2. парадигма ОБЄКТНО-ОРІЄНТОВАНОГО програмування

Лекція 2. Об'єктно-орієнтоване програмування та його реалізація в C# на платформі MS.NET

2.1 Основні принципи об’єктно-орієнтованого програмування

Об'єктно-орієнтоване програмування (ООП) є результатом еволюції модульного програмування і програмування, керованого подіями. Воно зявилося в 90-х роках 20-го століття як реакція на зростання складності програмного забезпечення (ПЗ) і визначило розвиток технології і мов програмування на наступні роки. Ця парадигма разом з компонентною зараз є найбільш популярною серед розробників програмних систем.

У 80-і роки минулого століття стало зрозуміло, що надії на те, що структурне програмування (і проектування) зможе суттєво покращити якість програм і продуктивність праці програмістів не виправдалися.

Якщо на початку ери комп'ютеризації вартість апаратних засобів (hardware) значно перевищувала вартість програмних засобів (ПЗ) (software), то згодом ситуація змінилася. Витрати на розробку і супровід ПЗ зростали, а вартість розробки апаратних засобів - знижувалася.

Об'єктно-орієнтований підхід базується на «старому» фундаменті процедурної парадигми і успадковує такі її кращі риси, як модульність і абстракція типів даних.

Основна новизна цієї парадигми в тому, що в ній поєднані структури даних і функції обробки цих даних.

Отже, повторимо основні концепції ООП.

Визначення. Об'єктно-орієнтоване програмування (ООП) – парадигма, заснована на представленні предметної області у вигляді системи взаємозв'язаних абстрактних об'єктів і їх реалізацій.

Зараз в парадигмі об'єктно-орієнтованого програмування домінують два стилі – програмування, базоване на класах (class-based programming) і програмування, базоване на прототипах (prototype-based programming) – відносно новий напрям ООП.

Програмування, базоване на класах. На відміну від процедурного програмування, в якому дані і функції їх обробки не зв'язані, в ООП визначена нова структура даних - клас - абстрактний тип, в якому окрім даних містяться функції їх обробки (методи).

Розглянемо основні поняття ООП: об'єкт, клас, властивість і метод.

Кожний об'єкт в ООП має свій тип (клас).

Клас представляє собою абстрактний тип даних, який має:

Поля – атрибути об'єкту.

Властивості - параметри об'єкту (значення його атрибутів).

Методи - дії, які можна виконувати над об'єктом цього типу, або які сам об'єкт може виконувати (процедури та функції).

Події - повідомлення, які посилає об'єкт (або посилаються об'єкту) при зміні стану.

Кожний об'єкт є екземпляром деякого класу об'єктів. Один клас відрізняється від інших іменем і, звичайно, набором інтерфейсів. Інтерфейси, у свою чергу, - це набір повідомлень, які можна посилати об'єкту. Реалізуються інтерфейси у вигляді відкритих (public) методів класу.

В основі об'єктно-орієнтованого програмування лежать 4 основні принципи:

Абстракція - опис взаємодії виключно в термінах повідомлень/подій в предметній області. Об'єкти надають не повну інформацію про реальні властивості предметної області. Їх моделі адекватні вирішуваній задачі, працювати з ними зручніше, ніж з низькорівневим описом усіх можливих властивостей і реакцій об'єкту.

Інкапсуляція - здатність приховування реалізації (властивостей і методів усередині класу), тобто можливість доступу до об'єкту і маніпулювання ним виключно за допомогою властивостей (get, set) і методів класу.

До основних властивостей інкапсуляції відносяться наступні:

  1.  сумісне зберігання даних і функцій (тобто властивостей і методів) усередині класу;
  2.  приховування внутрішньої інформації від користувача (що забезпечує більшу безпеку програмі) – за допомогою специфікаторів доступу private, internal;
  3.  ізоляція користувача від деталей реалізації (що забезпечує незалежність від моделі обчислень і потенційно дружній інтерфейс програми).

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

У мовах програмування поняття наслідування означає застосовність всіх або деяких властивостей та/або методів базового класу для всіх класів, похідних від нього. Крім того, збереження властивостей і/або методів базового класу повинне забезпечуватися і для всіх конкретизацій (тобто конкретних об'єктів) будь-якого похідного класу.

Поліморфізм – це концепція, що дозволяє мати різні реалізації для одного і того ж методу, які будуть вибиратися залежно від типу об'єкту, переданого до методу при його виклику.

В об'єктно-орієнтованому програмуванні під поліморфізмом розуміється можливість оперувати об'єктами, не володіючи точним знанням їх типів.

Питання: Які приклади поліморфізму можна навести?

Відповідь: в С++, C# перевантаження функцій – одне і те саме ім'я функції може використовуватися для передачі повідомлень об'єктам різних класів. Такі функції повинні мати різні списки параметрів.

Отже -

Класи, наслідування і поліморфізм - фундаментальні властивості, яким повинні задовольняти мови програмування, щоб підтримувати об'єктно-орієнтовану парадигму програмування.

Для реалізації цих властивостей різні мови програмування використовують різні підходи.

2.2 Чисто об'єктно-орієнтовані і гібридні мови програмування

Розрізняють чисті і гібридні об'єктно-орієнтовані мови програмування. Чисті — це ті, які дозволяють використовувати тільки одну модель програмування — об'єктно-орієнтовану. Ви можете оголошувати класи і методи, але не можете визначити глобальні змінні і звичайні функції або процедури.

Прикладами “чистих” мов ООП сьогодні є Java, C#.

C++, Object Pascal і VB, VBA - гібридні мови, які дозволяють використовувати, при необхідності, процедурний підхід.

Корисним результатом наслідування стала велика кількість повторно-використовуваних об'єктів, зібраних у бібліотеки класів. Такі бібліотеки включають практично весь програмний інтерфейс операційної системи і дозволяють задіяти при програмуванні засоби більш високого рівня, ніж просто виклики функцій. Базові конструкції і класи можуть багатократно використовуватися при створенні нової програми. При цьому скорочується час розробки програм. Як приклад подібної системи можна навести бібліотеку Microsoft Foundation Class (MFC) для компілятора MS Visual C++.

Подібні реалізації є і в інших компіляторах. Далі детальніше розглянемо реалізацію об’єктно-ораєнтованої парадигми у мові C# та платформі MS.NET.

2.3. Реалізація принципів ООП в мові C#

Мова C# є чисто об'єктною мовою програмування. Це означає, що всі визначення змінних і процедур (методів) повинні знаходитися в тілі класу.

Для того, щоб можна було створювати програми в C#  клас грає  дві різні ролі: модуля і типу даних.

1. Клас – це модуль, архітектурна одиниця побудови програмної системи. Модульність побудови – основна властивість програмних систем. У ООП програмна система, що будується за модульним принципом, складається з класів, що є основним видом модуля. Модуль може не бути змістовною одиницею, його розмір і вміст визначається архітектурними міркуваннями, а не семантичними.

У мові C# дозволяється оголосити клас, який не розглядається як тип даних, і в якого зберігається єдина роль – роль модуля. Такий клас оголошується з модифікатором static. В такому класі можуть бути задані константи, лише статичні поля і лише статичні методи. У нього немає конструкторів в звичайному сенсі цього слова, що дозволяють створювати об'єкти – екземпляри класу.

Статичний клас не може розглядатися як тип даних.

Приклад – клас Program консольної програми зі статичним методом main.

Приклад Генерація масиву чисел і його сортування

class Program

{        // генератор даних

       static void ValsGenerator(int[] Vals)

       {

           // Random - клас для генерації випадкових чисел

           Random aRand = new Random();

           // заповнення масиву

           for (int i = 0; i < Vals.Length; i++)

               Vals[i] = aRand.Next(100);

       }

       static void Main(string[] args)

       {

         const int N = 10;

         int[] Data = new int[N];

         ValsGenerator(Data);

         Array.Sort(Data);

         Console.WriteLine("Друк відсортованих даних");

         for (int i = 0; i < Data.Length; i++)

         Console.WriteLine("Data[" + i + "] = " + Data[i]);

         Console.ReadLine();

       }

}

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

Модульність побудови – основний засіб боротьби із складністю системи.

2. Друга роль класу. Клас – це тип даних, який задає реалізацію деякої абстракції даних, характерної для проблемної області, для  якої створюється програмна система.

Склад класу як типу даних визначається не архітектурними міркуваннями, а тією абстракцією даних, яку повинен реалізувати клас. Якщо ви створюєте клас Account, що реалізовує таку абстракцію, як банківський рахунок, то в цей клас не можна додати поля з класу Car, задаючого автомобіль. З іншого боку в цьому класі мають бути всі поля і всі методи, необхідні клієнтам класу, що оперують з банківськими рахунками.

В С# оголошення класів вводяться ключовим словом class.

Клас є основою для створення об'єктів. В класі визначаються дані і код, який працює з цими даними.

Методи і змінні, що складають клас, називаються членами класу. При визначенні класу оголошуються змінні, які він містить і код, який працює з цими змінними. Безпосередньо ініціалізація змінних в об'єкті (змінних екземпляра) виконується в конструкторі.

Об'єкти є екземплярами класу. Це динамічні об'єкти, вони створюються при виконанні програми в області видимості і знищуються після виходу з неї.

Формально клас описується таким чином:

Синтаксис опису класу:

тип доступу class им’я_класу {

тип_доступу тип им’я змінної1;

тип_доступу тип им’я змінної2;

тип_доступу тип_результату

им’я _методу1(список_параметрів) {тіло_методу}

}

де тип_доступу визначає область видимості класу. Для класів визначено такі модифікатори доступу:

public - клас доступний для інших компонент;

internal  - клас видимий в середині цього компонента (збірки).

Для членів класу (даних і методів) визначені такі модифікатори доступу:

рublic - члени класу доступні за межами даного класу;

internal - члени класу доступні в межах однієї збірки;

рrotected - члени класу доступні усередині даного класу;

private - члени класу доступні тільки для інших членів даного класу.

За замовчанням застосовується модифікатор internal.

Членами класу можуть бути:

• Константи (const)

• Поля (field)

• Конструктори (у тому числі без параметрів)

• Деструктори

• Методи

• Властивості (property)

• Індексатори (властивості з параметрами)

• Події (event)

• Вкладені типи.

Звернення до поля класу виконується за допомогою операції доступу (крапка). Праворуч від крапки задається ім'я поля, зліва — ім'я екземпляра для звичайних полів або ім'я класу для статичних. Створення об’єкту класу  виконується оператором new.

Синтаксис оператора new:

Ім’я класу  об’єкт = new Ім’я класу();   

Приклад. Визначається простий клас Demo і два способи звернення до його полів.

using System;

namespace ConsoleApplication1

{

   class Demo

   {

       public int a = 1;                                       // поле даних

       public const double  c = 1.66;                // константа

       public static string s = "Demo";             // статичне поле класу

       double y;                                                 // закрите поле даних

   }

   class Class1

   {   static void Main()

       {

           Demo x = new Demo();                  // створення екземпляра класу Demo

           Console.WriteLine( x.a );               // x.a - звернення до поля класу

           Console.WriteLine( Demo.c );       // Demo.c - звернення до константи

           Console.WriteLine( Demo.s );       // звернення до статичного поля

       }

   }

}

Питання

1. Які основні принципи об’єктно-орієнтованої парадигми?

2. У чому полягає сутність механізму абстракції даних?

3. Які парадигми підтримуються у С++?

4. Які концепції покладено в основу об’єктно-орієнтованої парадигми?

5. Назвіть основні відміни обєктно-орієнтованого програмуванні від структурного.

6. Що таке обєкт у обєктно-орієнтованому програмуванні і як він використовується?

7. Що таке “властивість” об’єкта?

8. Що таке “наслідування”. Навести приклад

9. Що таке “поліморфізм” і стосовно якої парадигми він використовується?

10. Що таке “інкапсуляція” і до якої парадигми належить це поняття?

11. Яка особливість реалізації принципів ООП в C# порівняно з C++?

12. Які дві ролі класу в C#?


Тема 3. Програмування за прототипом і сценарне програмування 

Лекція 3. Програмування за прототипом і сценарне програмування

3.1 Програмування за прототипом

В цьому стилі програмування поняття класу відсутнє, а повторне використання (наслідування) виконується клонуванням існуючого екземпляра об'єкту - прототипу.

На відміну від стилю ООП, базованого на класах і концентруючого увагу розробника на ієрархії класів і на зв’язках між ними, стиль прототипного програмування загострює увагу на поведінці невеликої кількості «зразків», які далі використовуються як «базові» об'єкти для створення інших об'єктів.

Створення нового об'єкту виконується одним з двох методів: шляхом клонування існуючого об'єкту, або шляхом створення об'єкту «з нуля». Для створення об'єкту з нуля надаються синтаксичні засоби додавання властивостей і методів в об'єкт. Потім, для побудованого об'єкту може бути отримана повна копія, клон. В процесі клонування копія успадковує всі характеристики свого прототипу, але з цієї миті стає самостійною і може бути змінена. В деяких реалізаціях копії зберігають посилання на об'єкти-прототипи, делегуючи їм частину своєї функціональності; при цьому зміна прототипу може торкнутися всіх його копій. В інших реалізаціях нові об'єкти знаходять повну незалежність від своїх прототипів: прототип копіюється один-в-один, з усіма методами і атрибутами, і копії привласнюється нове ім'я (посилання). Перевага даного підходу полягає в тому, що творець копії може її міняти, не побоюючись побічних ефектів серед інших нащадків свого предка. Крім того, істотно знижуються обчислювальні витрати на диспетчеризацію, оскільки немає необхідності обходити весь ланцюжок можливих делегатів у пошуках відповідного методу або атрибута. В числі недоліків підходу - труднощі з розповсюдженням змін в системі: модифікація прототипу не спричиняє за собою негайну і автоматичну зміну всіх його нащадків. Канонічним прикладом прототипної мови є мова Self. Прототипний стиль програмування покладено також в основу JavaScript.

3.2 Сценарне програмування

Сценарні мови (або мови скриптів (scripting languages)) мають достатньо тривалу історію розвитку. Концепція сценарного програмування з'явилася як розвиток мови LISP (парадигми функціонального програмування). До перших сценарних мов відносять вбудовані засоби управління командної оболонки операційною системою. Командний файл на мові операційної системи, представляє собою управляючий сценарій, який виконує задану послідовність дій ( *.bat-файл ).

За останні роки, завдяки розвитку web-технологій, сценарні мови програмування, зробили величезний крок уперед. Сценарні мови використовуються для створення динамічних інтерактивних web-сторінок, зміст яких модифікується залежно від дій користувача і стану решти сторінок і даних.

Характерною рисою сценарних мов є формування програми на деякій зовнішній мові як результату виконання сценарію (наприклад, PHP). Сценарна мова мало спирається на створення кінцевого продукту з нуля і більшою мірою – на використання тих можливостей, які має операційна система, графічне середовище, прикладна сервісна машина та інші подібні компоненти, взаємодія яких здійснюється за допомогою сценаріїв.

Сценарна парадигма припускає розбиття задачі на окремі частини, кожна з яких розв'язується спеціалізованими програмними засобами, а сценарій виступає в ролі «диспетчера», відповідального за організацію їхньої взаємодії.

Сценарні мови для web-розробки створені в 90-і роки XX століття і включають елементи різних парадигм програмування від імперативної до об'єктно-орієнтованої. Серед найбільш популярних сценарних систем можна відзначити: Perl, PHP, ASP, VBScript, JavaScript, Pyton. Синтаксис і семантика різних сценарних мов схожі. Це обумовлено значним впливом мов С і С++ на програмістів.

Крім Web-застосунків сценарні мови використовуються для настройки і розширення різних прикладних програмних продуктів (наприклад, OPIMA-Workflow), для запису сценаріїв тестування в інструментальних засобах тестування тощо.

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

Питання

1. Які мови сценаріїв вам відомі?

2. У чому відміна сценарної парадигми програмування від імперативної?

3. Які основні ознаки сценарної парадигми програмування та основні мови?


ТЕМА 4. ПАРАДИГМА КОМПОНЕНТНОГО ПРОГРАМУВАННЯ

Лекція 4. Компонентне програмування як розвиток об’єктного

4.1 Основні ідеї компонентної розробки

Парадигма ООП і пов'язана з нею концепція «повторного використання» (reuse) стимулювали розвиток компонентного програмування)

Компонентна розробка (CBSE, від Component based software engineering або CBD, від Component-based development) – сучасний напрям в програмній інженерії, в основі якого лежить індустріальний підхід до створення програмних систем - «не з нуля», а шляхом швидкої збірки з готових програмних компонентів.

Головна задача CBSE – ґрунтуючись на знанні властивостей окремих компонентів, що інтегруються, гарантувати передбачуваність властивостей системи. CBSE узагальнює ідеї об'єктно-орієнтованої парадигми, повторного використання, абстрактної архітектури, формальних специфікацій і базується на концепціях компоненту (component), інтерфейсу (interface), контракту (contract), компонентної моделі (component model), компонентного каркасу (component framework), композиції (composition) і сертифікації (certification).

Схематично опис моделі компонентної системи подано на рис. 4.1 і стисло прокоментовано далі.

Компонент (1) – це програмна реалізація (виконуваний код) функцій об'єкту, призначена для виконання. Разом з функціональністю компонент реалізує один або декілька інтерфейсів (2) відповідно до певних зобов'язань, описаних у контракті (3). Контрактні зобов'язання гарантують, що незалежно розроблені компоненти можуть взаємодіяти один з одним і розгортатися в стандартних середовищах (4) (на етапі побудови системи або на етапі її виконання).

Компонентна програмна система ґрунтується на невеликій кількості компонентів різних типів (5), кожний з яких має спеціалізовану роль в системі і описується інтерфейсом (2). Компонентна модель (6) утворена множиною типів компонентів, їх інтерфейсів, а також специфікацією допустимих шаблонів (паттернів) взаємодії типів компонентів. Компонентний каркас (7) забезпечує множину сервісів (8) для підтримки функціонування компонентної моделі. У багатьох відношеннях компонентні каркаси подібні спеціалізованим операційним системам, хоча вони оперують на більш високих рівнях абстракції і мають більш обмежений діапазон механізмів координації взаємодії компонентів.

Рис. 4.1. Загальна модель компонентної системи

Компонентний підхід дає такі переваги при розробці ПС:

- незалежні розширення ПС завдяки тому, що елементом (одиницею) розширення є компонент, а компонентна модель і каркас гарантують, що розширення не стануть причиною не передбачуваної поведінки ПС;

- створення ринкових компонентів завдяки тому, що компонентні моделі встановлюють стандарти, яким повинні задовольняти компоненти для незалежної розробки і розгортання в стандартному середовищі;

- економія часу виходу на ринок ПС завдяки тому, що ключові архітектурні рішення можуть бути «вбудовані» в компонентну модель і каркас;

- забезпечення якості ПС завдяки тому, що компонентні моделі і каркаси можуть проектуватися з урахуванням пріоритетних атрибутів якості для певної області застосування. Компонентні моделі визначають правила проектування, які обов'язкові для всіх компонентів, які використовуються в компонентній системі. По суті, різні «глобальні» властивості системи (наприклад, масштабованість, безпека і т.п.) вбудовуються безпосередньо в компонентну модель. Якщо компонентна модель накладає обмеження на компоненти, то компонентний каркас реалізує ці обмеження разом з наданням необхідних сервісів.

Найбільш важливий аспект CBSE – передбачуваність композиції взаємодіючих компонентів і каркасів. Можливі три основні види композицій в ПС:

– «компонент-компонент» (взаємодія по контрактах прикладного рівня, яка визначається під час розробки (раннє зв’язування) або під час виконання (пізнє зв’язування);

– «каркас-компонент» (взаємодія між компонентом і іншими компонентами каркаса по контрактах системного рівня із забезпеченням управління ресурсами);

  •  «каркас-каркас» (взаємодія між компонентами, які розгортаються в гетерогенних середовищах (каркасах) по контрактах інтероперабельного (interoperation) рівня).

Компонент виступає в двох ролях – як реалізація (що розробляється, розгортається і інтегрується в систему) і як архітектурна абстракція (що визначає правила проектування, встановлені стандартною моделлю для всіх компонентів).

Компоненти розробляються у вигляді деякої програмної абстракції, що включає:

інформаційну частину - опис призначення, дати виготовлення, умов застосування (ОС, платформа тощо) та можливостей повторного використання;

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

– інтероперабільність – здатність взаємодіяти з компонентами інших середовищ;

– переносимість (мобільність) – здатність працювати на різних платформах;

– інтегрованість – здатність до об'єднання з іншими компонентами в складі ПС;

– не функціональні характеристики - безпека, надійність і захист компоненту і даних;

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

Специфікація інтерфейсу може виконуватися засобами API (Application Programming Interface) мови програмування або на мові специфікації інтерфейсу (не залежному від мови програмування) - Interface Definition Language (IDL).

Сучасні мови програмування, наприклад, Java, мають розширення, спеціально призначені для специфікації поведінки: iContract, JML (Java Modeling Language), Jass (Java with assertions), Biscotti, and JINSLA (Java INterface Specification LAnguage). Можуть використовуватися також методи (мови) VDM (VDM++), Z (OOZE, Object-Z). Всі вони забезпечують опис послідовності виконання операцій безвідносно до часу. Для опису синхронізації операцій в розподілених і паралельних системах можуть використовуватися, наприклад, Object Calculus, CSP (Communicating Sequential Processes), Piccola, а для специфікації не функціональних атрибутів - NoFun.

В CBSE зроблено перехід від концепції специфікації власне компонентів, до концепції специфікації схем (шаблонів) їхньої взаємодії шляхом визначення контрактів – з одного боку, зобов'язань компоненту (шаблонів взаємодії, забезпечуваних компонентом), а з іншого боку, правил взаємодії (абстрактних шаблонів взаємодії відповідно до ролі в системі, яка покладається на компонент).

Таким чином, компонентні системи ґрунтуються на чітко визначених стандартах і угодах для розробників компонентів (встановлених у компонентній моделі) та інфраструктурі компонентів (компонентному каркасі), яка реалізує сервіси для моделі, спрощуючи розгортання окремих компонентів і застосувань.

Компонентна модель пропонує:

- стандарти по типах компонентів (наприклад, проекти, форми, COBRA-компоненти, RMI-компоненти, стандартні класи-оболонки, бази даних, JSP-компоненти, сервлети, XML-документи, DTD-документи і т.п., які визначені у відповідних мовах програмування);

- стандарти схем взаємодії (методи локалізації, протоколи комунікації, необхідні атрибути якості взаємодії – безпека, управління транзакціями тощо);

- угоди про зв’язування компонентів з ресурсами (сервісами, що надаються каркасом або іншим компонентом, розгорненим у цьому каркасі). Модель описує, які ресурси доступні компонентам, як і коли компоненти зв'язуються з цими ресурсами. Каркас, у свою чергу, розглядає компоненти як ресурси, що підлягають управлінню.

Найбільш відомі компонентні моделі - COM (Component Object Model) (DCOM – розподілена компонентна модель, COM+), CORBA, Java Beans, .Net Framework.

1. Component Object Model (COM) – початковий стандарт Microsoft для компонентів. Визначає протокол для конкретизації і використання компонент усередині процесу, між процесами або між комп'ютерами. Основа для ActiveX, OLE і багатьох інших технологій. Може використосуватися в Visual Basic, C++ і ін.

2. Java Beans – стандарт Sun Microsystems для компонентів (тільки для Java)

3. CORBA (стандарт OMG, має громіздкий IDL-інтерфейс, складність відображення однієї мови реалізації в іншу).

Компонентний каркас (подібно операційній системі, об'єкти дії якої - компоненти) керує ресурсами, розподіленими компонентами, і надає механізми для організації взаємодії компонентів. Каркас необов'язково існує окремо від компонентів під час роботи системи, його реалізація може бути об'єднана з реалізацією компоненту, хоча переважно перше, як, наприклад, каркас для підтримки компонентної моделі EJB (Enterprise JavaBeans).

Тривалість успіху компонентної інженерії буде обумовлена доступністю високоякісних програмних компонентів і довірою споживачів до якості компонентів, які вони купують, що, у свою чергу, може бути забезпечено шляхом сертифікації компонентів. Сертифікації підлягають окремі компоненти, каркаси і сама компонентна система. Проте існує залежність властивостей системи від властивостей компонентів, що сертифікуються, і, чим більше ця залежність, тим більш значущими будуть результати сертифікації компонентів. При 100% упевненості взагалі відпаде необхідність сертифікувати систему. Вона буде «правильною» за визначенням (принаймні, в контексті певних властивостей, по яких встановлена залежність). У відсутності 100% упевненості проблема сертифікації системи переходить в площину прогнозів і обґрунтовувань композицій компонентів в умовах існуючої невизначеності.

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

З погляду програмування парадигма компонентного програмування – це спроба вирішити ті проблеми, які виникають при використанні об'єктно-орієнтованої парадигми. Це, наприклад, організація повторного використання шляхом розповсюдження бібліотек класів (початкового коду) або бібліотек динамічної компоновки (dll-бібліотек), проблема розробки розподілених застосувань і ін.

Основна ідея компонентної парадигми - розповсюдження класів в бінарному вигляді (тобто не у вигляді початкового коду) і надання доступу до методів класу через чітко визначені інтерфейси, що дозволяє зняти проблему несумісності компіляторів і забезпечує зміну версій класів без перекомпіляції компонентів.

4.2 Компонентна об'єктна модель COM (Component Object Model). 

Як приклад компонентної моделі, яка реалізована у Windows, розглянемо модель COM (Component Object Model).

Компонент - це сховище (у вигляді DLL або EXE файла) для одного або декількох класів. Все, що знає програма-клієнт про клас, це його унікальний ідентифікатор і один або декілька інтерфейсів, що забезпечують доступ до реалізованих даним класом методів. Допускається реалізація компоненту і програми-клієнта на різних мовах (Visual C++, Visual Basic). В реєстрі системи зберігається інформація про місцеположення компоненту, що містить даний клас. Це дозволяє системі прозоро для клієнта перенаправляти виклики методів до потрібного компоненту і повертати результати.

Таким чином, забезпечується виконання двох важливих принципів компонентного програмування:

- незалежність від мови програмування

- прозорість місцеположення серверу для клієнта.

Визначення. Модель СОМ (Component Object Model) або її ще називають Модель багатокомпонентних об'єктів – це програмна модель, яка визначає набір правил, за якими повинні будуватися компоненти. Тільки при дотриманні цих правил компоненти забезпечують коректне і надійне функціонування.

Модель СОМ складається з набору стандартних функцій і специфікацій (стандартів обміну, стандартів виклику функцій), які забезпечують розробку програм.

Правила визначають стандартний внутрішній інтерфейс між об'єктами і методику взаємодії об'єктів, а саме – виклик функцій і обмін даними між об'єктами.

Кожний інтерфейс, який підтримується об'єктом є контрактом між цим об'єктом і його клієнтами. Вони зобов'язуються: об'єкт — підтримувати методи інтерфейсу в точній відповідності з визначеннями останнього, а клієнт — коректно викликати методи. Щоб контракт був працездатним, об'єкт і його клієнти повинні домовитися про спосіб явної ідентифікації кожного інтерфейсу, про загальний спосіб специфікації методів інтерфейсу, а також про конкретну реалізацію інтерфейсу.

Модель СОМ побудована за принципом «клієнт-сервер».

Клієнтом є програма, яка викликає функції компоненту або використовує його дані (компонентна система).

Кожний об'єкт СОМ реалізований усередині деякого серверу, що містить код, який реалізує методи інтерфейсів об'єкту, а також контролює дані об'єкту, поки той активний. Один сервер може підтримувати (і часто підтримує) більше одного об'єкту деякого класу і навіть підтримувати декілька класів.

Сервери об'єктів СОМ. Розглянемо три основні типи серверів:

1. Сервер "в процесі" (in-рrocess): об'єкти реалізуються в бібліотеці, що динамічно підключається, і, таким чином, виконуються в тому ж процесі, що і клієнт.

2. Локальний сервер (out-рrocess): об'єкти реалізовані в окремому процесі, що виконується на тому самому комп'ютері, що і клієнт.

3. Віддалений сервер: об'єкти реалізовані в DLL або в окремому процесі, які розташовані на віддаленому по відношенню до клієнта комп'ютері.

Можливість створення віддалених серверів підтримує Розподілена модель СОМ (DCOM).

Важливість і універсальність моделі СОМ полягає в тому, що з погляду клієнта, об'єкти, реалізовані в будь-якому з трьох видів серверів, виглядають однаково; доступ до методів об'єктів клієнт як і раніше здійснює за допомогою інтерфейсів.

4.3. Технологія ActiveX – основні можливості 

Модель COM використовується як фундамент технологій компонентного програмування, які раніше називалися DDE, OLE Automation, ActiveX.

В даний час технологія ActiveX (технологія активних об'єктів) об’єднує декілька технологій, які базуються на моделі СОМ. Основне призначення ActiveX – забезпечення простої взаємодії компонентів в компонентній системі. Ця технологія зараз швидко розвивається у напрямі розширення типів об'єктів, які нею підтримуються і послуг, що надаються.

Основні технології, що входять зараз до ActiveX:

  1.  OLE (Object Linking and Embeding) – технологія зв’язування і вставки об'єктів одного застосування в інше;
  2.  Automation – технологія управління вставленими об'єктами і об'єктами інших застосувань;
  3.  ADO (ActiveX Data Object) – технологія універсального доступу до різних джерел даних;
  4.  елементи управління ActiveX – технологія створення елементів управління ActiveX (власних компонентів);
  5.  документи ActiveX - технологія створення документів, працюючих в InternetExplorer, і перетворення документів у стандарт документів ActiveX;
  6.  Active Server Pages – технологія створення і виконання сценаріїв на web-серверах.
  7.  Remote Automation – технологія віддаленого управління і ряд інших.  

Питання

1. У чому сутність компонентної парадигми?

2. Які основні ознаки визначають парадигму компонентного програмування? 

3. Що таке “компонент” і чим він відрізняється від класу?

4. Що таке “інтерфейс” компонента і як він використовується у компонентній системі (програмі)?

5. Які основні типи композицій використовуються у компонентній моделі?

6. З чого складається внутрішня частина компонента?

7. З чого складається інформаційна частина компонента?

8. З чого складається зовнішня частина компонента?

9. У якому вигляді використовуються компоненти (у вигляді початкового (исходного)), як exe-файли чи як dll-бібліотеки?

10. Які основні компоненті моделі використовуються у Windows?

11. Які основні складові утворюють структуру компонента?

12. Які основні типи композицій використовуються у компонентній моделі?

13. Які правила визначає модель COM?

14. З чого складається модель COM?

15. Які основні типи серверів моделі COM? 


Лекція 5. Компонентне програмування в .NET 

5.1 Основні концепції платформи MS.NET 

Платформа MS.NET – це підхід до проектування і реалізації програмного забезпечення, в основі якого лежать такі основні концепції:

1) ідеологія проектування і реалізації програмного забезпечення;

2) модель ефективної підтримки життєвого циклу прикладних систем;

3) уніфікована, інтегрована технологічна платформа для програмування;

4) сучасний, зручний та безпечний інструментарій для створення, розміщення і підтримки програмного забезпечення.

Як модель обчислень  .NET реалізує:

1. Компонентний підхід як розвиток об'єктно-орієнтованого.

2. Універсальну систему типізації (уніфікацію даних і метаданих).

3. Строго ієрархічну організацію коду, просторів імен і класів.

4. Універсальний інтерфейс .NET Framework (включаючи підтримку різних мов і парадигм програмування).

5. Високу варіативність екземплярів реалізації (зокрема, на основі веб-сервісів).

Підсистема MS.NET Framework є ядром платформи MS.Net, яке забезпечує можливість побудови і виконання MS.Net застосувань.

До складу MS.NET Framework входить: загальномовне середовище виконання (Common Language Runtime або CLR) і бібліотека класів підсистеми MS.NET Framework.

Бібліотека класів FCL (Framework Class Library) – це статична складова платформи.

Загальномовне середовище виконання CLR – динамічна складова.

Для динамічного компоненту CLR фізичною одиницею, яка об'єднує класи і інші ресурси, є збірка (assembly).

5.1.1 Структура FCL

За функціональним призначенням у складі FCL можна виділити:

- набір базових класів, що забезпечують, наприклад, роботу з рядками, введення-виведення даних, багатопоточність і т.п.;

- набір класів для роботи з даними, що надають можливість використовування SQL-запитів, ADO.Net і обробки XML даних;

- набір класів Windows Forms, що дозволяють створювати звичайні Windows-застосування, в яких використовуються стандартні елементи управління Windows;

- набір класів Web Forms, що забезпечують можливість швидкої розробки Web-застосувань, в яких використовується стандартний графічний інтерфейс користувача;

- набір класів Web Services, що підтримують створення розподілених компонентів-сервісів, доступ до яких може бути організований через Інтернет.

Описи просторів імен по аналогії з описами типів даних розміщуються у файлах. Простори імен можуть об'єднувати різні збірки, а також бути вкладеними один в одний. Крім того, файли з описами можуть містити декілька просторів імен. Важливо відзначити, що між просторами імен і файлами не існує однозначної відповідності.

Допускається імпорт просторів імен з використанням зарезервованого слова using мови програмування C#.  

Простір імен визначає область видимості об'єктів (змінних, класів, даних).

Основним простором імен бібліотек FCL є простір System, що містить як класи, так і інші вкладені простори імен. Наприклад, простір System.Windows.Forms містить класи, які використовуються при створенні Windows-застосувань. Клас Form з цього простору задає форму - вікно, на якому розміщуються елементами управління.

В таблиці перелічено ієрархію основних просторів імен та їх призначення

System

Головний простір

System.Data

Класи для роботи з базами даних

System.Data.Common

System.Data.OleDb

System.Data.SqlClient

System.Collections

Класи для роботи с контейнерами

System.Diagnostics

Класи для трасування и відлагодження коду

System.Drawing

Класи графіки

System.Drawing.Drawing2D

System.Drawing.Printing

System.IO

Підтримка введення/виведення

System.Net

Підтримка передачі даних по мережах

System.Reflection

Робота з типами даних, визначеним користувачем, під час виконання програми

System.Reflection.Emit

System.Runtime.InteropServices

Підтримка взаємодії зі "звичайним кодом" (некерованим) – DLL, COM-сервери, віддалений доступ

System.Runtime.Remoting

System.Security

Криптографія, прівілеї

System.Threading

Робота с потоками

System.Web

Робота с web-застосунками

5.1.2 Загально мовне середовище виконання – CLR – динамічна складова MS.NET Framework

Базовий рівень підсистеми MS.NET Framework складає загальномовне середовище виконання (Common Language Runtime або CLR). В Windows XP його код міститься в mscorlib.dll. Це головна бібліотека .NET CLR. 

Середовище виконання CLR реалізує управління пам'яттю, типами даних, міжмовною взаємодією, розгортанням (deployment) застосувань.

Середовище CLR активізує виконуваний код, виконує для нього перевірку безпеки, розташовує цей код в пам'яті і виконує його. Важливою частиною роботи середовища CLR є управління пам'яттю, а саме автоматичне  вивільнення пам'яті, що звільняється при роботі програм (збірка сміття).

Для забезпечення можливості багатомовної розробки програмний код, після компіляції на одній з алгоритмічних мов платформи MS.Net, представляється на спеціально розробленій спільній проміжній мові (Common Intermediate Language або CIL). Ця мова, з одного боку, достатньо близька до машинно-залежних мов – асемблерів, з іншого боку, CIL забезпечує вищий рівень представлення різних комп'ютерних платформ. Як результат, програма на мові CIL залишається платформо-незалежною, проте вимагає деякої додаткової настройки (компіляції) перед початком свого виконання.

В ході компіляції програма на .NET-сумісній мові програмування трансформується відповідно до наперед заданої узагальненої специфікації типів Common Type System (CTS). Система типів CTS повністю описує всі типи даних, які підтримуються середовищем виконання, визначає їх взаємозв'язки і зберігає їх відображення в систему типів .NET.

Програмні файли на мові CIL, одержувані після компіляції програм на алгоритмічних мовах платформи MS.Net, називаються збірками (assembly), інше їх найменування - переносимі виконувані файли (Portable Executable або PE).

Збірки є файлами з розширеннями exe або dll і складаються з безпосередньо програмного коду на мові CIL і додаткових службових даних, які називаються метаданими (у складі метаданих необхідна інформація про збірку – відомості про типи, дані про версію, посилання на зовнішні збірки і т.п.).

Збірки перед своїм виконанням повинні пройти певну настройку для роботи в умовах конкретної вибраної платформи – для виконання таких настройок у складі середовища CLR є ряд JIT-компіляторів (Just-Іn-Time compilers), що викликаються для перекладу програмного коду на проміжній мові (CIL-кода) в машинний (native) код платформи виконання.

Таким чином, має місце 2-етапна компіляція модулів:

1. На першому етапі створюється незалежний від платформи PE-файл (керований модуль). Цей файл містить код на проміжній мові MSIL (Microsoft Intermediate Language) і метадані, які містять всю необхідну інформацію про програму для її подальшого використання.

2. На другому етапі за допомогою JIT (Just In Time Compiler) виконується компіляція і верифікація модулів, формування збірок для конкретної платформи та їх виконання.

5.1.3. Система типів даних в Microsoft .NET

Cистема типів Microsoft .NET утворює ієрархію із зростанням спільності знизу вгору, в якій явно виділяються дві великі групи типів, а саме, типи-значення (value type) і типи-посилання (reference type).

Ця система типів спільна для всіх мов, які підтримуються в .NET. Існує також механізм відображення типів з CTS (Common Type System) на типи конкретних мов і навпаки.

Типи даних також обєднуються в простори імен (namespace).

Рис. 5.1. Структура системи типів Microsoft .NET

Типи-значення є статичними типами, пам’ять для них виділяється у стеку і вивільняється після завершення роботи програми.

Типи-значення не беруть участь в наслідуванні. Крім того, типи-значення копіюються при привласненні значення.

Посилкові типи потребують використовування покажчиків на об’єкти, що типізуються, а також централізованого зберігання і вивільнення пам'яті. Отже, об’єкти цього типу є динамічними, пам’ять під них виділяється з «кучі» і вивільняється після знищення об’єкти («збірка сміття»).

Посилкові типи можуть приймати одну з трьох форм:

1) об'єктні типи (object type);

2) інтерфейсні типи (interface type);

3) типи-покажчики (pointer type).

Управління типами в CTS

• Типи можуть використовуватися після ініціалізації (з урахуванням методу виклику, властивостей get і set і т.д.).

• Над типами можуть виконуватися перетворення (як явним, так і неявним чином).

5.2. Розробка компонентів на платформі .NET

Для інсталяції на комп'ютери користувачів раніше створеного прикладного програмного забезпечення створюються інсталяційні комплекти у формі так званих збірок.

Збіркою в .NET називається логічна одиниця, що містить модулі, необхідні для здійснення інсталяції програмного забезпечення. Збірка характеризується унікальністю, яка забезпечується ідентифікатором версії збірки і цифровим підписом автора. Збірка є самодостатньою одиницею для інсталяції програмного забезпечення і не вимагає ніяких доповнень. Можливо як індивідуальне, так і колективне (мережне) використання збірки на основі компонентної технології. Збірка забезпечує простий і зручний механізм інсталяції і економить час на розгортання програмного забезпечення, зводячи до мінімуму витрати часу і праці на інсталяцію.

Опис збірки міститься в маніфесті, де зберігаються метадані про компоненти збірки, ідентифікація автора і версії, відомості про типи і залежність, а також режим і політика використання. Метадані типів маніфесту вичерпно описують всі типи, визначені в збірці, а саме, властивості, методи, аргументи, значення, що повертаються, атрибути, базові класи і т.д.

Сімейство мов, які компілюються в проміжну мову (Intermediate Language або IL, тобто в так званий керований код) об'єднується в Microsoft Intermediate Language або MSIL.

Потім проміжна мова IL завжди компілюється в цільовий (native) код перед виконанням програми.

Для більш ефективного маніпулювання системою типізації компонент створюваного програмного забезпечення в рамках моделі COM, концепція .NET передбачає механізм просторів імен (namespace).

Описи просторів імен по аналогії з описами типів даних розміщуються у файлах.

Розглянемо основні властивості, якими характеризуються простори імен в середовищі Microsoft .NET.

Перш за все, простори імен можуть як об'єднувати різні збірки, так і бути вкладеними один в одного. Крім того, файли з описами можуть містити множинні простори імен. Важливо відзначити, що між просторами імен і файлами не існує однозначної відповідності. Нарешті, повне ім'я типу повинне містити всі необхідні простори імен.

Окрім цих властивостей механізм просторів імен в середовищі обчислень .NET має ще ряд важливих особливостей.

Так, допускається імпорт просторів імен з використанням зарезервованого слова using мови програмування C#.

Наприклад,

using System;

5.3. Поняття збірки і маніфесту в .NET

Розглянемо особливості використання механізму збірок, найважливішої концепції компонентного програмування, стосовно мови C#.

Нагадаємо, що під збіркою розуміється самодостатня виконувана одиниця, що містить всі необхідні дані для інсталяції, розгортання і повторного використання.

Збірка є мінімальною одиницею для розгортання застосувань, тобто представляє собою своєрідний атом компонентного програмування.

Кожний тип збірки характеризується унікальним ідентифікатором – номером версії збірки. Таким чином, кожний програмний проект формується у вигляді збірки, яка є самодостатнім компонентом для розгортання, тиражування і повторного використання. Збірка ідентифікується цифровим підписом автора і унікальним номером версії.

Між збірками і просторами імен існує наступне співвідношення. Збірка може містити декілька просторів імен. В той же час, простір імен може займати декілька збірок.

Збірка може мати в своєму складі як один, так і декілька файлів, які об'єднуються у складі маніфесту або опису збірки, який на звичній нам природній мові аналогічний змісту книги. Маніфест містить метадані про компоненти збірки, ідентифікацію автора і версії, відомості про типи і залежність, а також режим і політику використання збірки. Метадані типів маніфесту повною мірою описують всі типи, які описані в збірці.

В результаті компіляції програмного коду на мові C# в середовищі обчислень .NET створюється або збірка, або так званий модуль. При цьому збірка існує у формі виконуваного файла (з розширенням EXE), або файла динамічно приєднуваної бібліотеки (з розширенням DLL). Природно, до складу збірки входить маніфест. Модуль є файлом з розширенням .NETMODULE і, на відміну від збірки, не містить в своєму складі маніфесту. Інтеграція в програмний проект інших модулів і ресурсів (зокрема, типів і метаданих) може бути здійснена за допомогою системного програмного забезпечення, відомого під назвою компонувальника збірок.

Лабораторна робота 1. Створення DLL-бібліотеки

Мета роботи:

1. Створення DLL-бібліотеки

2. Створення рішення з кількох проектів (модулів)

3. Створення DLL-бібліотеки як окремого рішення.

4. Вивчення структури збірки, метаданих збірки

В платформі Microsoft .NET реалізовано компонентно-орієнтований підхід до програмування.

Цей підхід до проектування і реалізації програмних систем і комплексів є розвитком об'єктно-орієнтованого і практично придатніший для розробки великих  і розподілених систем.

В компонентній моделі .Net компонентом є збірка, яка може бути у вигляді виконуваного файлу (з розширенням EXE), або файлу динамічної бібліотеки (з розширенням DLL). До складу збірки входить маніфест.

Збірка є самодостатньою одиницею для розгортання, тиражування та повторного використання.

Збірка має маніфест, який містить інформацію про збірку (метадані, які описують збірку).

Динамічна бібліотека DLL як тип компонента

Динамічна бібліотека — набір функцій, скомпонованих разом у вигляді бінарного файла, який може бути динамічно завантажений в адресний простір процесу, що використовує ці функції. Динамічне завантаження (dynamic loading) — завантаження під час виконання процесу.

Оскільки динамічні бібліотеки є двійковими файлами, можна організувати спільну роботу бібліотек, розроблених із використанням різних мов програмування і програмних засобів, що спрощує створення застосувань на основі програмних компонентів (отже, динамічне компонування лежить в основі компонентного підходу до розробки програмного забезпечення).

1. Створення DLL-бібліотеки

Запустимо Visual Studio 2008, із стартової сторінки перейдемо до створення проекту, виберемо тип проекту «Class Library».  У вікні створення DLL всі поля заповнені значеннями за замовчанням. Як правило, їх слід перевизначити, задаючи власну інформацію.

У полі Name задати ім'я DLLMyLib.

У полі Location вказується шлях до каталогу, де зберігатиметься Рішення, що містить проект.

У полі Solution вибраний елемент «Create New Solution», що створює нове Рішення. Альтернативою є елемент списку, вказуючий, що проект може бути доданий до існуючого Рішення.

У вікні Solution Name задано ім'я Рішення.

Зверніть увагу на інші установки, зроблені в цьому вікні, - включений прапорець (за замовчанням) «Create directory for solution», у верхньому віконці із списку можливих каркасів вибраний каркас Framework .Net 3.5. Задавши необхідні установки і клацнувши по кнопці «OK», отримаємо автоматично побудовану заготівку проекту DLL, відкриту в середовищі Visual Studio 2008 .

Імена класів повинні бути змістовними. Змінимо ім'я «Class1» на ім'я «MyFun».  Для цього у вікні коду проекту виділимо ім'я змінної об'єкту, потім в головному меню виберемо пункт Refactor і підпункт Rename. У вікні, що відкрилося, вкажемо нове ім'я. Тоді будуть показані всі місця, що вимагають перейменування об'єкту. В даному випадку буде лише одна очевидна заміна, але в загальному випадку замін багато, так що автоматична заміна всіх входжень корисна.

Наступний крок також продиктований правилом стилю – ім'я класу і ім'я файлу, що зберігає клас, повинні збігатися. Перейменування імені файлу робиться безпосередньо у вікні проектів Solution Explorer.

І наступний крок продиктований також важливим правилом стилю, - додавання коментаря. Для цього в рядку перед заголовком класу слід набрати три слеша (три косі риски). В результаті перед заголовком класу з'явиться заголовний коментар – тег «summary», в який і слід додати короткий, але змістовний опис призначення класу. Теги «summary», якими слід супроводжувати класи, відкриті (public) методи і поля класу відіграють три важливі ролі. Вони полегшують розробку і супровід проекту, роблячи його самодокументованим. Клієнти класу при створенні об'єктів класу отримують інтелектуальну підказку, що пояснює суть того, що можна робити з об'єктами. Спеціальний інструментарій дозволяє побудувати документацію за проектом, що включає інформацію з тегів «summary».

У нашому випадку коментар до класу MyFun може бути достатньо простим – «Обчислення математичних функцій ».

Напишемо реалізацію одного методу класу – обчислення функції Sin(x) через ряд Тейлора.

Спочатку напишемо коментарі до методу (у форматі XML). Далі напишемо реалізацію методу. Отримаємо код.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace MyLib

{

///Обчислення математичних фунцій

   public class MySin

   {

    /// <summary>

    /// Sin(x)

    /// </summary>

    /// <param name="x">кут в радіанах – перший аргумент функції  Sin</param>

    ///<param name="n">показник ступеня – другий аргумент функції  Sin</param>

    /// <returns>Повертає значення функції Sin для заданого кута</returns>

       public static double Sin(double x, int n)

       {

           double result = 0;

           for (int i = 0; i < n; i++)

           {

               result = result + (Math.Pow((-1), i) * Math.Pow(x, (2 * i + 1))) / F(2 * i + 1);

           }

           return result;

       }

       static double F(int n)

       {

           double tmp = 1;

           for (int i = 1; i <= n; i++)

           {

               tmp = tmp * i;

           }

           return tmp;

       

       }

   }

}

Побудуємо Рішення, що містить проект, для чого в Головному меню виберемо пункт Build|Build Solution. В результаті успішної компіляції буде побудований файл з уточненням dll. Він знаходиться в папці проекту

.\bin\Debug

Оскільки побудована збірка не містить виконуваного файлу, то безпосередньо запустити наш проект на виконання не удасться. Побудуємо консольний  проект, до якого приєднаємо нашу DLL, і протестуємо, наскільки коректно працюють створені нами методи.

2. Створення консольного проекту для тестування функції з бібліотеки.

Виберемо пункт меню File|New|Project, задамо тип проекту ConsoleApplication, дамо йому ім'я – ConsoleMyLib, вкажемо, що проект додається до існуючого рішення.  В результаті у вже існуюче Рішення додасться ще один проект.

Напишемо код, який викликає функцію Sin(x,n), яку ми реалізували, стандартну функцію Sin(x), обчислює похибку і виводить результат на консоль.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace TestDLL

{

   class Program

   {

       /// <summary>

       /// Виклик бібліотечного метода Sin(x,n) з MyLib.dll

       /// </summary>

       /// <param name="args"></param>

       static void Main(string[] args)

       {

           Console.WriteLine("Введите x- угол в радианах");

           double x = double.Parse(Console.ReadLine());

           Console.WriteLine("Введите показатель степени n");

           int n = int.Parse(Console.ReadLine());

           //вызов метода вычисления sin(x) из библиотеки

           double my_sinus = MyLib.MyFun.Sin(x, n);

           //вызов метода из класса Math

           double sinus = Math.Sin(x);

           double delta = sinus - my_sinus;

           Console.WriteLine("my_sinus= {0},sin={1},delta={2}", my_sinus, sinus, delta);

           Console.ReadKey();

       }

   }

}

Побудуємо рішення і отримаємо повідомлення про помилку. Наша бібліотека не підключена  до проекту.

3. Підключення проекту бібліотеки до консольного проекту.

Для цього додамо посилання на проект з DLL MyLib. У вікні Solution Explorer наведемо покажчик миші до імені консольного проекту і з контекстного меню виберемо пункт меню «Add Reference». Виберемо вкладку «Projects». Оскільки проект MySin включений в Рішення, то він автоматично з'явиться у вікні, Якщо посилання потрібно встановити на проект, не включений в Рішення, то у вікні додавання посилань потрібно вказати шлях до проекту.

Посилання  на DLL  з'явиться в папці «References» консольного проекту. Тепер проекти зв'язані і з консольного проекту доступні функції DLL.

Перебудуємо рішення, щоб не було помилок.

4. Встановлення стартового проекту.

У вікні Solution Explorer наведемо курсор миші на заголовок консольного проекту і виберемо:

Set as StartUp Project

Після цього його можна запустити на виконання.

5. Створення Windows-проекту в тому самому рішенні.

Виберемо пункт меню File|New|Project, задамо тип проекту Windows Forms Application, дамо йому ім'я – WindowsMySin, вкажемо, що проект додається до існуючого Рішення.

На формі створимо 2 текстові поля для введення вхідних параметрів, третє і четверте – для результатів.

Додамо 2 кнопки. При натисканні кнопки "Обчислення Sin" виконується виклик функцій, "Вихід" – завершення роботи.

Код форми:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

namespace WindowsMySin

{

   public partial class Form1 : Form

   {

       public Form1()

       {

           InitializeComponent();

       }

       private void button1_Click(object sender, EventArgs e)

       {

          double x = double.Parse(txt_x.Text);

          int n = int.Parse(txt_n.Text);

          //вызов метода вычисления sin(x) из библиотеки

          double my_sinus = MyLib.MyFun.Sin(x, n);

          //вызов метода из класса Math

          double sinus = Math.Sin(x);

          txt_y1.Text = my_sinus.ToString();

          txt_y2.Text = sinus.ToString();

       }

       private void button2_Click(object sender, EventArgs e)

       {

           this.Close();

       }

   }

}

6. Робимо проект стартовим і запускаємо на виконання. Результат:

7. Документування коду

    /// <summary>

    /// Sin(x)

    /// </summary>

    /// <param name="x">кут в радіанах – перший аргумент функції  Sin</param>

    ///<param name="n">показник ступеня – другий аргумент функції  Sin</param>

    /// <returns>Повертає значення функції Sin для заданого кута</returns>

Завдання для самостійної роботи

2. Створити DLL-бібліотеку, яка містить методи, що реалізують завдання. В кожному методі вказати XML-коментарі.

3. Створити рішення, яке включає DLL-бібліотеку, консольний проект, який тестує роботу бібліотечних методів.

3. Створити Windows-проект в тому самому рішенні, який викликає бібліотечні методи.

4. Створити DLL-бібліотеку як окреме рішення. Зв'язати бібліотеку з Windows-проектом.

№ варіанту

Зміст завдання

1

1. Створити масив для зберігання значень зросту студентів групи (20 чоловік). Заповнити масив за допомогою класу Random цілими числами в діапазоні від 160 до 190 включно.  Відсортувати масив і вивести на консоль його елементи.

2. Є прямокутний масив розмірністю (5x5). Визначити суму всіх елементів третього рядка  і  суму всіх елементів першого стовпчика.

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

6x4-3x3+8x2-25=0

2

1. Згенерувати масив М випадкових чисел в діапазоні від 1 до 50. Обчислити  суму елементів масиву, середнє арифметичне (мат.очікування) елементів M, квадратний корінь від М, min і max елементів масиву. Результати вивести на консоль.

2.  В двовимірному масиві зберігається інформація про зарплату  18 співробітників за 12 місяців (за січень – першому стовпчику, лютий – другому, ...). Визначити загальний бюджет зарплати за рік, загальну  і середню зарплату за квітень.

3. Реалізувати консольній застосунок знаходження методом Ньютона коренів нелінійного рівняння

(x2-6*x)2 -2(x-3)2=81

3

1. Згенерувати масив випадкових чисел в діапазоні від 10 до 100. Обчислити добуток елементів масиву, середнє арифметичне (мат.очікування) елементів M, min і max елементів масиву. Результати вивести на консоль.

2.  В двовимірному масиві зберігається інформація про зарплату  18 співробітників за 12 місяців (за січень – першому стовпчику, лютий – другому, ...). Визначити загальну зарплату кожного співробітника за рік і середню зарплату за кожний місяць.

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

(x2+2x)2-(x+1)2=55

4

1. Згенерувати масив випадкових дійсних чисел в діапазоні від 0 до 1. Відсортувати масив, знайти min і max елементи. Результати вивести на консоль.

2.  В двовимірному масиві зберігається інформація про зарплату  30 працівників фірми за 12 місяців (за січень – першому стовпчику, лютий – другому, ...). Визначити середню зарплату  фірми за кожний місяць року, а також середню зарплату за кожний місяць кожного співробітника.

3. Реалізувати консольній застосунок знаходження коренів нелінійного рівняння методом бісекції

(x2+x+1)( x2+x+1) -12=0

5

1. Згенерувати дві серії випадкових чисел, що повторюються. Кількість чисел ввести з консолі. Результати вивести на консоль.

2. В двовимірному масиві зберігається інформація про оцінки  студентів з двох дисциплін (з дисципліни ОС – в першому стовпчику, з дисципліни Мова С# - в другому). Визначити середню успішність студентів  групи і середній бал (рейтинг) кожного студента  з цих дисциплін.

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

(x2-5*x+7) 2- (x-2)(x-3)=0

6

1. Згенерувати масив чисел Фібоначчі. Кількість чисел ввести з консолі. Результати вивести на консоль.

2. Фірма має  10 магазинів. Інформація про прибуток кожного магазину за кожний місяць зберігається в двовимірному масиві (першрго – в першому рядку, другого – в другому, і т.д.). Обчислити середній прибуток кожного магазину.

3. Реалізувати консольній застосунок знаходження методом Ньютона коренів нелінійного рівняння

x4-13x2+36=0

7

1. Створити масив для зберігання значень ваги  студентів групи (20 чоловік). Заповнити масив за допомогою класу Random цілими числами в діапазоні від 50 до 100 включно.  Відсортувати масив і вивести на консоль його елементи.

2. В двовимірному масиві зберігається інформація про оцінки  кожного із 20 студентів групи по кожній з 10 дисциплін. Перший рядок – інформація про оцінки першого студента, друга – другого і т.д. Обчислити середню успішність кожного студента.

3. Реалізувати консольній застосунок знаходження коренів нелінійного рівняння методом бісекції

2x8+x4-15=0

8

1. Створити масив з 10 елементів і заповнити його значеннями в коді. Всі його елементи:

- зменшити на 20;

- помножити на останній елемент

- збільшити на число В, яке ввести з консолі

2. В двовимірному масиві зберігається інформація про оцінки кожного із 20 студентів групи по кожній з 10 дисциплін. Перший рядок – інформація про оцінки першого студента, друга – другого і т.д. Обчислити середню успішність групи по кожній з дисциплін і в цілому успішність групи.

3. Реалізувати консольний застосунок знаходження методом бісекції коренів нелінійного рівняння

x4-13x2+36=0

9

1. Створити масив з 10 елементів і заповнити його значеннями в коді. Визначити суму всіх елементів масиву, суму квадратів всіх елементів масиву, середнє арифметичне всіх елементів масиву.

2. В двовимірному масиві 3x5 знайти суму елементів в кожному рядку і суму елементів кожного стовпчика.

3.  Реалізувати консольній застосунок знаходження коренів нелінійного рівняння методом Ньютона

x4-2x3+x-132=0

10

1. Створити масив з 10 елементів і заповнити його значеннями в коді. Всі його елементи: збільшити у 2 рази, розділити на перший елемент, зменшити на число А, яке ввести з консолі.

2. Три групи студентів, в кожній з яких 20 чоловік, в сесію здавали по 4 екзамени.  Відомості про оцінки кожної групи зберігаються в двовимірних масивах. Визначити кращу групу за середньою оцінкою

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

8x4+6x3-13x2-x+3=0

11

1. Створити масив з 8 елементів і заповнити його випадковими дійсними числами в діапазоні від 1 до 20.  Результати вивести на консоль

2. Створити прямокутний масив і заповнити його випадковими числами від 1 до 40. Знайти суму елементів другого стовпчика

 

3. Реалізувати консольній застосунок знаходження методом Ньютона коренів нелінійного рівняння

x3+6x+4x2+3=0

12

1. Створити масив з 8 елементів і заповнити його випадковими дійсними числами в діапазоні від 21 до 40. Результати вивести на консоль

2. Створити прямокутний масив і заповнити його випадковими числами від 1 до 40. Знайти суму елементів третього рядка масиву, які менше 20

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

2x4-x3-9x2+13x-5=0

13

1. Створити масив і заповнити його 20-ма першими цілими числами, які діляться на 13 або на 17 і знаходяться в інтервалі, ліва границя якого рівна 300.

2. Створити прямокутний масив і заповнити його випадковими числами від 1 до 40. Знайти суму елементів першого рядка масиву і кількість його не нульових елементів

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

(x-1)3+(2x+3)3=27x3+8

14

1. Створити масив і заповнити його 30-ма простими числами (простим є число, яке ділиться на 1 і самого себе)

2. Створити прямокутний масив цілих чисел і

заповнити його випадковими числами від 1 до 100. Визначити суму елементів масиву, які більше 30 і середнє арифметичне  всіх елементів

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

x4-4x3-19x2+106x-120=0

15

1. Створити масив і заповнити його 20-ма випадковими числами в діапазоні  20 до 100. Вивести на консоль елемент за його індексом в масиві.

2. Створити прямокутний масив цілих чисел і заповнити його випадковими числами від 1 до 60. Визначити суму елементів масиву, які більше 10 і середнє арифметичне елементів першого рядка

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

x4-2x3+x-132=0

16

1. Створити масив, розмір масиву ввести з консолі, заповнити його випадковими числами від 1 до 50. Відсортувати елементи. Вивести на консоль в прямому і зворотному порядку.

2. Створити прямокутний масив цілих чисел і ініціалізувати його при створенні. Для кожного рядка масиву обчислити суму від'ємних елементів.

3. Реалізувати консольній застосунок знаходження методом Ньютона коренів нелінійного рівняння

6x3-x2-20x+12=0

17

1. Створити масив, розмір масиву ввести з консолі, заповнити його випадковими дійсними числами від 1 до 50. Обчислити корінь квадратний кожного з його елементів і середнє арифметичне двох сусідніх елементів.

2. Створити прямокутний масив цілих чисел і ініціалізувати його при створенні. Для кожного рядка масиву обчислити суму додатних і від'ємних  елементів.

3. Реалізувати консольній застосунок знаходження методом Ньютона коренів нелінійного рівняння

x4+1=2(1+x)4

18

1. Створити масив, в якому зберігаються  дані про кількість опадів, які випали за кожний день місяця (наприклад, в листопаді). Обчислити загальну і середню кількість опадів за  місяць.

2. Створити прямокутний масив цілих чисел і ініціалізувати його при створенні. Для кожного стовпчика масиву обчислити суму додатніх, від'ємних елементів.

3. Реалізувати консольній застосунок знаходження методом Ньютона коренів нелінійного рівняння

5sin(2x)-5cos(2x)=tg(x)+5

19

1. Створити масив, в якому зберігаються  дані про температуру  в одному місяці. Обчислити середню температуру в місяці.

2. Створити прямокутний масив цілих чисел і ініціалізувати його при створенні. Для кожного рядка  масиву обчислити  кількість елементів, які більше 10.

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння.

3sin(x)-cos(x)=1/cos(x)

20

1. Створити масив, в якому зберігаються дані про кількість опадів, що випали за кожний день місяця (наприклад, в травні). Обчислити в якій половині місяця (першій чи другій) випало більше опадів. Обчислити в якій декаді місяця  кількість опадів була найбільшою

2. Створити прямокутний масив цілих чисел і ініціалізувати його при створенні. Знайти  максимальний і мінімальний елементи кожного рядка.

3. Реалізувати консольній застосунок знаходження методом бісекції коренів нелінійного рівняння

x4+1=2(1+x)4 


Лекція 6. Візуальне програмування

6.1. Парадигма візуального програмування

Парадигма візуального програмування базується на парадигмах ООП, компонентній та вимагає наявності інтегрованого середовища розробки (IDE), наприклад, Visual Studio .Net.

Поява можливостей візуального програмування з використанням повторно-використовуваного коду дозволило підвищити продуктивності праці програмістів в 10-20 разів.  

Лабораторна робота 2. Візуальне програмування – робота з БД   

Компонентне програмування – робота з об'єктами БД. (2 год)

Практикум прикладного программирования на C# в среде VS.NET 2008

http://www.intuit.ru/department/se/prcsharp08/

или прямо на лекцию 4

http://www.intuit.ru/department/se/prcsharp08/4/

Мета роботи:

1. Підключення до сервера БД

2. Створення власної БД і таблиць

3. Заповнення таблиці тестовими даними

4. Створення Windows-застосунку (форми)

5. Зв'язування елементів форми з джерелом даних

6. Створення запитів до даних і їх відображення на формі (у списку і таблиці).

1. Підключення до сервера БД

а) головне меню View/Server Explorer відображає на екрані вікно серверів

б) виділяємо вузол Data Connection, в контекстному меню вибираємо пункт Create New SQL Server Database.

Команди для візуальної роботи з різними джерелами даних зосереджені в меню Data.

2. Створення власної БД і таблиць

а) у вікні створення БД вибираємо сервер і вказуємо  назву БД: Lab2.

Використовуємо аутентифікацію Windows або SQL.

б). В БД створюємо таблицю Student:

Для цього виділяємо вузол  Tables і вибираємо Add New Table

В режимі конструктора створюємо потрібні поля і зберігаємо таблицю під назвою Student.

Для введення даних у таблицю у вікні Server Explorer виділяємо вузол з назвою таблиці, в контекстному меню вибираємо Show Table Data.

Для зміни структури таблиці – вибираємо Open Table Definition.

Для внесення змін у таблицю на диску – вибираємо Refresh.

Для перегляду частини даних з таблиці за певним критерієм – вибираємо New Query.

Можна, також, користуватися меню Data.

3. Заповнення таблиці тестовими даними

Для введення даних у таблицю у вікні Server Explorer виділяємо вузол з назвою таблиці, в контекстному меню вибираємо Show Table Data. Вводимо дані. Даємо Refresh для фіксації змін у БД.

4. Створення Windows-застосунку (форми)

a) Створюємо новий проект. Вибираємо тип Windows Form Application, В полі Name вказуємо назву проекту – WindowsFormLab2, далі місце його зберіганняу папці Lab2.

б) Створюємо на формі список ListBox. В ньому будуть відображатися прізвища всіх студентів групи. Властивості Name призначаємо listStudents.

5. Зв'язування елементів форми з джерелом даних

а) Встановлюємо для списку джерело даних (властивість DataSource).

З таблиці вибираємо тільки прізвище.

Завершуємо роботу майстра.

На формі в невидимій частині буде розміщено 3 компоненти: Lab2DataSet, studentBindingSource, studentTableAdapter.

б) для відображення даних з таблиці у списку, властивості DisplayMember призначимо назву вибраного в набір поля (St_Name).

д) зберігаємо рішення і запускаємо на виконання без режиму відлагодження.

Для перегляду джерела даних можна скористатися пунктом меню Data – ShowDataSource.

7. Створення запитів до даних і їх відображення на формі у вигляді таблиці (Grid)

Розміщуємо на формі компонент типу DataGridView. У вікні задач DataGridView Tasks вибираємо AddProjectData Source...

Вибираємо нашу БД і всі поля з таблиці Student.

Збираємо Рішення і запускаємо на виконання.

Змінимо заголовки колонок таблиці. Для цього виділимо DataGridView і під вікном  властивостей виберемо посилання Edit Columns.  У вікні Edit Columns по черзі вибираємо назви колонок і змінюємо для них властивості HeaderText.

Завдання для самостійної роботи

1. Дослідити код застосунку, який створено дизайнером.

2. Заповнити таблицю даними (не менш як 10 записів студентів групи)

3. Замінити  назви стовпчиків  для Grid.

Индивідуальні завдання (за номером у журналі)

1. Створити таблицю. 5-6 полів

2. Заповнити її даними в режимі редагування таблиці (5 записів)

3. Створити форму із списком і Grid.

4. Вивести дані у список і Grid

Варіанти завдань

Таблиця

Можливі колонки

1

Персона

код, прізвище, ім'я, по-батькові, рік народження, стать, місце проживання

2

Викладач

код, ПІБ, посада, кафедра, вчений ступінь, дисципліна

3

Телефонний довідник

телефон, ПІБ абонента, місто, район, адреса (вулиця, дім,квартира)

4

Клієнт (банку)

Номер рахунку, прізвище, ім'я, по-батькові, рік народження, сума на рахунку

5

Книжковий каталог

Код книги, назва, автор (и), рік видання, видавництво, кількість сторінок

6

Каталог товарів

Код, назва,тип товару, ціна, виробник

7

Каталог путівок

Код, країна, вартість, тривалість, умови проживання

8

Каталог дисків

Код, тема, назва, рік видання, вартість

9

Університет

код, назва, місто, адреса, URL сайту

10

Курсова робота

Код, студент, група, назва роботи, дисципліна, керівник

11

Дипломна робота

Код, студент, група, назва роботи, керівник, оцінка, рік захисту

12

Навчальна дисципліна

код, назва, викладач, кількість кредитів, семестр

13

14

15

Теоретичні відомості:

З'єднання з БД забезпечує об'єкт SQLConnection.

Взаємодію  з БД після з'єднання забезпечує об'єкт  DataAdapter

Зберігання  інформації в пам'яті  забезпечує  об'єкт  DataSet.

Від'єднані об'єкти БД:

DataAdapter

ADO.NET використовує об'єкт типа DataAdapter як міст між DataSet і джерелом даних, яке є основною базою даних. DataAdapter містить метод Fill() для оновлення даних з бази і заповнення DataSet.

DataSet

DataSet є відображенням використовуваної бази даних, перенесеним на машину користувача. При цьому немає необхідності постійно підключатися до сервера бази даних для модифікації даних.

DataSet складається з об'єктів типа DataTable і об'єктів DataRelation


ТЕМА 5. ПАРАДИГМА ДЕКЛАРАТИВНОГО ПРОГРАМУВАННЯ

Лекція 7. Основи парадигми декларативного програмування

7.1 Основи парадигми декларативного програмування

Парадигма декларативного (описового) програмування розвивалася паралельно з парадигмою імперативного (наказового). Ці дві основні парадигми часто протиставляються, хоча ідеї обох парадигм вже давно тісно переплетені. Так, декларативним є опис Web-сторінок на HTML, XML-документів, опис структур таблиць БД та SQL-запитів тощо. Відповідний стиль програмування також відносять до декларативного, а мови називають доменними, тобто, спеціалізованими для певних областей застосування, або DSL-мовами (Domain Specific Languages).

У програмі, що розробляється в парадигмі декларативного програмування, чітко формулюється мета і результат її роботи, а не алгоритм отримання цього результату. Для обробки структур даних використовуються стандартні алгоритми, які реалізовані у самих цих мовах. Наприклад, при створенні Web-сторінки засобами HTML специфікується, яким чином повинна виглядати сторінка, а трансляція цієї специфікації виконується за допомогою алгоритму, реалізованого у браузері. DSL-мови іноді вбудовуються в універсальні мови, хоча писати програми в декларативному стилі можна і за допомогою імперативних мов, інкапсулюючи “не декларативні” деталі в бібліотечні компоненти.

Але традиційно парадигма декларативного програмування асоціюється з мовами функціонального програмування (Lisp) та логічного програмування (Prolog).

Суть декларативного підходу полягає в тому, що програма представляє собою не набір команд, а опис дій, які необхідно здійснити.

Наприклад, в імперативній парадигмі програма представляється як набір операторів, а програма на декларативних мовах - є описом об'єктів, і зв'язків між ними.

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

Розглянемо стисло основні поняття кожної з цих парадигм.

7.2 Основи функціонального програмування

Функціональне програмування сформувалося як данина математичній спрямованості при дослідженні і розвитку штучного інтелекту і освоєнні нових горизонтів в інформатиці.

Функціональне програмування (functional programming) спирається на теорію рекурсивних функцій і лямбда-числення Алонзо Черча. В ньому акцент робиться на залежність між функціями та даними. Функціональна програма складається з сукупності визначень функцій, які у свою чергу є викликами інших функцій і операторів, що управляють послідовністю викликів.

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

Енциклопедія Wiki дає наступне визначення:

Функціональне програмування - розділ дискретної математики і парадигма програмування, в якій обчислювальний процес розглядається як обчислення значень функцій у математичному розумінні.

Свою історію функціональне програмування веде з 1958 року, коли Джон Маккарті створив мову Лісп (LISP - LISt Processing – мова обробки списків) - першу в світі мову функціонального програмування. До 80-х років минулого століття цей напрям досить добре розвивався. Була створена ціла низка мов функціонального програмування, а також було значно вдосконалено сам Лісп. З появою персональних компютерів (ПК) і поширенням обєктно-орієнтованої парадигми інтерес до функціонального програмування різко знизився. Перші ПК не мали достатньо обчислювальних ресурсів і, в той же час, вимагали зручного інтерфейсу користувача. Дейкстра зазначав, що поява ПК відкинула програмування на 15 років назад. Програмісти знову почали рахувати байти і такти процесора. Поступово на перший план виходить об'єктно-орієнтоване програмування, яке є дійсно зручним для створення графічних інтерфейсів. Декларативні мови застосовувалися переважно в університетах, наукових центрах, а також в тих компаніях, які займалися складними задачами і мали досить потужні обчислювальні ресурси.

Положення почало змінюватися останнім часом. Продуктивність комп'ютерів давно перестала бути проблемою, а складність вирішуваних задач постійно зростає.

Основна особливість функціональних мов – відсутність типів даних. (безтиповість).

Основні характеристики функціонального програмування:

1.) Аплікативність: програма є вираз, який складається із застосування функцій до аргументів.

2.) Настроюваність: оскільки не тільки програма, але і будь-який програмний об'єкт є виразом, можна легко породжувати нові програмні об'єкти за зразком, як значення відповідних виразів.

Настроюваність активно використовується в такому напрямі програмування, як генеруюче програмування (generic programming,). Основна задача, вирішувана в рамках цього напряму - створення максимально універсальних бібліотек, орієнтованих на вирішення задач, які часто зустрічаються (обробка агрегатних даних; потокове введення-виведення; взаємодія між програмами, написаними на різних мовах, універсальні віконні бібліотеки). Ці напрями найбільш яскраво представлені в STL - стандартній бібліотеці шаблонів мови С++ та в реалізації платформи DOT.NET.

Сфера застосування.

Як і інші стилі декларативного програмування, функціональне програмування застосовується для вирішення задач, які важко сформулювати в термінах послідовних операцій – переважно задач, пов'язаних з розпізнаванням образів, спілкуванням на природній мові, реалізацією експертних систем, автоматизованим доведенням теорем, символьними обчисленнями, тобто задач, які традиційно відносять до області штучного інтелекту.

Найбільш відома мова функціонального програмування – Lisp (1958) і його нащадки, найбільш сучасні з яких - Scheme і Common Lisp.

Основи Лісп

Базис Ліспу досить лаконічний — атоми і структури з найпростіших бінарних вузлів, а також декілька базових функцій і функціоналів. Базис містить вбудовані (примітивні) функції, які аналізують та будують будь-які структурні значення (atom, eq, cons, car, cdr), і вбудовані спеціальні функції і функціонали, які управляють обробкою структур, що представляють обчислювані вирази (quote, cond, lambda, label, eval). Над базисом будуються прості формули у вигляді списків, де перший елемент — функція, інші — її аргументи, у тому числі змінні, реалізовані за допомогою різних варіантів стека або асоціативного списку. Вся решта механізмів обчислення і перетворення формул може бути зведена до цього базису, розглядатися як його варіант або розширення.

Програма на Ліспі – це функція, яка застосовується до вхідних даних (аргументів) та повертає результат:

output = program(input)

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

Але останнім часом в інформаційних технологіях спостерігається зростання використання мов програмування, що інтерпретуються (наприклад, мови скриптів), а також включення в компілюючі мови механізмів символьної обробки і засобів динамічного аналізу, що підвищує інтерес до Ліспу та його варіантів. Моделююча сила Ліспу може послужити основою для чергового витка досліджень в компонентному програмуванні, формалізації поведінки інформаційних систем, розробки методів перетворення і захисту інформації, високопродуктивного програмування для суперкомп'ютерів, створення прототипів систем для нових застосувань.

Із сучасних мов елементи функціонального програмування є в Pyton, C#. Мова F# є мовою функціонального програмування на платформі DOT.NET.

Елементи функціонального програмування в С#:

-делегати (розширення показчика на функцію в C++);

- лямбда-вирази і дерева виразів.

7.3 Основи логічного програмування

Логічне програмування виникло як спрощення функціонального програмування для математиків і лінгвістів, які розвязують задачі символьної обробки.

На відміну від функціонального, логічне програмування засновано на логіці предикатів – напряму формальної логіки, що отримав розвиток у XX столітті.

У логічному програмуванні програма є сукупність правил або логічних виразів. Крім того, в програмі допускаються логічні причинно-наслідкові зв'язки, зокрема, на основі операції імплікації.

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

Програма на мові логічного програмування представляє собою деяку теорію і твердження, яке потрібно довести. Виконання програми полягає у доведенні цього твердження. Теорія задається за допомогою аксіом і правил виведення. Твердження, яке вимагається довести, вводиться в програму як цільова функція.

Робота програми здійснюється шляхом пошуку доведення запропонованого твердження в базі знань, що є сукупністю фактів і правил виведення.

Якщо у функціональному програмуванні функції однозначні - одержують аргументи і повертають результат, то в логічному програмуванні різниця між введенням і виведенням умовна. Можна вказати бажаний результат і отримати введення, яке його забезпечить. Інша важлива відмінність - недетермінізм логічних мов. Результат в них не обов'язково визначається однозначно. Таким чином, оскільки довільне цільове твердження може бути доведене не єдиним чином, система, що реалізує мову логічного програмування, послідовно пропонує відновити спробу довести твердження по-іншому. Для доказу тверджень використовується уніфікація (зіставлення двох довільних термів) і метод резолюцій.

В логічному програмуванні, також як і у функціональному програмуванні, програмісту невідомі методи обчислень, і послідовності елементарних дій. Основна частина відповідальності за їх ефективність покладається на транслятор логічної мови програмування.

Сфера застосування

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

7.4 Основи Пролог

Пролог - практично єдина широко використовувана мова логічного програмування. Програма на мові Пролог в загальному вигляді представляється як відношення між введенням і результатом.

program(input, output)

Розглянемо простий приклад.

Введемо відношення батько між об'єктами Іван і Петро. На Пролозі це буде виглядати так:

батько (іван, петро) – це факт, який визначає, що Іван є батьком Петра. Батько – ім'я відношення, Іван і Петро - його аргументи.

Відношення, про яке відомо, що воно є істина, називається фактом.

Сукупність фактів в Пролозі називають базою даних (або базою фактів).

Синтаксис Прологу

Розглянемо основні елементи Пролог. Отже, Пролог-програма складається з програмних конструкцій (clause) трьох типів:

Факти, правила, питання

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

Константи - це поіменовані конкретні об'єкти або відношення.

Змінна — це ланцюжок (слово), складений з літер, цифр і символу підкреслення, що починається з великої літери або символу підкреслення. Змінні служать для позначення об'єктів, значення яких змінюються в ході виконання програми

Атом — це ланцюжок, складений з літер, цифр і символу підкреслення, що починається з маленької літери або з великої літери, але тоді в одинарних лапках.

Числа записуються традиційним чином.

Цілі ( діапазон -32768- 32767)

Раціональні ( діапазон 1Е-307 - 1Е+308)

Структура - це єдиний об'єкт, що складається з сукупності інших об'єктів, які називаються компонентами. Компоненти у свою чергу можуть бути також структурами. Структура в Пролозі називається функтор.

Наприклад, дата:

data(dd,mm,yyyy)

Ідеї мови Пролог простежуються в сучасних мовах представлення знань в Інтернет: OWL, RDF, які лежать в основі розвитку Семантичного Веб

Питання:

1. Яка основна відміна між імперативною та декларативною парадигмами?

2. Які мови програмування традиційно відносять до декларативної парадигми?

3. Яка математична теорія лежить в основі функціонального програмування? 

4. Яка математична теорія лежить в основі логічного програмування?

5. Яка мова програмування традиційно є мовою функціонального програмування? 

6. Яка мова програмування традиційно є мовою логічного програмування?

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

8. Для якого класу задач призначене функціонального програмування?

9. Для якого класу задач призначене логічне програмування?

10. Що собою представляє програма у логічному програмуванні?

11. До якої парадигми відноситься мова Prolog?

12. До якої парадигми відносяться мови Lisp, Common Lisp?

13. У чому полягає виконання програми у логічному програмуванні?


Лекція
8. Основи XML

План

1. Визначення і структура XML-документа

2. Створення XML-документа

3. Способи відображення XML-документа.

4. Правила створення коректного XML-документа

8.1. Визначення і структура XML-документа

Будь-який документ можна представити у вигляді деякого набору символів, розділених на дві групи: перша група визначає вміст документа, друга – спеціальні набори символів (теги), призначені для специфічного виділення або позначки деяких частин першої групи. У XML-документах перша група носить назву "текст" або "контент", а друга називається розміткою. У мові HTML, наприклад, до розмітки відносяться всі теги, без виключення.

Розмітка XML-документа є дещо складніше поняття, ніж в мові HTML. Це пов'язано з трьома наступними обставинами:

1. XML-документ може містити інструкції обробки самого себе. Це означає, що обробник XML-документа (процесор) є посередником між цим документом і деяким застосуванням. Такими застосуваннями можуть бути бази даних, сервер каталога, мова програмування, що працює на стороні сервера, і тому подібне.

2. Синтаксис мови XML визначений жорстко і не допускає багатозначного тлумачення своїх правил. Причому будь-яке відхилення від цих правил спричиняє за собою відмову процесора обробляти весь документ. Тому в мові XML кількість обмежень на синтаксис документа, про які необхідно пам'ятати розробнику, значно більше, чим в мові HTML.

3. На відміну від мови HTML, розробник XML-документів сам визначає назви тегов і, можливо, правила їх інтерпретації. Якщо такі правила присутні, то вони відокремлені від безпосередньо XML-коду і утворюють так званий сценарій XSLT (XSL Transformation). Іншими словами, якщо XML-файл служить не лише для зберігання яких-небудь даних, але і для їх представлення, (наприклад, в браузері), то способи представлення цих даних винесені в окремий XSL-файл (XSL – розширювана мова стилів).

Структура інформації, що міститься в XML-файлі, є ієрархічною моделлю даних (як і HTML-документа), тобто, вся символьна інформація: розмітка або контент є сукупністю вузлів деякого дерева. По правилах XML в коректному документі має бути присутнім єдиний кореневий елемент. Всі останні елементи є його безпосередніми нащадками або нащадками інших його нащадків. Процес обробки такого документа починається з першого або кореневого елементу, потім обробляються вузли дерева другого рівня, потім — третього і так далі. Переважна більшість помилок виникають в результаті того, що набори символів розмічені не однозначно, тобто процесор не може визначити, до якого саме вузла слід віднести даний набір.

8.2. Створення XML-документа

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

8.2.1. Структура XML-документа

Як і HTML-документ, XML-документ складається з двох частин: Заголовка (прологу) (як тег HEAD в HTML) і елементу Документ (його також називають кореневим елементом).

Розглянемо ще один приклад XML-документа.

<?xml version="1.0" encoding="koi-8"?>

<notepad>

 <note id="1" date="12/04/99" time="13:40">

 <subject>Важная ділова встреча</subject>

<importance/>

<text>

Треба зустрітися з <Person id="1625">Иваном Івановичем</person>, заздалегідь  подзвонивши йому по телефону <tel>123-12-12</tel>

 </text>

</note>

...

<note id="2" date="12/04/99" time="13:58">

 <subject>Позвонить домой</subject>

 <text>

<tel>124-13-13</tel>

</text>

</note>

</notepad>

Питання. Як називається в даному прикладі кореневий елемент?

Заголовок XML-документа

Заголовок (пролог) згідно специфікації мови XML, підкоряється наступним правилам синтаксису:

1) заголовок повинен починатися з символів <?;

2) перед початковими символами заголовка не повинно бути інших символів;

3) заголовок повинен закінчуватися символами ?> ;

4) після початкових символів повинне стояти слово xml;

5) вказівка версії за допомогою конструкції version =" . . . " є обов'язковою;

6) номер версії на даний момент — 1.0;

7) номер версії має бути поміщений в лапки.

Окрім номера версії заголовок XML-документа може включати в оголошення кодування документа, яке визначається за допомогою конструкції encoding =". . . ". Наприклад:

<?xml version="1.0" encoding="koi-8"?>,

або

<?xml version="1.0" encoding="Windows-1251"?>

Елемент Документ

Другою основною частиною XML-документа є єдиний елемент Документ, або кореневий елемент, який у свою чергу містить додаткові елементи.

Примітка. Елемент Документ в XML-документі схожий на елемент BODY на HTML-сторінці, за винятком того, що ви можете призначити йому будь-яке допустиме ім'я.

Важливо!

1. Мова XML є чутливою до регістру символів, тому як відкриваючі, так і закриваючі теги мають бути записані символами в одному регістрі.

Невірно        Вірно

<tag> content </Tag>     <tag> content </tag>

<TAG> content </TAG>

tag і Tag – це різні теги на відміну від HTML!

2. Не допускається один або декілька пропусків перед відкриваючою дужкою тега, хоча в будь-якому іншому місці пропуски допустимі. Те саме стосується і символів кінців рядків. Таким чином, будуть вірними, наприклад, такі два варіанти коду:

<tag_name attl="l" att2="2">...</tag_name>

і

<tag_name

  attl="l" att2="2"

>

.......

</tag_name>

3. Використання закриваючого тега завжди обов'язково!

<?xml version="1.0"?>

<INVENTORY>

 <BOOK><TITLE>The Adventures of Huckleberry Finn</TITLE>

   <AUTHOR>Mark Twain</AUTHOR>

   <BINDING>mass market paperback</BINDING>

   <PAGES>298</PAGES>

   <PRICE>$5.49</PRICE>

 </BOOK>

<BOOK>

   <TITLE>Moby-Dick</TITLE>

   <AUTHOR>Herman Melville</AUTHOR>

   <BINDING>trade paperback</BINDING>

   <PAGES>605</PAGES>

   <PRICE>$4.95</PRICE>

 </BOOK>

<BOOK>

   <TITLE>The Scarlet Letter</TITLE>

   <AUTHOR>Nathaniel Hawthorne</AUTHOR>

   <BINDING>trade paperback</BINDING>

   <PAGES>253</PAGES>

   <PRICE>$4.25</PRICE>

 </BOOK>

</INVENTORY>

 

Імена елементів в XML-документі (такі як INVENTORY, BOOK і TITLE в наведеному вище прикладі) не є визначеннями мови XML. Ви всього лише призначаєте ці імена при створенні певного документа. Для ваших елементів ви можете вибирати будь-які коректно задані імена (LIST замість INVENTORY, або ITEM замість BOOK).

Примітка. Хоча немає спец. заборон, краще імена елементів писати латиницею.

У попередньому прикладі XML-документ має ієрархічну структуру у вигляді дерева з елементами, вкладеними в інші елементи, і з одним елементом верхнього рівня – він носить назву елемент Документ або кореневий елемент, – який містить всі інші елементи. Структуру описаного в прикладі документа можна представити, як показано на рисунку.

Таким чином, за допомогою XML ви можете описати ієрархічну структуру документа, такого як книга, що містить частини, глави і розділи.

8.3. Способи відображення XML-документа

Є три основні способи повідомити браузер як обробляти і відображувати кожен із створених XML-элементов.

  •  Таблиця стилів. За допомогою даного методу ви пов'язуєте таблицю стилів з XML-документом. Таблиця стилів є окремим файлом, що містить інструкції для форматування окремих XML-елеменьів. Ви можете використовувати або каскадну таблицю стилів (Cascading Style Sheet - CSS), яка також застосовується для HTML-сторінок, або розширювану таблицю у форматі мови стильових таблиць (Extensible Stylesheet Language - XSL), що має ширші можливості, ніж CSS, і розроблену спеціально для XML-документів.
  •  Звязування даних. Цей метод вимагає створення HTML-сторінки, зв'язування з нею XML-документа і встановлення взаємодій стандартних HTML-элементів на сторінці, таких як SPAN або TABLE, з елементами XML. Надалі HTML-элементи автоматично відображують інформацію з пов'язаних з ними XML-элементів.
  •  Написання сценарію. У цьому методі ви створюєте HTML-сторінку, пов'язуєте її з XML-документом і маєте доступ до окремих XML-элементів за допомогою спеціально написаного коду сценарію (JavaScript або VBScript). Браузер сприймає XML-документ як об'єктну модель документа (Document Object Model - DOM), що складається з великого набору об'єктів, властивостей і команд. Написаний код дозволяє здійснювати доступ, відображення і маніпулювання XML-елементами. 

Ви можете відкрити XML-документ безпосередньо через Internet Explorer, так само, як і ви б відкрили HTML-сторінку.

Якщо XML-документ не містить зв'язку з таблицею стилів, Internet Explorer позначає різні складові частини документа різним кольором, аби полегшити їх розпізнавання, а також представляє елемент Документ у вигляді ієрархічного дерева з можливістю згортання і розгортання структури і перегляду з меншою або більшою мірою деталізації.

Якщо ж XML-документ має зв'язок з таблицею стилів, Internet Explorer відображуватиме лише символьні дані з елементів документа, відформатувавши їх відповідно до правил, встановлених в таблиці стилів.

8.4. Правила створення коректного XML-документа

8.4.1. Визначення коректного документа

Коректно сформованим (правильно оформленим, well-formed) називається документ, що відповідає мінімальному набору критеріїв відповідності для ХМL-документа. Коли ви створюєте коректно сформований XML-документ, ви можете додавати елементи і вводити дані безпосередньо у ваш документ, як ви це робите при створенні HTML-документів. Правила створення коректного документа:

  •  Документ повинен мати лише один елемент верхнього рівня (елемент Документ або кореневий елемент). Всі інші елементи мають бути вкладені в елемент верхнього рівня.
  •  Елементи мають бути вкладені впорядкованим чином. Тобто, якщо елемент починається усередині іншого елементу, він повинен і закінчуватися усередині цього елементу.
  •  Кожен елемент повинен мати початковий і кінцевий тег. На відміну від HTML, в XML не дозволяється опускати кінцевий тег – навіть у тому випадку, коли браузер може визначити, де закінчується елемент (за винятком порожніх елементів – тобто елементів, що не мають вмісту). 
  •  Ім'я типу елементу в початковому тезі повинне в точності відповідати імені у відповідному кінцевому тезі.
  •  Імена типів елементів чутливі до регістра, в якому вони набрані. Насправді весь текст усередині XML-розмітки є чутливим до регістра. Наприклад, наступний опис елементу є неправильним, оскільки ім'я типу елемента в початковому тезе не відповідає імені типа в кінцевому тезі:

<TITLE>Leaves of grass</Title>  <!-- некоректний елемент -->

Питання. Знайти помилку в наведеному вище рядку.

8.4.2. Складові частини коректно сформованого ХМL-документа

Як ми вже знаємо, XML-документ складається з двох основних частин: прологу і елементу Документ (кореневого елементу). Окрім цього, коректно сформований XML-документ може містити коментарі, інструкції по обробці, пропуски. На наступному рисунку наведений приклад коректно сформованого XML-документа, що відображає різні частини документа і включення, які ви можете додавати в кожну з частин.

Примітка.

XML-визначення в даному прикладі також включає оголошення документа автономним (standalone='yes'). Це оголошення може використовуватися в деяких XML-документах з метою спростити обробку документа.

У цьому прикладі є коментар в пролозі, а також інший коментар, наступний за елементом Документ.

8.4.3. Додавання елементів в документ

Поняття елементу (element) є найголовнішим в мові XML. Елемент є логічними дужками, в які поміщається інформація, виділена із загального контента документа. Ці логічні дужки є відкриваючими і закриваючим тегами, або, у тому випадку, коли в елементу відсутній вміст, це буде тег порожнього елементу. Синтаксис запису тегів майже нічим не відрізняється від їх аналога в мові HTML.

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

Кожен елемент містить ряд вкладених елементів, як показано на наступному рисунку.

Примітка. Ім'я, яке міститься в початковому і кінцевому тезі, є тип елементу.

Кожен з елементів, вкладених в елемент BOOK, наприклад, елемент TITLE, містить лише символьні дані, як показано на наступному рисунку.

Елементи організовані в ієрархічну деревовидну структуру, в якій одні елементи вкладені в інші. Документ повинен мати один і лише один елемент верхнього рівня - елемент Документ, або кореневий елемент — а всі інші елементи вкладені в нього.

При додаванні елементу в XML-документ ви можете вибрати будь-яке ім'я типа, керуючись при цьому наступними правилами:

  •  ім'я повинне починатися з букви або з символу підкреслення (_), після чого можуть йти букви, цифри, символи крапки (.), тире (—) або підкреслення;
  •  у специфікації XML вказано, що імена типів елементів, які починаються з префікса «xml» (при будь-якому поєднанні рядкових або прописних букв), «зарезервовані для стандартних імен».

Нижче наведені приклади неправильних визначень типів.

Наступні імена використовувати неприпустимо:

1stPlace  <!-- Перший символ не може бути цифрою -->

У Section <!-- Пропуск усередині імені не дозволяється -->

B/Section <!-- Коса риска усередині імені не дозволяється -->

:Chapter  <!-- Двокрапку не можна використовувати першим символом -->

A:Section <!-- двокрапка допускається, лише якщо ви оголосили А як простір імен -->

8.4.4. Типи вмісту елементу

Вмістом елементу вважається текст, розташований між початковим і кінцевим тегами. Ви можете використовувати як вміст елементу наступні типи повідомлень:

  •  вкладені елементи - елемент INVENTORY і елемент ВООК мають в своєму вмісті вкладені елементи: 

  •  символьні дані - це текст, що виражає інформаційний вміст елементу, наприклад, назва певної книги в елементі TITLE.  Нижче наведений приклад вмісту елементу, що складається з поєднання символьних даних і вкладеного елементу, як показано на наступному малюнку.

При додаванні в елемент символьних даних ви можете використовувати будь-які символи, за винятком лівої кутової дужки (<), амперсанда (&) і рядка ]]>.

  •  Посилання на загальні примітиви (entity, сутності) і посилання на символи. На наступному рисунку наведений елемент, що містить обидва типи таких посилань.

  •  Розділи CDATA — це текстовий блок, в якому ви можете вільно розміщувати будь-які символи, за винятком рядка ]]>. Приклад розділу СDАТА усередині елементу, показаний на наступному рисунку.

  •  Інструкції по обробці містять інформацію, необхідну для XML-застосувань.
  •  Коментарі — це примітки до вашого XML-документу, які читаються людьми, але ігноруються XML-процессором. На наступному рисунку наведений елемент, що містить інструкцію по обробці і коментар.

Порожні елементи

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

<HR></HR>

Або ви можете використовувати спеціальний тег порожнього елементу:

<HR/>

Ці нотації є еквівалентними.


Лекція 9. Робота з XML в .NET

План

1. Класи для роботи з XML .NET

2. Читання і запис потоків даних Xml

2.1. Використання класу XmlReader

2.2. Методи читання даних

2.3. Контроль типів даних при читанні Xml-документа

3. Створення XML-документа в Visual Studio

9.1. Класи для роботи з XML .NET

Багато складових технологій .NET нерозривно пов'язані з XML. А значить, XML добре підтримується з боку Framework Class Library. У .NET підтримуються наступні технології:

  •  XML 1.0
  •  простори імен XML
  •  XSD схеми
  •  вирази XPath
  •  XSL перетворення 
  •  DOM Level 1 Core, DOM Level 2 Core

Середовище .NET Framework  не лише дозволяє застосовувати XML в створюваних застосуваннях, але і сама застосовує його в конфігураційних файлах, документації за вихідним кодом і в маніфесті збірки.

Приклад 1. Маніфест збірки

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

 <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>

 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

   <security>

     <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">

       <requestedExecutionLevel level="asInvoker" uiAccess="false"/>

     </requestedPrivileges>

   </security>

 </trustInfo>

</assembly>

Класи для роботи з XML зібрані в просторі імен System.Xml. Цей простір завантажується разом з класами, які можуть використовуватися для обробки даних XML.

Таблиця 9.1. Основні класи читання і запису даних XML

XmlReader

Абстрактний клас, що виконує читання і забезпечує швидку доставку некешованих даних XML. Клас є однонаправленим синтаксичним аналізатором

XmlWriter

Абстрактний клас, що виконує запис даних у вигляді потоку або файлу

XmlTextReader

Розширює можливості класу XmlReader. Забезпечує однонаправлений потоковий доступ до даних XML

XmlTextWtiter

Розширює можливості класу Xml.Writer. Забезпечує швидку однонаправлену генерацію потоків XML

Таблиця 9.2. Деякі класи обробки даних XML

XmlNode

Абстрактний клас, що представляє один вузол в XML-документі. Базовий клас для деяких інших класів

XmlDocument

Розширює клас XmlNode. Є реалізацією DOM від W3C. Забезпечує деревовидне представлення XML-документа в пам'яті з можливостями навігації і редагування

XmlNavigator

Забезпечує навігацію по документу

XMLDataDocument

Слугує мостом між сховищами даних і реляційними даними, що зберігаються в DataSet

9.2. Читання і запис потоків даних Xml

Середовище .NET Framework  підтримує два способи обробки  XML-документів: потокове введення-виведення і DOM. Абстрактні класи XmlReader, XmlWriter і породжені від них класи підтримують потокову  модель введення-виведення.

Класи, засновані на XmlReader забезпечують швидкий однонаправлений курсор, який організує потік даних XML для обробки.

Від XmlReader породжені наступні класи:

XmlNodeReader

використовує XmlNode як джерело замість потоку

XmlTextReader

Забезпечує однонаправлений потоковий доступ до даних XML

XmlValidatingReader

Додає визначення шаблону DTD (Document TypeDefinition) і забезпечує перевірку достовірності даних

Від XmlWriter  породжені наступні класи:

XmlTextWriter

Розширює можливості класу Xml.Writer. Забезпечує швидку однонаправлену генерацію потоків XML

XmlQueryOutput

Розширює можливості класу Xml.Writer, Забезпечує функціональність, необхідну для виведення результатів перетворень XSLT 

Для роботи з даними кожен з класів надає необхідні методи.

9.2.1. Використання класу XmlReader

Приклад читання даних XML з файлу. Дані зберігаються у файлі "book2.xml" і є описом книжкового каталога:

<?xml version="1.0" encoding="Windows-1251"?>

<INVENTORY>

  <BOOK>

     <TITLE>Страны Світу </TITLE>

     <AUTHOR>Книжний Клуб</author>

     <BINDING>Харьков</BINDING>

     <PAGES>380</PAGES>

     <PRICE>$4.00</PRICE>

  </BOOK>

  <BOOK>

     <TITLE>Секреты роботи в Windows</TITLE>

     <AUTHOR>Дэвид Маккормік</author>

     <BINDING>Харьков</BINDING>

     <PAGES>300</PAGES>

     <PRICE>$5.20</PRICE>

  </BOOK>

  <BOOK>

     <TITLE>Выбор і модернізація компьютера</TITLE>

     <AUTHOR>Михаил Кутузов</author>

     <BINDING>Питер - Москва </BINDING>

     <PAGES>320</PAGES>

     <PRICE>$6.30</PRICE>

  </BOOK>

  <BOOK>

     <TITLE>3d max</TITLE>

     <AUTHOR>Кэлли Мердок</author>

     <BINDING>Киев-Москва</BINDING>

     <PAGES>1050</PAGES>

     <PRICE>$10.95</PRICE>

  </BOOK>

  <BOOK>

     <TITLE>Система Програмування Delphi</TITLE>

     <AUTHOR>Волков Андрей</author>

     <BINDING>Москва</BINDING>

     <PAGES>800</PAGES>

     <PRICE>$10.95</PRICE>

  </BOOK>

  <BOOK>

     <TITLE>Как зібрати свій компьютер</TITLE>

     <AUTHOR>Джон Кослі</author>

     <BINDING>Москва</BINDING>

     <PAGES>300</PAGES>

     <PRICE>$6.90</PRICE>

  </BOOK>

  <BOOK>

        <?MyApp Part="value 1" Parm2="value 2" ?>

        <TITEL>dfsdfdfsdf</TITEL>

        <AUTHOR>sdfsdf</AUTHOR>

        <!-- sdfsdfsdfsdf -->

        <BINDING>фіваваіва</BINDING>

        <PAGES>234</PAGES>

        <PRICE>$12.8</PRICE>

   </BOOK>

</INVENTORY>

Створимо форму з двома кнопками і текстовим редактором (richTextBox1), в який розміщуватимемо прочитані дані.

При натисненні кнопки ReadXml виконується читання і розбір XML-файла і виведення його в текстовий редактор. Обробник кнопки ReadXML_Click:

     private void ReadXML_Click(object sender, EventArgs e)

       {

           //читання файлу

           richTextBox1.Clear(); //очистка редактора

           XmlReader rdr = XmlReader.Create("book2.xml");//створення об'єкту rdr

           while (rdr.Read())

           {

               if (rdr.NodeType == XmlNodeType.Text)

                   richTextBox1.AppendText(rdr.Value + "\r\n");

           

           }

       }

Клас XmlReader є абстрактним, тобто, для таких класів не можна створювати об'єкти оператором new. Для того, щоб його можна було використовувати, потрібно включити в нього статичні методи.

У цьому обробнику використовується статичний метод Create, який повертає об'єкт XmlReader.  Далі в циклі while виконується читання кожного рядка файлу. У міру читання виконується перевірка властивості NodeType. Якщо вузол є текстовим, в текстовий редактор додається його вміст.

9.2.2. Методи читання даних

Класи для роботи з XML надають декілька способів пересування по XML-документу. Наприклад, метод Read() переміщає на наступний вузол. Потім можна перевірити, чи має цей вузол вміст (HasValue() ) або атрибути (HasAttributes()).

Основні методи аналізу документа представлені в таблиці нижче.

Read()

читає черговий запис і переміщає на наступний вузол

HasValue()

повертає true, якщо елемент має вміст, інакше - false

HasAttributes()

переглядає елемент на наявність атрибутів.  Повертає true, якщо елемент має вміст, інакше – false

ReadStartElement()

перевіряє, чи є вузол кореневим, після чого зміщується на наступний вузол. Якщо вузол не кореневий, збуджується виключення  XmlException.

IsStartElement()

аналогічний методу ReadStartElement()

ReadString()

читання одного рядка з файлу, що містить документ

ReadElementString()

подібний до методу ReadString() за винятком того, що йому можна передати ім'я елементу. Якщо наступний вузол з вмістом не є початковим дескриптором або якщо параметр Name не збігається з поточним параметром вузла, збуджується виключення

MoveToContent()

переміщення до вмісту вузла

Приклад 2. Виведення окремих елементів XML-документа

Розглянемо використання методу ReadElementString() і інших методів, а також використання файлових потоків (читання з файлу).

Не забути  підключити  using System.IO;

Додамо на форму кнопку Read from file. Код обробника буде наступним:

     private void btmReadXml2_Click(object sender, EventArgs e)

       {

           //читання лише назв книг (елемент "TITLE"

           richTextBox1.Clear();

           FileStream fs = new FileStream("book2.xml", FileMode.Open);

           XmlReader rdr = XmlReader.Create(fs);

           while (!rdr.EOF)

           {

               //Якщо потрапляємо на тип елементу, перевірити його і завантажити у вікно

               if (rdr.MoveToContent() == XmlNodeType.Element && rdr.Name == "TITLE")

               {

                   richTextBox1.AppendText(rdr.ReadElementString() + "\r\n");

               }

               else

               {

                // інакше - переміститися на наступний запис

                   rdr.Read();

               }

           }

  }

В цьому прикладі в циклі while використовується метод MoveToContent() для пошуку вузла типа XmlNodeType. Element з назвою книги rdr.Name == "TITLE")

               

if (rdr.MoveToContent() == XmlNodeType.Element && rdr.Name == "TITLE")

Перегляд виконується до кінця файлу (умова циклу

           while (!rdr.EOF)

Якщо типом вузла не є елемент або його ім'я не збігається з "TITLE", то викликається метод Read() для переходу до наступного вузла. Якщо черговий вузол "TITLE" знайдений, його вміст додається у вікно виводу. Таким чином, будуть виведені лише назви книг.

9.2.3. Контроль типів даних при читанні Xml-документа

Клас XmlReader також дозволяє читати дані із строгим контролем типів. Для цього використовуються методи ReadElementContentAs... ReadElementContentAsDouble(),  ReadElementContentAsBoolean() та інші. Далі показано як можна прочитати значення в десятковому форматі і виконати обчислення.  У прикладі вибирається значення ціни книги, яке збільшується на 25%.

Створимо ще одну кнопку з написом New Price, а в її обробнику напишемо код:

private void btnNewPrice_Click(object sender, EventArgs e)

{

 //Обробник кнопки NewPrice - контроль типів

  richTextBox1.Clear();

  XmlReader rdr = XmlReader.Create("book2.xml");

  while (rdr.Read())

    {

     if (rdr.NodeType == XmlNodeType.Element)

      {

        if (rdr.Name == "PRICE")

         {

          decimal price = rdr.ReadElementContentAsDecimal();

          richTextBox1.AppendText("Curent Price = "+ price+ "\r\n");

          price += price * (decimal)0.25;

          richTextBox1.AppendText("New Price = " + price + "\r\n\r\n");

         }

        else if (rdr.Name=="TITLE")

          richTextBox1.AppendText(rdr.ReadElementContentAsString()+"\r\n");

      }

    }

   rdr.Close();

}

Якщо це значення не може бути перетворене до необхідного типа, збуджується виключення FormatException.

Компілюємо і запускаємо на виконання наш проект.

В результаті отримуємо повідомлення про помилку. Причина – текст елементу має вигляд:

     <PRICE>$10.95</PRICE>

Виправимо всі елементи <PRICE> 10.95</PRICE>

а  документ збережемо під ім'ям ("book3.xml");

В результаті  отримаємо:

9.3. Створення XML-документа в Visual Studio

Для створення  XML-файла в середовищі Visual Studio  потрібно в меню File вибрати New->File. У вікні створення  вибрати Xml-файл.

Відкриється Xml-редактор, в якому  можна вводити елементи Xml. Редактор автоматично перевіряє помилки і підставляє закриваючі теги. Створений файл можна зберегти в потрібному місці на диску командою SaveXmlFile.xml As...


Лекція 10. Створення XML-документів в .NET

План

1. Використання класу XmlWriter - запис потоків даних Xml

2. Використання DOM в .Net

2.1. Читання XML-документа за допомогою XmlNodeList

2.2. Вставка елементів (вузлів)  в XML- документ

3. Обробка атрибутів

3.1. Витягання атрибутів за допомогою XmlReader

3.2. Вставка атрибутів  в документ за допомогою XmlWriter

10.1. Використання класу XmlWriter - запис потоків даних Xml

Таблиця 10.1. Основні класи читання і запису даних XML

XmlReader

Абстрактний клас, що виконує читання і забезпечує швидку доставку некерованих даних XML. Клас є однонаправленим синтаксичним аналізатором

XmlWriter

Абстрактний клас, що виконує запис даних у вигляді потоку або файлу

XmlTextReader

Реалізація  класу XmlReader. Забезпечує однонаправлений потоковий доступ до даних XML

XmlTextWtiter

Реалізація  класу Xml.Writer. Забезпечує швидку однонаправлену генерацію потоків XML

Для роботи з даними кожен з класів надає необхідні методи.

Клас XmlWriter дозволяє записувати Xml-код в потік даних, файл, в клас StringBuilder, TextWriter  та інші об'єкти XmlWriter.

Клас легко конфігурується, що дозволяє визначити потребу в допоміжних установках, таких як відступи, лапки, простори імен і інше. Така конфігурація виконується з використанням об'єкту XmlWriterSettings.

Створимо обробник кнопки WriteXml  прикладу попередньої лекції.

При натисненні кнопки WriteXml виконується створення елементів XML-документа і запис його в новий файл  "booknew.xml";

      private void btmWriteXml_Click(object sender, EventArgs e)

       {

          // запис у файл

           XmlWriterSettings setting = new XmlWriterSettings();

           setting.Indent = true;

           XmlWriter writer = XmlWriter.Create("booknew.xml", setting);

           writer.WriteStartDocument();

           //початок створення єлементов

           writer.WriteStartElement("Catalog");

           writer.WriteStartElement("book");

           writer.WriteElementString("title", "Основи інженерії якості програмних систем");

           writer.WriteStartElement("author");

           writer.WriteElementString("name", "Коротун Т.М.");

           writer.WriteElementString("name", "Коваль Г.І.");

           writer.WriteEndElement();

           writer.WriteElementString("price", "120.00");

           writer.WriteEndElement();

           writer.WriteEndElement();

           writer.WriteEndDocument();

           //Очищення потоку

           writer.Flush();

           writer.Close();

       }

В цьому прикладі створюється новий XML-файл booknew.xml, у який записуються дані про нову книгу. Клас XmlWriter перезаписує існуючий вміст файлу новим вмістом.  Для вставки нових елементів використовуються методи класу XmlWriter.  Для створення об'єкту XmlWriter використовується статичний метод Create(). У прикладі рядок, що представляє ім'я файлу, передається як параметр разом з екземпляром класу XmlWriterSettings.

Клас XmlWriterSettings має властивості, які керують способом створення Xml-докуметів. Наприклад, властивість Indent – булеве значення, яке визначає, чи повинні елементи виводитися з відступом.  Властивість IndentChars містить  рядок символів, використовуваний для відступу.  За умовчанням це рядок з двох символів. Властивість NewLine служить для визначення символу нового рядка.

Основні методи класу XmlWriter

WriteStartDocument()

додає оголошення документа. Після цього можна додавати дані.

WriteEndDocument()

визначає кінець документа (вставляє тег кінця)

WriteStartElement()

додає новий елемент

WriteElementString

вставляє рядок, вказуючий ім'я і вміст елементу

WriteEndElement

визначає кінець елементу (вставляє тег кінця)

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

В результаті буде створений такий файл:

<?xml version="1.0" encoding="utf-8"?>

<Catalog>

 <book>

   <title>Основи інженерії якості програмних систем</title>

   <author>

     <name>Коротун Т.М.</name>

     <name>Коваль Г.І.</name>

   </author>

   <price>120.00</price>

 </book>

</Catalog>

Цей файл містить XML-документ, що описує одну книгу.  Такий метод придатний для створення нових документів. А що робити, якщо необхідно додати елемент в існуючий XML-документ? Наприклад додати нову книгу в каталог. Для цього потрібно скористатися класами  DOM.

10.2. Використання DOM в .Net

Реалізація об'єктної моделі документа (DOM, Document Object Model) в .NET підтримує специфікації W3C DOM Level 1 і Core DOM Level 2. DOM реалізується за допомогою класу XmlNode. XmlNode є абстрактним класом, який представляє вузол документа XML. XmlNodeList є впорядкованим списком вузлів. Це активний список вузлів, і будь-які зміни в будь-якому вузлі негайно відбиваються в списку. XmlNodeList підтримує індексний доступ або ітеративний доступ. Ці два класи складають основу реалізації DOM на платформі .NET.

Основні класи, які грунтуються на XmlNode

Ім'я класу

Опис

XmlLinkedNode

Розширює XmlNode. Повертає вузол безпосередньо перед або після поточного вузла. Додає властивості NextSibling і PreviousSibling в XmlNode.

XmlDocument

Розширює XmlNode. Представляє весь документ. Реалізує специфікації DOM Level 1 і Level 2.

XmlAttribute

Розширює XmlNode. Об'єкт атрибуту об'єкту XmlElement.

XmlCDataSection

Розширює XmlCharacterData. Об'єкт, який представляє розділ документа CData.

XmlCharacterData

Абстрактний клас, який надає методи маніпуляції з текстом для інших класів. Розширює XmlLinkedNode.

XmlComment

Розширює XmlCharacterData. Представляє об'єкт коментаря XML.

XmlDeclaration

Розширює XmlLinkedNode. Представляє вузол оголошення (<?xml version='1.0' ...>)

XmlDocumentFragment

Розширює XmlNode. Представляє фрагмент дерева документа.

XmlDocumentType

Розширює XmlLinkedNode. Дані, пов'язані з оголошенням типа документа.

XmlElement

Розширює XmlLinkedNode. Об'єкт елементу XML.

XmlEntity

Розширює XmlNode. Синтаксично розібраний або нерозібраний вузол сутності.

XmlEntityReferenceNode

Розширює XmlLinkedNode. Представляє посилковий вузол сутності.

XmlNotation

Розширює XmlNode. Містить нотацію, оголошену в DTD або в схемі. 

XmlProcessingInstruction

Розширює XmlLinkedNode. Містить інструкцію обробки XML. 

XmlSignificantWhitespace

Розширює XmlCharacterData. Представляє вузол з роздільником. Вузли створюються, лише якщо прапор PreserveWhiteSpace заданий як true. 

XmlWhitespace

Розширює XmlCharacterData. Представляє роздільник у вмісті елементу. Вузли створюються, лише якщо прапор PreserveWhiteSpace заданий як true. 

XmlText

Розширює XmlCharacterData. Текстовий вміст елементу або атрибуту.

Як можна бачити .NET робить доступним клас, який відповідає майже будь-якому типу XML. Діаграма спадкоємства класів.

10.2.1. Читання XML-документа за допомогою XmlNodeList

Створимо нове застосування WINXML-DOM WindowsApplication, який читатиме дані книжкового каталога і завантажуватиме назви книг у вікно списку.

Для різноманітності дані виводитимемо в Listbox. Це аналогічно прикладу використання XmlReader. Відмінність полягає в тому, що здійснюється вибір, з якими вузлами ми хочемо працювати, замість того аби використовувати весь документ. Ось код для виконання цього прикладу в середовищі XmlNode.

Додамо на форму список і дві кнопки. Крім того, додамо текстові поля для наступної версії програми.

При натисненні кнопки Чтение в список виводимо назви книг. Обробник кнопки:

      private void btmReadXML_Click(object sender, EventArgs e)

       {

        // змінити дорогу доступу відповідно до структури доріг доступу

         doc.Load("book2.xml");

         // отримати лише ті вузли, які потрібні

         XmlNodeList nodeLst=doc.GetElementsByTagName("TITLE");

         // ітерації за списком XmlNodeList

        foreach(XmlNode node in nodeLst) listBox1.Items.Add(node.InnerText);

       }

Зверныть увагу, що ми додали наступне оголошення на рівні модуля:

   public partial class Form1 : Form

   {     

       public XmlDocument doc = new XmlDocument();

        public Form1()

       {

           InitializeComponent();

       }

Якби це було все, що потрібно зробити, то використання XmlReader було б значно ефективнішим способом завантаження вікна списку. Причина в тому, що ми пройшли через документ один раз і потім закінчили з ним роботу. Проте, якщо бажано повторно відвідати вузол, то використання XmlDocument є кращим для цього способом.

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)

       {

           // створити рядок пошуку XPath

           string srch = "INVENTORY/BOOK[TITLE='" + listBox1.SelectedItem.ToString() + "']";

           // пошук додаткових даних

           XmlNode foundNode = doc.SelectSingleNode(srch);

           if (foundNode != null) MessageBox.Show(foundNode.InnerText);

           else MessageBox.Show("Not found");

       }

В цьому прикладі listbox із заголовками завантажується з документа book2.xml. Коли ми клацаємо на вікні списку, викликаючи породження події SelectedIndexChange, ми беремо текст вибраного пункту в listbox, в даному випадку заголовок книги, створюємо оператор XPath і передаємо його в метод SelectSingleNode об'єкту doc. Він повертає елемент book, частиною якого є TITLE (foundNode). Виведемо для наочності InnerText вузла у вікні повідомлення. Ми можемо продовжувати клацати на елементах в listbox скільки завгодно раз, оскільки документ завантажений і залишається завантаженим, поки ми його не звільнимо.

Невеликий коментар відносно методу SelectSingleNode. Це реалізація XPath в класі XmlDocument. Існують методи SelectSingleNode і SelectNodes. Обидва вони визначені в XmlNode, на якому грунтується XmlDocument. SelectSingleNode повертає XmlNode, і SelectNodes повертає XmlNodeList.

10.2.2. Вставка елементів (вузлів)  в XML- документ

Раніше розглядався приклад XmlTextWriter, який створює новий документ. Обмеження полягало у тому, що він не вставляв вузол в поточний документ. Це можна зробити за допомогою класу XmlDocument.

Створимо в обробнику кнопки Запис код, що Додає в список і файл нову книгу (елемент BOOK).

private void btmSaveXML_Click(object sender, EventArgs e)

       {

           // змінити дорогу доступу, як потрібний існуючою структурою

           doc.Load("book2.xml");

           // створити новий елемент 'book'

           XmlElement newBook = doc.CreateElement("BOOK");

           // створити новий елемент 'title'

           XmlElement newTitle = doc.CreateElement("TITLE");

           newTitle.InnerText = "Основи інженерії якості ПС";

           newBook.AppendChild(newTitle);

           // створити новий елемент author

           XmlElement newAuthor = doc.CreateElement("AUTHOR");

           newAuthor.InnerText = "Коротун Т.";

           newBook.AppendChild(newAuthor);

           XmlElement newName = doc.CreateElement("AUTHOR");

           newAuthor.InnerText = "Коваль Г.";

           newBook.AppendChild(newAuthor);

           // створити новий елемент Binding

        

           XmlElement newBind = doc.CreateElement("BINDING");

           newBind.InnerText = "Академперіодіка";

           newBook.AppendChild(newBind);

           //

           XmlElement newPages = doc.CreateElement("PAGES");

           newPages.InnerText = "650";

           newBook.AppendChild(newPages);

           //

           XmlElement newPrice = doc.CreateElement("PRICE");

           newPrice.InnerText = "150";

           newBook.AppendChild(newPrice);

           

           // додати до поточного документа

           doc.DocumentElement.AppendChild(newBook);

           // записати doc на диск

           XmlTextWriter tr = new XmlTextWriter("booksEdit.xml", null);

           tr.Formatting = Formatting.Indented;

           doc.WriteContentTo(tr);

           tr.Close();

           // завантажити listBox1 зі всіма заголовками, включаючи новий

           listBox1.Items.Clear();

           XmlNodeList nodeLst = doc.GetElementsByTagName("TITLE");

           foreach (XmlNode node in nodeLst)      listBox1.Items.Add(node.InnerText);

       }

При виконанні цього коду буде отримана функціональність попереднього прикладу, але у вікні списку з'явилася одна додаткова книга "Основи інженерії  якості ПС". Клацання миші на заголовку цієї книги приведе до виведення такої ж інформації, як і для інших книг.

В цьому прикладі спочатку створюється новий елемент BOOK:

           XmlElement newBook = doc.CreateElement("BOOK");

Метод CreateElement має три перенавантажені версії, які дозволяють визначити ім'я елементу, ім'я і простір імен URI, і, нарешті, prefix (префікс), lоcalname (локальне ім'я) і namespace (простір імен).

Потім додаються нові елементи, вкладені в елемент BOOK.

           // створити новий елемент 'title'

           XmlElement newTitle = doc.CreateElement("TITLE");

           newTitle.InnerText = "Основи інженерії якості ПС";

           newBook.AppendChild(newTitle);

Тут знову створюється новий об'єкт на основі XmlElement (newTitle). Призначимо властивості InnerText заголовок нової книги і додаємо нащадок до елементу book. Потім це повторюється для решти елементів book.

Нарешті, ми додаємо елемент newBook до вузла doc.DocumentElement. Це той же рівень, що і в усіх інших елементів book. Ми замінили існуючий документ новим, на відміну від XmlWriter, де можна було лише створити новий документ. Останнє, що потрібно зробити, це записати новий документ XML на диск. В даному прикладі ми створюємо новий XmlTextWriter і передаємо його в метод WriteContentTo. Не забудьте викликати метод Close на XmlTextWriter, аби скинути вміст внутрішніх буферів і закрити файл.

Методи WriteContentTo і WriteTo отримують XmlTextWriter як параметр. WriteContentTo зберігає поточний вузол і всіх нащадків в XmlTextWriter, тоді як WriteTo зберігає поточний вузол. Оскільки doc є об'єктом на основі XmlDocument, він представляє весь документ і тому буде збережений. Можна було б також використовувати метод Save. Він завжди зберігатиме весь документ. Save має чотири перенавантажені версії. Можна визначити рядок з ім'ям файлу і шляхом доступу, об'єкт на основі класу Stream, об'єкт на основі класу TextWriter, або об'єкт на основі XmlWriter. Саме це було використано при виконанні прикладу. Додамо новий елемент в кінець списку:

           listBox1.Items.Clear();

           XmlNodeList nodeLst = doc.GetElementsByTagName("TITLE");

           foreach (XmlNode node in nodeLst) listBox1.Items.Add(node.InnerText);

В цьому прикладі вміст елементів формувався просто в обробнику кнопки.

Наступний приклад демонструє створення XML-елементів, вміст яких береться з текстових полів форми при натисненні кнопки Добавить:

Обробник кнопки Добавить:

      private void btmAdd_Click(object sender, EventArgs e)

       {

           // змінити дорогу доступу, як потрібний існуючою структурою

           doc.Load("book2.xml");

           // створити новий елемент 'book'

           XmlElement newBook = doc.CreateElement("BOOK");

           // створити новий елемент 'title'

           XmlElement newTitle = doc.CreateElement("TITLE");

           newTitle.InnerText = txtName.Text;

           newBook.AppendChild(newTitle);

           // створити новий елемент author

           XmlElement newAuthor = doc.CreateElement("AUTHOR");

           newAuthor.InnerText = txtAuthor1.Text;

           newBook.AppendChild(newAuthor);

           if (txtAuthor2.Text.Length != 0)

           {

               XmlElement newName = doc.CreateElement("AUTHOR");

               newAuthor.InnerText = txtAuthor2.Text;

               newBook.AppendChild(newAuthor);

           }

           // створити новий елемент Binding

           XmlElement newBind = doc.CreateElement("BINDING");

           newBind.InnerText = txtPub.Text;

           newBook.AppendChild(newBind);

           //

           XmlElement newPages = doc.CreateElement("PAGES");

           newPages.InnerText = txtPages.Text;

           newBook.AppendChild(newPages);

           //

           XmlElement newPrice = doc.CreateElement("price");

           newPrice.InnerText = txtPrice.Text;

           newBook.AppendChild(newPrice);

           // додати до поточного документа

           doc.DocumentElement.AppendChild(newBook);

           // записати doc на диск

           XmlTextWriter tr = new XmlTextWriter("booksEdit.xml", null);

           tr.Formatting = Formatting.Indented;

           doc.WriteContentTo(tr);

           tr.Close();

           // завантажити listBox1 зі всіма заголовками, включаючи новий

           listBox1.Items.Clear();

           XmlNodeList nodeLst = doc.GetElementsByTagName("TITLE");

           foreach (XmlNode node in nodeLst) listBox1.Items.Add(node.InnerText);

      }

Якщо потрібно створити документ із самого початку, можна використовувати клас XmlTextWriter. Можна також використовувати XmlDocument. Який з них вибрати? Якщо дані, які бажано помістити в XML, доступні і готові для запису, то підійде клас XmlTextWriter. Проте, якщо необхідно створити документ XML поступово, вставляючи вузли в різні місця, то найбільш прийнятним буде використання XmlDocument.

10.3. Обробка атрибутів

Зазвичай атрибути не розглядаються як частина структури документа.  Але, при необхідності, можна визначити їх наявність і витягувати значення. Для витягання і запису атрибутів можна (як для елементів) використовувати класи XmlReader, XmlWriter, а також XmlDocument.

10.3.1. Витягання атрибутів за допомогою XmlReader

У таблиці перелічені деякі властивості і методи для обробки атрибутів.

HasAttributes

властивість. Повертає значення true, якщо елемент має атрибути і false – якщо немає

AttributeCount

властивість. Повідомляє скільки атрибутів  має елемент

GetAttribute()

метод. Витягує атрибут по імені або по індексу

MoveToFirstAttribute()

метод. Дозволяє перейти до першого атрибуту

MoveToNextAttribute()

метод. Дозволяє перейти до наступного атрибуту

Для демонстрації цих можливостей додамо в XML-файл booknew.xml у елемент book атрибути:

<?xml version="1.0" encoding="utf-8"?>

<Catalog>

 <book genre="Программная інженерія"  yearpublic="2006" >

   <title>Основы інженерії якості програмних систем</title>

   <author>

     <name>Коротун Т.М.</name>

     <name>Коваль Г.І.</name>

   </author>

   <price>120.00</price>

 </book>

</Catalog>

Відкриємо попередній проект WINDOWS-XML.

Додамо на форму ще одну кнопку для витягання атрибутів з елементу book. У обробник кнопки вставимо код:

       private void btnAttr_Click(object sender, EventArgs e)

       {

           //витягання атрибутів з елементу

           richTextBox1.Clear();

           XmlReader rdr = XmlReader.Create("booknew.xml");

               //читання вузлів

           while (rdr.Read())

           {

               //перевірити, чи не є він вузлом

               if (rdr.NodeType == XmlNodeType.Element)

               {

               //Якщо це елемент, перевірить його атрибути

                   for (int i = 0; i < rdr.AttributeCount; i++)

                   {

                     richTextBox1.AppendText(rdr.GetAttribute(i) + "\r\n");

                   }

               }

     

           }

           rdr.Close();

       }

10.3.2. Вставка атрибутів  в документ за допомогою XmlWriter

Додамо на форму кнопку WriteAttributes. Обробник кнопки створює новий файл booknew.xml, у якому розміщується документ Catalog, що складається з одного вкладеного елементу  book. У елементі book є два атрибути "genre" і "yearpublic". Метод WriteAttributeString() додає атрибут до елементу.

    private void btmWriteAtt_Click(object sender, EventArgs e)

       {

           // запис у файл з атрибутами

           XmlWriterSettings setting = new XmlWriterSettings();

           setting.Indent = true;

           string fname = "booknew.xml";

           XmlTextWriter writer = new XmlTextWriter(fname, null);

           writer.Formatting = Formatting.Indented;

           writer.WriteStartDocument();

           //початок створення єлементов

           writer.WriteStartElement("Catalog");

           writer.WriteStartElement("book");

           writer.WriteAttributeString("genre", "Програмна інженерія");

           writer.WriteAttributeString("yearpublic", "2006");

           writer.WriteElementString("title", "Основи інженерії якості програмних систем");

           writer.WriteStartElement("author");

           writer.WriteElementString("name", "Коротун Т.М.");

           writer.WriteElementString("name", "Коваль Г.І.");

           writer.WriteEndElement();

           writer.WriteElementString("price", "120.00");

           writer.WriteEndElement();

           writer.WriteEndElement();

           writer.WriteEndDocument();

           //Очищення потоку

           writer.Flush();

           writer.Close();

       }

В результаті  буде створений файл booknew.xml, що містить опис книги.

Інший спосіб додавання і витягання атрибутів – викорстання моделі DOM (клас XmlDocument).

Висновки

Класи C# забезпечують різні способи обробки Xml-документів. Окрім розглянутих в лекції, в .NetFramework є класи для створення схем документів, перевірки документів  на відповідність схемі, пошук інформації по вмісту(XPath і XslTransform), обробку запитів, взаємодію з базою даних.


Лекція 11. Елементи функціонального програмування в C#

План

1. Елементи функціонального програмування в C#

2. Делегати

3. Лямбда-вирази і лямбда-функції

11.1. Елементи функціонального програмування в C#

Навіть з назви «Функціональне програмування» ясно, що основний наголос в ньому робиться на функції (у математичному сенсі), тобто, y=f(x). Функціональне обчислення – функція (або якщо бути точніше – «чиста функція», pure function) – повинна приймати деякі аргументи (вхідні дані) на вході, виконувати обчислення і повертати деякий результат. При цьому функція не повинна створювати жодних побічних ефектів. Під побічними ефектами розуміється можливість функції:

  1.  Змінювати глобальні (статичні в термінах C#) змінні.
  2.  Викликати інші функції, які можуть створити побічний ефект.
  3.  Займатися будь-яким введеннямиведенням усередині функції.
  4.  Посилати або приймати деякі повідомлення.

По суті, пункти 2-4 є різновидами одного і того ж – зміна стану за допомогою виклику.

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

Програмування у функціональному стилі дозволяє зробити код коротше і безпечніше.

C# не є повністю мовою функціонального програмування, але містить елементи, що дозволяють писати програми у функціональному стилі.

До основних елементів функціонального програмування, підтримуваних в C#, можна віднести: делегати, лямбда-вирази і дерева виразів, а також нова інтегрована мова запитів Language Integrated Query (LINQ).

11.2. Делегати

Делегати в C# є аналогом посилання на функцію в C++. Сама по собі функція (метод) або її ім'я не є чимось, чим можна було б маніпулювати, але якщо помістити її делегат, з'явиться можливість посилатися на неї, а значить передавати в інші функції і повертати функції з інших функцій. Таким чином, можна сказати, що делегати є аналогами функціональних типів в мовах функціонального програмування.

Основне використання делегатів у C# - обробка подій.

Багато класів стандартної бібліотеки .Net Framework використовують делегати для повідомлення про події, що сталися в них. Відповідно, розробники середовища .NET визнали, що буде доцільно ввести загальний стандартний тип делегат, який використовуватиметься у всій бібліотеці. Його прототип представлений нижче.

public delegate void EventHandler(

  // Посилання на об'єкт, що викликав подію.

  object sender   

  // Параметри, що описують подію.

  EventArgs e

);

Цей делегат приймає всього лише два параметри, що явно замало для універсального делегата. Але все таки виявляється, цих параметрів вистачає для передачі будь-якої інформації. Сам по собі клас EventArgs не містить жодного члена, здатного передавати яку б то не було інформацію. Він введений лише для узагальнення. Коли необхідно передати додаткову інформацію, вводиться новий клас, похідний від EventArgs, в якому вже і вводяться поля, які передають необхідну інформацію. У одній загальній бібліотеці у класу EventArgs 100 нащадків, і їх кількість від версії до версії середовища виконання неухильно зростає.

При зверненні до події, що має тип даного делегата, як параметр необхідно передати посилання на поточний об'єкт (this), а в другому параметрі екземпляр класу EventArgs або похідного від нього.

SomeEvent(this, EventArgs.Empty);

де властивість Empty просто повертає порожній екземпляр типу EventArgs. В принципі, його можна створити і самому скориставшись оператором new.

SomeEvent(this, new EventArgs());

Приклад

Програма для генерації варіантів тестів. Використовуються стандартые делегати.

Одні і ті самі дії можна виконати при натисненні кнопки, вибором пункту меню або кнопки панелі інструментів. Наприклад, генерація варіантів (програмна кнопка).

     private void btmGentest_Click(object sender, EventArgs e)

       {

//кнопка Button – фрагмент коди

           DateTime Date;  //дата з календаря у форматі DateTime

           //Знімаємо дані з полів форми

           string Disc = txtDisc.Text;                     //Дисциплина

           string Teacher = comboBox1.Text;            //Преподаватель

           try

           {

               if (Disc.Length == 0)

               {

                   throw new Exception("Введіть назву дисципліни");

               }

               if (Teacher.Length == 0)

               {

                   throw new Exception("Введіть прізвище викладача");

               }

               Date = monthCalendar1.SelectionRange.Start;   //дата, вибрана на календарі. За умовчанням, поточна дата

               string strDate = Date.ToString();             //преобразование дати в рядок

               int numberVariant = (int)numericUpDown1.Value; //к-во варіантів завдань.

           

}

---------------------------  ----------------------------------

      private void toolStripButton1_Click(object sender, EventArgs e)

       {

           //кнопка панелі інструментів Генерувати - делегат події btmGentest_Click

           btmGentest_Click(this, new EventArgs());

       }

--------- ------------------- ------------------------------

       private void генеруватиToolStripMenuItem1_Click(object sender, EventArgs e)

       {

           //меню Генеруваті

           //кнопка генерації - делегат події btmGentest_Click

            btmGentest_Click(this, new EventArgs());

}

11.3. Лямбда-вирази і лямбда-функції 

Функціональне програмування базується на лямбда численні, яке запропоноване Алонзо Черчем.

Вікипедія дає таке визначення:

Лямбда-числення (исчисление, лямбда-числення) — формальна система, розроблена американським математиком Алонзо Черчем, для формалізації і аналізу поняття обчислюваності.

лямбда-числення може розглядатися як сімейство прототипних мов програмування. Їх основна особливість полягає в тому, що вони є мовами вищих порядків. Тим самим забезпечується систематичний підхід до дослідження операторів, аргументами яких можуть бути інші оператори, а значенням також може бути оператор. Мови в цьому сімействі є функціональними, оскільки вони базуються на уявленні про функцію або оператор, включаючи функціональну аплікацію і функціональну абстракцію.

Базисом функціонального програмування є лямбда вирази і анонімні функції.

Анонімні функції дозволяють створити функції, в яких немає імені.

У контексті мов програмування під лямбда-функцією розуміють анонімну функцію. Тобто функцію, якій не зіставлено жодне ім'я, просто значення функціонального типа.

Анонімна функція – це оператор або вираз "inline", який можна використовувати кожного разу, коли очікується тип делегата. Її можна використовувати для ініціалізації іменованого делегата або підставити замість типу іменованого делегата як параметр методу.

Існує два типи анонімних функцій:

  •  Лямбда-вирази
  •  Анонімні методи

Лямбда-виразце анонімна функція, яка містить вирази і оператори і може використовуватися для створення делегатів або типів дерев виразів.

У всіх лямбда-виразах використовується лямбда-оператор =>, який читається як "переходить в". Ліва частина лямбда-оператора визначає параметри введення (якщо такі є), а права частина містить вираз або блок оператора.

Лямбда-вираз x => x * x читається як "x переходить в x x разів". Цей вираз може бути призначений типу делегата таким чином:

delegate int del(int i);

static void Main(string[] args)

{

   del myDelegate = x => x * x;

   int j = myDelegate(5); //j = 25

}

Оператор => має той самий пріоритет, що і оператор призначення (=) і є правоасоциативним.

Багато мов програмування підтримують роботу з анонімними функціями.

Приклади

С#

delegate(int x){return x +1; }

Pyton

lambda x: x + 1

Lisp

(lambda (x) (+ x 1))

PHP (http://blog.kron0s.com/anonymous-functions-in-php )

Змінні-функції

До того як сказати що-небудь про анонімні функції, поглянемо на концепцію PHP відому як змінні-функції. Вона полягає в тому, що якщо додати до змінної круглі дужки, то інтерпретатор PHP спочатку перевірить, чи не існує функції з ім'ям рівним значенню змінної і якщо вона є - виконати її. Це можна побачити на наступному прикладі:

  1.  function Hello($name)
  2.  {
  3.      echo "Привіт $name";
  4.  }

Ми можемо викликати цю функцію, використовуючи змінну, що зберігає її ім'я. І це може бути дуже корисно, якщо ім'я функції не визначене до моменту виконання.

  1.  $func = "Hello";
  2.  $func("Світ!");
  3.   
  4.  // результат:
  5.  //Привіт, Світ!

Інший приклад, використовуючи клас і статичний метод:

  1.  <?php
  2.  class CHello
  3.  {
  4.      static function Hello($name)
  5.      {
  6.          echo "Привіт $name";
  7.      }
  8.  }
  9.  $func = "Hello";
  10.  CHello::$func("Світ!");
  11.   
  12.  // результат:
  13.  // Привіт, світ!
  14.  ?>

Анонімні або лямбда функції в php

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

Розглянемо на прикладі:

  1.  <?php
  2.  $str = "Привіт, Світ!";
  3.  $lambda = create_function('$match', 'return "Друг!";');
  4.  $str = preg_replace_callback('/Мир/' $lambda, $str);
  5.  echo $str ;
  6.  ?>

Тут ми створили маленьку безіменну (анонімну) функцію, яка викликається у функції preg_replace_callback. Хоча create_function дозволяє створити анонімні функції, це не частина мови, а "хак". PHP 5.3 підтримує по справжньому анонімні функції як частину мови. Ми створюємо безіменну функцію і призначаємо її змінній і потім просто використовуємо цю змінну як функцію.

Приклад:

  1.  <?php
  2.  $func = function($name)
  3.  {
  4.      echo "Привіт $name\n";
  5.  };
  6.   
  7.  $func("Світ!");
  8.  $func("Олексій!");
  9.   
  10.  // результат:
  11.  //Привіт, Світ!
  12.  //Привіт, Олексій!
  13.  ?>

Зверніть увагу, що в кінці визначення функції є крапка з комою. Вона необхідна, оскільки таке визначення функції це твердження, а після визначення твердження завжди має бути крапка з комою. Ще один приклад:

  1.  <?php
  2.  $str = "Привіт, Світ!";
  3.  $func = function($match)
  4.  {
  5.      return "друг!";
  6.  };
  7.   
  8.  $str = preg_replace_callback('/Мир/' $func, $str);
  9.  echo $str ;
  10.  ?>

Анонімні і вкладені функції

PHP дозволяє вкладати функції всередину одна одної. Розглянемо на прикладі. Функція censorString приймає рядок як параметр і замінює потрібні слова в рядку на "*". Функція censorString визначає вкладену функцію replace, яка використовується при виклику preg_replace_callback. Враховуючи те, що функція replace використовується в нашій програмі лише у функції censorString, краще всього визначити її як вкладену, аби не забруднювати простір імен.

  1.  <?php
  2.  function censorString($string, $censor)
  3.  {
  4.      function replace($match)
  5.      {
  6.          return str_repeat("*", strlen($match[0]));
  7.      }
  8.   
  9.      return preg_replace_callback('/'.$censor.'/', 'replace' $string);
  10.   
  11.  }
  12.   
  13.  echo censorString("Привіт, світ!", "світ");
  14.  echo censorString("Привіт, світ!", "Привіт");
  15.   
  16.  // результат:
  17.  // Привіт ***!
  18.  // Fatal error: Cannot redeclare replace()
  19.  ?>
  20.  

При такому визначенні функції як в прикладі вище, вкладена функція не існує до тих пір, поки не почнеться виконуватися батьківська функція. Як тільки виконується батьківська функція (censorString), вкладена функція з'являється в глобальному просторі імен. Тепер ми можемо дістати доступ до вкладеної функції з будь-якого місця програми. Проблема полягає в тому, що при повторному виклику батьківської функції буде зроблена спроба передекларувати вкладену функцію, що викличе помилку, оскільки вона вже існує. Рішення в тому, аби використовувати вкладену функцію, як це показано нижче. (Зверніть увагу на крапку з комою в кінці вкладеної функції.)

  1.  <?php
  2.   function censorString($string, $censor)
  3.  {
  4.      $func = function($match)
  5.      {
  6.          return str_repeat("*", strlen($match[0]));
  7.      };
  8.   
  9.      return preg_replace_callback('/'.$censor.'/', $func, $string);
  10.   
  11.  }