Oracle Типи об'єктів PL/SQL: CREATE TYPE з прикладами

⚡ Розумний підсумок

Об'єктні типи в PL/SQL надають об'єктно-орієнтованому програмуванню Oracle, що дозволяє моделювати реальні сутності за допомогою атрибутів та методів. Вони підтримують конструктори, успадкування та порівняння рівності, тому один тип рівня схеми може зберігати та обробляти структуровані дані.

  • 🧱 Компоненти типу об'єкта: Об'єктний тип поєднує атрибути, що зберігають дані, та члени, або методи, що визначають його логіку обробки.
  • 🏗️ Створити об'єкт: Типи об'єктів створюються на рівні схеми за допомогою CREATE TYPE, а їхні методи визначаються в окремому тілі CREATE TYPE BODY.
  • 🔧 Конструктори: Кожен тип об'єкта має неявний конструктор, названий на честь цього типу, і ви можете визначити явний конструктор для встановлення значень за замовчуванням.
  • 🧬 успадкування: Батьківський тип NOT FINAL розширюється за допомогою UNDER, тому підтип успадковує всі батьківські атрибути та члени.
  • 🇧🇷 рівність: Функція-член ORDER порівнює два екземпляри об'єкта та повертає від'ємне, нульове або додатне число.
  • 🤖 Допомога AI: Помічники штучного інтелекту, такі як GitHub Copilot, створюють визначення CREATE TYPE, конструктори та методи ORDER з коментаря.

Oracle Типи об'єктів PL/SQL, що показують CREATE TYPE з атрибутами та методами

Що таке тип об’єкта в PL/SQL?

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

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

Банківський рахунок, змодельований як об'єктний тип з атрибутами та методами в PL/SQL

In PL / SQL, об'єктно-орієнтоване програмування базується на типах об'єктів. Тип об'єкта може представляти будь-яку реальну сутність. У розділах нижче розглядаються типи об'єктів, їхні компоненти, а також способи їх створення та використання.

Компоненти типів об'єктів

Об'єктний тип PL/SQL містить переважно два компоненти.

  1. Attributes
  2. Члени/Методи

Attributes

Атрибути – це стовпці або поля, в яких зберігаються дані. Кожен атрибут відповідає типу даних, який визначає тип обробки та зберігання для цього атрибута. Атрибут може бути будь-яким допустимим Тип даних PL/SQL, або це може бути об’єкт іншого типу.

Члени/Методи

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

Створити об'єкт у Oracle

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

На скріншотах нижче показано синтаксис CREATE TYPE для специфікації об'єкта та синтаксис CREATE TYPE BODY, який визначає його методи.

Синтаксис CREATE TYPE, що визначає специфікацію об'єкта з атрибутами в Oracle Синтаксис CREATE TYPE BODY, що визначає методи об'єктного типу PL/SQL

CREATE TYPE<object_type_name> AS OBJECT
(
<attribute_l><datatype>,
.
.
);
/
CREATE TYPE BODY<object_type_name> AS OBJECT
(
MEMBER[PROCEDURE|FUNCTION]<member_name> 
IS
<declarative section>
BEGIN
<execution part>
END;
.
.
);
/

Пояснення синтаксису:

  • Наведений вище синтаксис показує створення ОБ'ЄКТА з атрибутами та ТІЛА ОБ'ЄКТА з методами.
  • Методи також можуть бути перевантажені в тілі об’єкта.

Ініціалізація оголошення типу об’єкта

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

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

На скріншоті нижче показано змінну, що оголошується як об'єктний тип всередині Блок PL/SQL.

Оголошення змінної об'єктного типу в декларативній секції блоку PL/SQL

DECLARE
<variable_name> <object_type_name>;
BEGIN
.
.
END;
/

Пояснення синтаксису:

  • Наведений вище синтаксис показує оголошення a змінна як тип об'єкта в декларативній секції.

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

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

Ініціалізація екземпляра об'єктного типу значенням null за допомогою його конструктора

DECLARE
<variable_name> <object_type_name>; 
BEGIN
<variable_name>:=<object_type_name>();
END;
/

Пояснення синтаксису:

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

Конструктори

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

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

Приклад 1: У наступному прикладі ми використовуємо член об'єктного типу для вставки записів у таблицю emp зі значеннями ('RRR', 1005, 20000, 1000) та ('PPP', 1006, 20000, 1001). Після вставки даних ми відображаємо їх за допомогою члена об'єктного типу. Ми також використовуємо явний конструктор для заповнення ідентифікатора менеджера значенням за замовчуванням 1001 для другого запису.

Ми виконуємо його в наступних кроках.

  • Крок 1: Створіть тип об'єкта та тіло типу об'єкта.
  • Крок 2: Створіть анонімний блок для виклику типу об'єкта через неявний конструктор для emp_no 1005.
  • Крок 3: Створіть анонімний блок для виклику типу об'єкта через явний конструктор для emp_no 1006.

Крок 1) Створіть тип об'єкта та тіло типу об'єкта.

На скріншоті нижче показано створення специфікації типу об'єкта emp_object з її атрибутами та членами.

Створення специфікації об'єктного типу emp_object з атрибутами та членами

CREATE TYPE emp_object AS OBJECT(
emp_no NUMBER,
emp_name VARCHAR2(50),
salary NUMBER,
manager NUMBER,
CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER, p_emp_name VARCHAR2,
p_salary NUMBER) RETURN SELF AS RESULT),
MEMBER PROCEDURE insert_records,
MEMBER PROCEDURE display_records);
/

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

Визначення тіла типу emp_object за допомогою явного конструктора та процедур-членів

CREATE OR REPLACE TYPE BODY emp_object AS
CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER,p_emp_name VARCHAR2,
p_salary NUMBER)
RETURN SELF AS RESULT
IS
BEGIN
Dbms_output.put_line('Constructor fired..');
SELF.emp_no:=p_emp_no;
SELF.emp_name:=p_emp_name;
SELF.salary:=p_salary;
SELF.manager:=1001;
RETURN;
END;
MEMBER PROCEDURE insert_records
IS
BEGIN
INSERT INTO emp VALUES(emp_no,emp_name,salary,manager);
END;
MEMBER PROCEDURE display_records
IS
BEGIN
Dbms_output.put_line('Employee Name:'||emp_name);
Dbms_output.put_line('Employee Number:'||emp_no);
Dbms_output.put_line('Salary:'||salary);
Dbms_output.put_line('Manager:'||manager);
END;
END;
/

Code Пояснення

  • Code рядки 1-9: Створення об'єктного типу 'emp_object' з 4 атрибутами та 3 членами. Він містить визначення конструктора лише з 3 параметрами. (Фактичний неявний конструктор містить кількість параметрів, що дорівнює кількості атрибутів, присутніх у об'єктному типі.)
  • Code рядок 10: Створення тіла типу.
  • Code рядки 11-21: Визначення явного конструктора. Присвоєння значень параметрів атрибутам та призначення атрибуту 'manager' значення за замовчуванням '1001'.
  • Code рядки 22-26: Визначення члена 'insert_records', в якому значення атрибутів вставляються в таблицю 'emp'.
  • Code рядки 27-34: Визначення члена 'display_records', який відображає значення атрибутів типу об'єкта.

вихід:

Тип створений

Тіло типу створено

Крок 2) Створення анонімного блоку для виклику створеного типу об'єкта через неявний конструктор для emp_no 1005.

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

Анонімний блок викликає emp_object через неявний конструктор для emp_no 1005

DECLARE
guru_emp_det emp_object;
BEGIN
guru_emp_det:=emp_object(1005,'RRR',20000,1000);
guru_emp_det.display_records;
guru_emp_det.insert_records;
COMMIT;
END;

Code Пояснення

  • Code рядки 37-45: Вставка записів за допомогою неявного конструктора. Виклик конструктора містить фактичну кількість значень атрибутів.
  • Code рядок 38: Оголошує 'guru_emp_det' як об'єкт типу 'emp_object'.
  • Code рядок 41: Оператор 'guru_emp_det.display_records' викликає член 'display_records', і значення атрибутів відображаються.
  • Code рядок 42: Оператор 'guru_emp_det.insert_records' викликає член 'insert_records', і значення атрибутів вставляються в таблицю. Потім блок фіксує (фіксує) зміну. угода.

вихід:

Ім'я працівника: RRR

Кількість працівників: 1005

Зарплата: 20000

Менеджер: 1000

Крок 3) Створення анонімного блоку для виклику створеного типу об'єкта через явний конструктор для emp_no 1006.

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

Анонімний блок викликає emp_object через явний конструктор для emp_no 1006

DECLARE
guru_emp_det emp_object;
BEGIN
guru_emp_det:=emp_object(1006,'PPP',20000);
guru_emp_det.display_records;
guru_emp_det.insert_records;
COMMIT;
END;
/

Вихід

Employee Name:PPP 
Employee Number:1006 
Salary:20000 
Manager:1001

Code Пояснення:

  • Code рядки 46-53: Вставка запису за допомогою явного конструктора.
  • Code рядок 46: Оголошує 'guru_emp_det' як об'єкт типу 'emp_object'.
  • Code рядок 50: Оператор 'guru_emp_det.display_records' викликає член 'display_records', і значення атрибутів відображаються.
  • Code рядок 51: Оператор 'guru_emp_det.insert_records' викликає член 'insert_records', і значення атрибутів вставляються в таблицю. Оскільки передається лише три аргументи, явний конструктор встановлює ідентифікатор менеджера на значення за замовчуванням 1001.

Успадкування типу об’єкта

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

Тип підоб'єкта називається успадкованим типом об'єкта, а тип надоб'єкта — батьківським типом об'єкта. Синтаксис нижче показує, як створювати батьківські та успадковані типи об'єктів. На знімку екрана нижче показано синтаксис батьківського (SUPER) типу, позначений як NOT FINAL.

Синтаксис CREATE TYPE для батьківського типу об'єкта NOT FINAL, що використовується у спадкуванні

CREATE TYPE <object_type_name_parent> AS OBJECT
(
<attribute_l><datatype>,
.
.
)NOT FINAL;
/

Пояснення синтаксису:

  • Наведений вище синтаксис показує створення типу SUPER. Речення NOT FINAL дозволяє успадкування типу.

На скріншоті нижче показано успадкований синтаксис типу (SUB), створений за допомогою ключового слова UNDER.

Синтаксис CREATE TYPE UNDER для типу подібного об'єкта, що успадковується від батьківського

CREATE TYPE<object_type_name_sub>UNDER<object_type_name_parent>
(
<attribute_l><datatype>,
.
);
/

Пояснення синтаксису:

  • Наведений вище синтаксис показує створення типу SUB. Він містить усі члени та атрибути батьківського об'єктного типу.

Приклад 1: У наведеному нижче прикладі ми використовуємо властивість успадкування для вставки запису з ідентифікатором менеджера '1002' для запису ('RRR', 1007, 20000). Ми виконуємо програму, виконавши такі кроки.

  • Крок 1: Створіть тип SUPER.
  • Крок 2: Створіть тип і тіло SUB.
  • Крок 3: Створіть анонімний блок для виклику типу SUB.

Крок 1) Створіть тип SUPER або батьківський тип.

На скріншоті нижче показано створення супертипів emp_object за допомогою речення NOT FINAL.

Створення супертипу emp_object NOT FINAL для прикладу успадкування

CREATE TYPE emp_object AS OBJECT(
emp_no NUMBER,
emp_name VARCHAR2(50),
salary NUMBER,
manager NUMBER,
CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER,p_emp_name VARCHAR2(50),
p_salary NUMBER)RETURN SELF AS RESULT),
MEMBER PROCEDURE insert_records,
MEMBER PROCEDURE display_records)NOT FINAL;
/

Code Пояснення:

  • Code рядки 1-9: Створення об'єктного типу 'emp_object' з 4 атрибутами та 3 членами. Він містить визначення конструктора лише з 3 параметрами. Він був оголошений як 'NOT FINAL', тому є батьківським типом.

Крок 2) Створіть тип SUB під типом SUPER.

На скріншоті нижче показано успадкований тип sub_emp_object та його тіло, що створюється.

Створення успадкованого типу sub_emp_object та його тіла за допомогою insert_default_mgr

CREATE OR REPLACE TYPE sub_emp_object 
UNDER emp_object
(default_manager NUMBER,MEMBER PROCEDURE insert_default_mgr);
/


CREATE OR REPLACE TYPE BODY sub_emp_object 
AS
MEMBER PROCEDURE insert_default_mgr 
IS
BEGIN
INSERT INTO emp
VALUES(emp_no,emp_name,salary,manager);
END;
END;
/

Code Пояснення:

  • Code рядки 10-13: Створення 'sub_emp_object' як успадкованого типу з одним додатковим атрибутом 'default_manager' та оголошенням процедури-члена.
  • Code рядок 14: Створення тіла для успадкованого типу об'єкта.
  • Code рядки 16-21: Визначення процедури-члена, яка вставляє записи в таблицю 'emp' зі значеннями з об'єктного типу SUPER, за винятком значення manager. Для значення manager використовується 'default_manager' з типу SUB.

Крок 3) Створення анонімного блоку для виклику типу SUB.

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

Анонімний блок, що викликає тип sub_emp_object для вставки ідентифікатора менеджера за замовчуванням

DECLARE
guru_emp_det sub_emp_object;
BEGIN
guru_emp_det:= sub_emp_object(1007,'RRR',20000,1000,1002);
guru_emp_det.insert_default_mgr;
COMMIT;
END;
/

Code Пояснення:

  • Code рядок 25: Оголошення 'guru_emp_det' як типу 'sub_emp_object'.
  • Code рядок 27: Ініціалізація об'єкта за допомогою неявного конструктора. Конструктор має 5 параметрів (4 атрибути типу PARENT та 1 атрибут типу SUB). Останній параметр (1002) визначає значення атрибута default_manager.
  • Code рядок 28: Виклик члена 'insert_default_mgr' для вставки запису з ідентифікатором менеджера за замовчуванням, переданим у конструкторі.

Рівність об'єктів PL/SQL

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

Цей метод ORDER має бути функцією, яка повертає числовий тип. Він приймає два параметри на вхід (перший параметр: ідентифікатор екземпляра власного об'єкта; другий параметр: ідентифікатор іншого екземпляра об'єкта).

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

  • Додатне значення вказує на те, що екземпляр об'єкта SELF більший за інший екземпляр.
  • Від'ємне значення вказує на те, що екземпляр об'єкта SELF менший за інший екземпляр.
  • Нуль вказує на те, що екземпляр об'єкта SELF дорівнює іншому екземпляру.
  • Якщо будь-який з екземплярів має значення null, функція повертає значення null.

На скріншоті нижче показано синтаксис функції-члена ORDER, яку необхідно включити до тіла типу для перевірки рівності.

Синтаксис функції-члена ORDER, що використовується для порівняння екземплярів об'єктів на рівність

CREATE TYPE BODY<object_type_name_ 1>AS OBJECT
(
  ORDER MEMBER FUNCTION match(<parameter> object_type_name_ 1)
  RETURN INTEGER IS
  BEGIN
    IF <attribute_name>parameter <attribute_name>THEN
      RETURN -1; --any negative number will do
    ELSIF id>c.id THEN
      RETURN 1; --any positive number will do
    ELSE
      RETURN 0;
    END IF;
  END;
  .
  .
);
/

Пояснення синтаксису:

  • Наведений вище синтаксис показує функцію ORDER, яку необхідно включити до тіла типу для перевірки рівності.
  • Параметр для цієї функції має бути екземпляром того самого типу об’єкта.
  • Функцію можна викликати як “obj_instance_1.match(obj_instance_2)”, і цей вираз повертає показане числове значення, де obj_instance_1 та obj_instance_2 – це екземпляри об’єктного типу.

Приклад 1: У наступному прикладі ми порівнюємо два об'єкти. Ми створюємо два екземпляри та порівнюємо атрибут «зарплата» між ними. Ми робимо це у два кроки.

  • Крок 1: Створіть тип та тіло об'єкта.
  • Крок 2: Створіть анонімний блок для порівняння екземплярів об'єктів.

Крок 1) Створення типу та тіла об'єкта.

На скріншотах нижче показано специфікацію emp_object_equality та її тіло, яке визначає функцію ORDER, що порівнює атрибут salary.

Створення специфікації типу об'єкта emp_object_equality за допомогою функції ORDER Визначення тіла типу emp_object_equality, яке порівнює атрибут salary

CREATE TYPE emp_object_equality AS OBJECT(
salary NUMBER,
ORDER MEMBER FUNCTION equals(c emp_object_equality)RETURN INTEGER);
/
CREATE TYPE BODY emp_object_equality AS
ORDER MEMBER FUNCTION equals(c emp_object_equality)RETURN INTEGER 
IS
BEGIN
IF salary<c.salary
THEN RETURN -1;
ELSIF salary>c.salary
THEN RETURN 1;
ELSE
RETURN 0;
END IF;
END;
END;
/

Code Пояснення:

  • Code рядки 1-4: Створення об'єкта типу 'emp_object_equality' з 1 атрибутом та 1 членом.
  • Code рядки 6-16: Визначення функції ORDER, яка порівнює атрибут 'salary' екземпляра SELF та екземпляра параметра. Вона повертає від'ємне значення, якщо зарплата SELF менша, додатне значення, якщо зарплата SELF більша, та 0, якщо зарплати рівні.

Code вихід:

Тип створений

Крок 2) Створення анонімного блоку для порівняння екземплярів об'єктів.

На скріншоті нижче показано анонімний блок, який порівнює два екземпляри emp_object_equality за зарплатою.

Анонімний блок, що порівнює два екземпляри emp_object_equality за зарплатою

DECLARE
l_obj_1 emp_object_equality;
l_obj_2 emp_object_equality;
BEGIN
l_obj_1:=emp_object_equality(15000); 
l_obj_2:=emp_object_equality(17000);
IF l_obj_1.equals(l_obj_2)>0
THEN
Dbms_output.put_line('Salary of first instance is greater');
ELSIF l_obj_1.equals(l_obj_2)<0
THEN
Dbms_output.put_line('Salary of second instance is greater'); 
ELSE
Dbms_output.put_line('Salaries are equal');
END IF;
END;
/

Вихід

Salary of second instance is greater

Code Пояснення:

  • Code рядок 20: Оголошення 'l_obj_1' типу 'emp_object_equality'.
  • Code рядок 21: Оголошення 'l_obj_2' типу 'emp_object_equality'.
  • Code рядок 23: Ініціалізація 'l_obj_1' значенням зарплати '15000'.
  • Code рядок 24: Ініціалізація 'l_obj_2' значенням зарплати '17000'.
  • Code рядки 25-33: Друк повідомлення на основі числа, повернутого функцією ORDER.

Поширені запитання

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

Обидва порівнюють екземпляри об'єктів. Метод MAP повертає одне скалярне значення, яке Oracle використовується для сортування або порівняння об'єктів, тоді як метод ORDER порівнює два екземпляри безпосередньо та повертає від'ємне, нульове або додатне число. Тип може визначати один або інший, але не обидва обидва.

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

Тип NOT INSTANTIABLE не може створювати об'єкти безпосередньо; він діє як аб'єкт ABS.tracбаза, яку розширюють інші типи. У поєднанні з NOT FINAL він визначає супертип, підтипи якого забезпечують конкретну реалізацію його оголошених методів.

Використовуйте ALTER TYPE для додавання або видалення атрибутів і методів, CASCADE для оновлення залежних об'єктів та DROP TYPE для видалення типу. Тип, який все ще використовується таблицями або іншими типами, не можна видалити, доки ці залежні об'єкти не будуть оброблені спочатку.

Здійснюйте запити до представлень словника даних USER_TYPES та ALL_TYPES щодо імен типів, а також до USER_TYPE_ATTRS та USER_TYPE_METHODS щодо їхніх атрибутів та методів. Ці представлення дозволяють перевіряти існуючу об'єктну модель без читання вихідного коду.

Так. Копілот GitHub створює специфікації CREATE TYPE, методи TYPE BODY, конструктори та функції ORDER з коментаря. RevПерегляньте типи даних атрибутів, параметри конструктора та речення успадкування перед розгортанням згенерованого типу.

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

Підсумуйте цей пост за допомогою: