Class
class Box<T> {
class EmailAddress {
</syntaxhighlight> Добрий service class має чітку відповідальність.; } Проста аналогія: class — це форма для печива, object — конкретне печиво, яке з цієї форми зробили.; * `User`;
- `Order`;
- `Invoice`;
- `PaymentGateway`;
- `EmailSender`;
- `Cart`;
- `Money`;
- `DateRange`;
- `UserRepository`;
- `PasswordResetService`.;
Приклад checklist для Class
God Class
Приклад:
const user = await userService.findUser(request.params.id);
істотно: property виглядає як інформаційні дані, але іноді за нею має змогу стояти логіка.; info(message: string) {
class EmailAddress {
class User:
deposit(amount: number) {
Class і Struct
console.log(MathUtils.double(5));
EmailSender class
public class User {
;* конфлікти методів;
* diamond problem;
* складніша логіка lookup;
* важче читати код;
* несподівана поведінка.; Class описує конкретний тип об’єкта.; Іноді це без ускладнень складність у костюмі дизайну.; Якщо назва туманна, клас уже важче зрозуміти.;<syntaxhighlight lang="python">
std::string name;
'''Практична порада:''' controller не має містити всю бізнес-логіку.; TypeScript додає до JavaScript classes типи й access modifiers.; Інакше subclass має змогу ламати код, який функціонує з base class.; * collections;
* repositories;
* wrappers;
* result types;
* API responses;
* reusable data structures.; це шаблон, характеристика або модель; додатково реалізовано які об’єкт зберігає, і поведінка, яку він має змогу виконувати виступає ключовою рисою створення об’єктів у програмуванні.; }
Добрий domain class містить не тільки поля, а й поведінку, яка має сенс у бізнесі.;</div>
'''Mutable class''' надає можливість змінювати стан object після створення.; |-
| Class
| Шаблон для створення об’єктів
|-
| Module
| Організаційна одиниця коду або namespace
|}
Ознаки:
}
class CreateUserDto {
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
'''Class/static method''' викликається на самому класі.; }
Сильний клас має чітку відповідальність, зрозумілу назву, захищає свій стан, підтримує роботу invariants і не робить зайвого.; }
<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
</div>
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
* давати класам точні назви;
* тримати одну основну відповідальність;
* приховувати internal state;
* робити objects валідними після constructor;
* не створювати God classes;
* не будувати глибокі inheritance trees без потреби;
* надавати маленький public interface;
* використовувати composition, коли inheritance зайве;
* писати tests для важливих methods;
* не змішувати domain logic і infrastructure без потреби;
* захищати invariants;
* використовувати immutable objects там, де це доречно;
* передавати dependencies через constructor;
* не використовувати static state без потреби.;<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
Приклад Java:
private status: "draft" | "paid" | "cancelled" = "draft";
== DTO Class ==
private String name;
addItem(item: string) {
</div>
private items: string [] = [];
print("Sound")
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
Приклад:
<syntaxhighlight lang="typescript">
Клас часто поєднує '''state''' і '''behavior'''.; Processor
}
!; ) {
Краще:
У domain-driven design клас має змогу представляти поняття предметної області.; Суть
}
'''Value object''' — об’єкт, який визначається значенням, а не identity.;<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
Поширено в Kotlin.; Код, який викликає `send`, не мусить знати всі деталі SMTP, retries, templates або provider API.; У багатьох системах composition дає гнучкіший дизайн.;</div>
+ changeEmail()
'''Inheritance''' або '''наслідування''' надає можливість одному класу успадковувати властивості й методи іншого класу.; // cannot be subclassed
'''Interface''' описує контракт, а class реалізує поведінку.; }
public price: number
</div>
public readonly amount: number,
== Base Class і Derived Class ==
</div>
}
'''Nested class''' — клас, оголошений всередині іншого класу.;== Class у Ruby ==
'''Практична порада:''' nested class корисний, коли тип має сенс тільки в контексті зовнішнього класу.; class UserController {
</div>
Ruby classes підтримують:
Практична роль: method відповідає на питання: “Що цей об’єкт має змогу робити?” Приклад: Помилка: більше класів не означає кращу архітектуру.; * Data classes і records з’явилися, щоб прибрати boilerplate для простих data containers.; Погано спроєктований клас має змогу зробити код складнішим.; User class DataManager { Favor composition over inheritance self.balance = balance class User: Приклад: def __init__(self, name): } Приклад: Invariant — правило, яке має залишатися істинним для об’єкта протягом його життя.; class BankAccount: Repository Class</syntaxhighlight> Це має змогу бути корисно для: } return this._name; class Car extends Vehicle { | |
|---|---|
| C++ | `class` має private members за замовчуванням, `struct` — public |
| C# | class — reference type, struct — value type |
| Swift | class — reference type, struct — value type |
return "Hello, " + name;
Приклад Python: class Cat {
class Circle extends Shape {
</div>
<syntaxhighlight lang="typescript">
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
}
constructor(name) {
'''Практична роль:''' mixin надає можливість додавати “домішки” поведінки без створення великої inheritance tree.; {| class="wikitable"
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
if (!value) {
Ризики:
describe() {
</syntaxhighlight>
this._name = value; def speak(self):
істотно: якщо клас не проєктувався для inheritance, іноді краще явно заборонити наслідування.;== Inheritance vs Composition ==
}
void speak() {
- fields;
- properties;
- methods;
- constructor;
- access modifiers;
- static members;
- inheritance rules;
- validation logic;
- business behavior;
- internal state;
- relationships with other classes.; constructor(
Method Overriding
істотно: ООП не означає автономно хороший дизайн.; Цікавий момент: хороший клас — це не без ускладнень “коробка для даних”, а охоронець правил, за якими ці інформаційні дані можуть змінюватися.;</syntaxhighlight>
- reusable behavior;
- logging;
- serialization;
- validation;
- permissions;
- UI behavior;
- shared methods.;== Недоліки і ризики Class ==
Class diagram — UML-діаграма, яка показує класи, fields, methods і relationships.; class Dog(Animal): Тут `User` — клас, а `anna` і `oleh` — об’єкти.; Клас має змогу бути зайвим, якщо:
status: string; def __init__(self, balance):
{
Module часто групує functions, classes, constants або types.; Класи є собою фундаментальним поняттям ООП і використовуються для моделювання domain entities, services, repositories, controllers, value objects, UI components і багатьох інших частин програм.;</syntaxhighlight> Controller має змогу: істотно: не кожен клас має бути “розумним”, але domain entity без поведінки часто втрачає сенс ООП.; self.name = name
Цікавий факт: у Python класи самі є собою об’єктами, з цієї причини їх можна передавати, змінювати й створювати динамічно.; Поширені modifiers: переважні аспекти immutable classes:
Чи не є собою це God class?; Функція `makeSound` не знає, чи отримала Dog, Cat або інший об’єкт.; істотно: не треба робити клас лише з цієї причини, що “так серйозніше виглядає”.;
}
</syntaxhighlight>
return "Meow";
speak() {
drive() {
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
<syntaxhighlight lang="java">
'''Object-Oriented Programming''' або '''ООП''' — стиль програмування, у якому програма моделюється через objects, classes і взаємодію між ними.;== Polymorphism ==
<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
Чи захищені invariants?; Поширено в Java та деяких інших мовах.; * У Ruby майже все є собою object, навіть числа й класи.; Приклад TypeScript:
* `dataclass` у Python;
* `record` у C#;
* `data class` у Kotlin;
* `case class` у Scala;
* `record` у Java;
* `struct` у Swift.; Ризик
</div>
</div>
) {}
</div>
== Class у TypeScript ==
* types;
* interfaces;
* access modifiers;
* generics;
* abstract classes;
* decorators у частині сценаріїв;
* readonly fields;
* parameter properties.; Приклад ідеї:
- email
data: any;
<syntaxhighlight lang="text">
* простіше reasoning;
* безпечніше в concurrency;
* менше side effects;
* легше тестувати;
* стабільні value objects.; Це спосіб моделювати систему через відповідальності, межі й поведінку.; Клас `GameCharacter` зберігає health, position, inventory і methods для movement або actions.; return $"Hello, {Name}";
end
<syntaxhighlight lang="javascript">
class User:
- легше тестувати;
- легше замінювати реалізації;
- менше hardcoded dependencies;
- чистіша технічна архітектура;
- краще separation of concerns.; }
class User end
send(to: string, message: string): Promise<void>
class User {
email: string;
return `Hello, ${this.name}`;
class Product {
}
return f"Hello, {self.name}"
<div style="background:#f0eaff; border-left:6px solid #8e44ad; padding:12px; margin:12px 0;">
Utils
Клас `User` зберігає identity, email, name і методи для зміни профілю.; Слабкий клас має змогу перетворитися на God class, зайву abstraction або без ускладнень контейнер без сенсу.; C# classes підтримують:
}
`Dog` наслідує `Animal` і змінює поведінку `speak`.;<syntaxhighlight lang="typescript">
greet() {
area() {
}
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
<div style="background:#e8f8f5; border-left:6px solid #16a085; padding:12px; margin:12px 0;">
== Controller Class ==
}
console.log(animal.speak());
abstract area(): number;
* Матеріали з object-oriented programming щодо classes, objects, inheritance, encapsulation, polymorphism і abstraction.; name: string;
</div>
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
def __init__(self, name):
}
Приклади:
== Class у Python ==
</div>
</div>
Підтримується в деяких мовах, як ілюстрація C++ і Python.;<syntaxhighlight lang="java">
Order
def greet
=== User class ===
Підказка: хороший class зазвичай можна пояснити одним реченням: “Цей клас відповідає за…” Runnable task = new Runnable() { Anemic class або anemic domain model — клас, який майже не має поведінки й лише зберігає інформаційні дані.; {| class="wikitable"
private engine: Engine,
- User;
- Order;
- Invoice;
- Customer;
- Product;
- Account;
- Project.; Чи без зайвих зусиль написати tests?; Це комфортно, але не варто робити приховану складну роботу без потреби.; * Документація мов програмування Java, C#, C++, Python, JavaScript, TypeScript, Ruby, Kotlin і Swift щодо class syntax і object model.; Клас варто створювати, якщо:
переважні аспекти Class
}
}
Method — функція, яка належить класу або об’єкту.; console.log(message);
Чи прихований internal state?; InvoiceGenerator
'''істотно:''' SRP не означає “один метод на клас”.; '''Практична роль:''' у C# class часто є собою основним способом моделювання domain logic, services, entities і application components.;</div>
}
count = 0
'''Mixin''' — спосіб додати класу поведінку без класичного глибокого inheritance.; }
== Access Modifiers ==
'''Immutable class''' — клас, об’єкти якого не змінюються після створення.; greet(): string {
</div>
Приклад:
}
</div>
Приклад:
Чи має клас зрозумілу назву?; * classes;
* interfaces;
* inheritance;
* access modifiers;
* constructors;
* static members;
* annotations;
* generics;
* packages.; class UserService {
'''Практична роль:''' checklist сприяє відрізнити корисний клас від зайвого архітектурного шуму.; * Матеріали щодо refactoring, class design, UML class diagrams, composition over inheritance і testing object-oriented code.; Ruby є собою дуже об’єктно-орієнтованою мовою: майже все є собою об’єктом.; '''Головна думка:''' class — це не без ускладнень синтаксис мови.; }
interface Logger {
</syntaxhighlight> Constructor зазвичай: Практична роль: value object надає можливість сховати правила й validation у маленькому класі замість розкидати їх по всьому коду.; class UserRepository {
Тематичні мітки
await this.emailSender.send(user.email, "Welcome");
TypeScript classes можуть використовувати:
Приклад: Service class містить логіку, яка не належить природно одному entity або value object.; * У JavaScript class syntax виглядає класично, але базується на prototypes.; }
Mixin
- `self`;
- dynamic attributes;
- inheritance;
- magic methods;
- dataclasses;
- class variables;
- properties;
- multiple inheritance;
- duck typing.; }
total: number;
Приклади:
Практична порада: якщо ви постійно передаєте разом ті самі інформаційні дані й функції, можливо, вони просяться в клас.; Клас `EmailSender` приховує деталі SMTP або external API й дає простий method `send`.; if (!value.includes("@")) {
істотно: service class без зайвих зусиль перетворити на “мішок логіки”.;Приклад:
class User {
const stringBox = new Box<string>("hello");
=== GameCharacter class ===
@classmethod
print("Woof")
'''Практична роль:''' anonymous class зручний для короткої одноразової реалізації interface або abstract class.; * state — інформаційні дані об’єкта;
* behavior — дії об’єкта.;<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
== Class і Dependency Injection ==
if (!value.includes("@")) {
abstract class Shape {
Це не завжди погано: DTO або simple data class можуть бути anemic навмисно.; }
private emailSender: EmailSender,
Приклад:
'''Головне правило:''' хороший клас має бути зрозумілим за назвою, безпечним у використанні й обмеженим у відповідальності.;== Abstraction ==
constructor(private radius: number) {
return cls.count
}
) {}
private balance = 0;
// database write
Final Class
`greet` функціонує з конкретним user, а `total_users` — з class-level state.;== Service Class ==
- має чітку відповідальність;
- має зрозумілу назву;
- приховує внутрішній стан;
- не робить забагато;
- захищає invariants;
- без зайвих зусиль тестується;
- має невеликий public interface;
- не залежить від усього підряд;
- відповідає предметній області.; constructor(
const user = await this.userRepository.findById(userId);
- id
PaymentGateway class
Manager Property — властивість об’єкта.;== Див.; додатково ==
- безпеки;
- стабільності API;
- performance optimization у частині мов;
- заборони неправильного extension;
- immutable value objects.; // unclear responsibility
Особливості Python classes:
- PaymentService;
- EmailService;
- ReportService;
- OrderPricingService;
- AuthService;
- NotificationService.;
- є собою стан і поведінка;
- потрібні invariants;
- є собою domain entity;
- потрібно кілька пов’язаних methods;
- потрібна polymorphism;
- потрібна lifecycle-логіка.; Приклад, де клас зайвий:
Class і Object
- є собою проста операційна дія;
- немає складного стану;
- логіка чиста;
- потрібне перетворення даних;
- немає потреби створювати object.; Приклад:
return Math.PI * this.radius * this.radius;
}
</syntaxhighlight>
У цьому прикладі `name` і `email` — fields.; Composition — підхід, де клас використовує інші об’єкти як частини, замість надмірного наслідування.;- properties;
- methods;
- interfaces;
- inheritance;
- generics;
- access modifiers;
- records;
- partial classes;
- attributes;
- async methods.;== Приклади сценаріїв використання ==
if (amount < 0) {
throw new Error("Amount cannot be negative");
}
}
} </syntaxhighlight>
response.json(user);
public string Name { get; set; }
{
- сотні або тисячі рядків;
- багато unrelated methods;
- багато dependencies;
- важко тестувати;
- важко змінювати;
- клас застосовується всюди;
- назва типу `Manager`, `System`, `AppService`;
- будь-яка зміна ризикована.; Поняття
} Приклади:
Приклад ідеї:
Name = name;
Polymorphism або поліморфізм надає можливість працювати з різними об’єктами через спільний інтерфейс або base class.;
Composition
- `public`;
- `private`;
- `protected`;
- `internal`;
- `readonly`;
- `static`;
- package-private у частині мов.;</syntaxhighlight>
!; Class design — бізнес-процес визначення, за що клас відповідає, які має fields, methods і relationships.;
Приклад JavaScript:
- є собою сутність із state і behavior;
- потрібно захистити invariants;
- є собою domain concept;
- є собою кілька пов’язаних methods;
- потрібно створювати багато instances;
- потрібен polymorphism;
- потрібне dependency injection;
- потрібне приховування details;
- є собою lifecycle або rules;
- проста структура даних уже не справляється.; Якщо об’єкт одразу після створення “напівзламаний”, клас спроєктований слабко.; * Найкращий клас часто має менше methods, ніж хочеться додати на старті.; Це спосіб дати програмній сутності ім’я, стан, правила й поведінку.;== Приклад хорошого Class ==
} // database query
Entity class — клас, який має identity й життєвий цикл.;
throw new Error("Invalid email");
}
String name;
function makeSound(animal: { speak(): string }) {
Чи не є собою це зайвою обгорткою над однією функцією?; Клас є собою одним із ключових понять object-oriented programming або ООП.; !; constructor( };
constructor(name) {
* validation;
* computed properties;
* controlled access;
* backward compatibility;
* hiding internal representation.; }
Приклад:
Приклад C#:
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
== Anonymous Class ==
}
</div>
== Class Naming ==
this.engine.start();
- status
== Anemic Class ==
console.error(message);
}
<div style="background:#f0eaff; border-left:6px solid #8e44ad; padding:12px; margin:12px 0;">
!; * приймає початкові інформаційні дані;
* ініціалізує fields;
* перевіряє параметри;
* встановлює default values;
* готує object до роботи.;</div>
Чи немає зайвого inheritance?;<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
`user` — instance класу `User`.; Суть
</div>
<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
* ім’я користувача;
* ціна товару;
* баланс акаунта;
* статус замовлення;
* дата створення;
* координати персонажа;
* рівень доступу.; Property має змогу:
</div>
== Приклад слабкого Class ==
<syntaxhighlight lang="text">
== Constructor ==
{| class="wikitable"
</div>
markAsPaid() {
class ConsoleLogger implements Logger {
Коли Class має змогу бути зайвим
</syntaxhighlight> Помилка: клас із назвою `Manager` часто приховує те, що команда ще не зрозуміла справжню відповідальність.; PasswordResetService
Основна ідея: class — це шаблон для створення об’єктів, який об’єднує стан і поведінку в одну зрозумілу модель.;}
Class у Java
Abstract Class
{
'''Практична роль:''' immutable class схожий на запечатаний документ: після створення його зміст не змінюється.; Чи можна пояснити відповідальність одним реченням?; '''Class''' і '''object''' — пов’язані, але різні поняття.; Проблема виникає, коли domain logic розкидана по services, а domain classes не захищають власні правила.; constructor(name) {
Чи public methods справді потрібні?; Підхід
== Instance ==
* encapsulation;
* abstraction;
* inheritance;
* polymorphism.; '''істотно:''' constructor має створювати валідний об’єкт.; Погано:
C# активно використовує classes у .NET-екосистемі.;== Sealed Class ==
!; }
return this.value.split("@")[1];
* нечітка назва;
* `any`;
* багато незрозумілих methods;
* немає явної відповідальності;
* важко тестувати;
* важко підтримувати.; }
'''Проста ідея:''' inheritance надає можливість сказати: “Dog — це особливий вид Animal”.;</div>
* має зрозумілу назву;
* захищає invariant;
* є собою immutable;
* має корисну behavior;
* не робить зайвого.; if (amount <= 0) {
throw new Error("Amount must be positive");
}
this.balance += amount;
}
getBalance() {
return this.balance;
}
}
Головне правило: клас має бути достатньо маленьким, щоб його можна було зрозуміти, і достатньо змістовним, щоб він не був зайвою обгорткою.; як ілюстрація, клас `User` описує, які поля й методи має користувач системи, а конкретний користувач системи Anna або Oleh є собою об’єктом цього класу.; * Іноді найкраще покращення класу — видалити його й залишити просту функцію.; !; God class — антипатерн, коли один клас знає й робить занадто багато.; !; Різниця |- | public | доступний ззовні |- | private | доступний тільки всередині класу |- | protected | доступний у класі й subclasses |- | readonly | значення не можна змінювати після ініціалізації у частині мов |}
}
speak() {
class BankAccount {
- надсилає email
Generics корисні для:
* balance не має змогу бути меншим за 0;
* email має бути валідним;
* order total не має змогу бути від’ємним;
* start date не має змогу бути пізніше end date;
* user role має бути однією з дозволених;
* cart item quantity має бути більшою за 0.; * prototypes;
* `this`;
* constructor;
* class fields;
* private fields;
* static methods;
* inheritance через `extends`.; У наслідуванні є собою:
'''Method overriding''' — коли subclass замінює реалізацію методу з parent class.; }
|-
| Interface
| Що об’єкт має вміти
|-
| Class
| Як саме це реалізовано
|}
class Counter:
<div style="background:#f0eaff; border-left:6px solid #8e44ad; padding:12px; margin:12px 0;">
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
- зберігає в database
const phone = new Product("Phone", 500);
Приклад:
class Cart {
public User(String name) {
== Getter і Setter ==
'''Sealed class''' обмежує, які класи можуть її наслідувати.;<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
'''Field''' — змінна, яка належить об’єкту або класу.; Це потужно, але потребує обережності.; '''Практична роль:''' назва класу — це перша документація.; Цей клас:
Python підтримує роботу класи, але має більш динамічну модель.; Якщо ім’я вибрано добре, код починає читатися майже як мова задачі.; Приклад
class User
Приклади:
Чи зрозуміє цей клас інший розробник через місяць?; !;<syntaxhighlight lang="kotlin">
EmailSender
* stateful objects;
* UI components;
* game objects;
* sessions;
* accumulators;
* workflows;
* domain entities.;
Getters і setters корисні для:
- overengineering;
- God class;
- class explosion;
- складна inheritance tree;
- tight coupling;
- mutable state bugs;
- hidden side effects;
- boilerplate;
- складне тестування при поганих dependencies;
- надмірні abstractions;
- неправильне моделювання domain;
- плутанина між class і data structure.; console.log("Moving");
Anonymous class — клас без імені, який створюється прямо на місці використання.; }
Приклад TypeScript:
У цьому прикладі `items` — state, а `addItem` і `countItems` — behavior.;<syntaxhighlight lang="javascript">
// unknown behavior
constructor(public value: T) {}
<syntaxhighlight lang="typescript">
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
як ілюстрація, клас `EmailSender` має змогу мати метод:
!; }
* constructors;
* destructors;
* copy/move semantics;
* operator overloading;
* templates;
* inheritance;
* virtual methods;
* RAII;
* access control.; Коли корисний
Класи є собою важливою частиною ООП, але ООП — це не без ускладнень “створити багато класів”.; UserManager:
== Immutable Class ==
- рахує billing
== Interface і Class ==
super();
Чи не краще використати composition?; ) {} class Failed(val reason: String) : PaymentResult() public:
Клас `Order` має items, status, total і методи `addItem`, `markAsPaid`, `cancel`.; Окремо варто відзначити Java, C# і інших мовах.; Клас має змогу захищати invariants через constructor, methods і access modifiers.; class Order {
У Java класи є собою центральним елементом мови.; як ілюстрація, у реальному світі “автомобіль” — це клас, а конкретна машина біля будинку — об’єкт.; Часто краще делегувати її service або domain layer.; * повторне використання поведінки;
* гнучкі ієрархії;
* mixin-подібні patterns.; Він означає одну зрозумілу відповідальність.; '''Практична роль:''' замість передавати email як простий string всюди, клас `EmailAddress` робить правило валідності явним.; Не варто переносити правило з C++ напряму в C# або Swift.; '''істотно:''' JavaScript classes виглядають схоже на Java або C#, але модель мови має власні особливості.; '''Головна перевага:''' клас сприяє перетворити розрізнені інформаційні дані й функції на зрозумілу програмну сутність.;<div style="background:#e8f8f5; border-left:6px solid #16a085; padding:12px; margin:12px 0;">
</div>
set name(value) {
'''Abstraction''' або '''абстракція''' у класах означає виділення суттєвого й приховування деталей.; У деяких мовах є собою і `class`, і `struct`.; !;
ReportExporter
public final class Money { } - id
}
Generic class — клас, який функціонує з типом як параметром.; void speak() {
- helper objects;
- тісно пов’язаних типів;
- builders;
- iterators;
- implementation details;
- logical grouping.;== Class у C# ==
honk() {
info(message: string): void;
істотно: private — це не без ускладнень “сховати від очей”, а спосіб зберегти invariants класу.; @name = name
Якщо об’єкт — це конкретна річ у програмі, то клас — це креслення, за яким такі речі створюються.; Цікавий факт: у Ruby можна “відкрити” існуючий клас і додати до нього методи.; public User(string name)
Instance або екземпляр — це конкретний об’єкт, створений на основі класу.;== Object-Oriented Programming == </syntaxhighlight>
Instance method викликається на конкретному об’єкті.; } sealed class PaymentResult Практична роль: class diagram сприяє побачити структуру системи до або під час реалізації.; + markAsPaid()
from dataclasses import dataclass
Практична роль: entity class моделює сутність із власною ідентичністю, правилами й історією змін.; class Animal { Основні принципи ООП: }
`deposit` — method.;
return "Woof";
public name: string,
</syntaxhighlight>
- `calculateTotal`;
- `sendEmail`;
- `approveOrder`;
- `withdraw`;
- `render`;
- `validate`;
- `save`;
- `move`;
- `login`.; * Глибока inheritance tree має змогу виглядати красиво на діаграмі, але бути дуже болючою в підтримці.; throw new Error("Invalid email address");
'''істотно:''' у C++ class часто керує не тільки логікою, а й ресурсами: пам’яттю, файлами, locks або handles.;<syntaxhighlight lang="python">
<syntaxhighlight lang="ruby">
C++ classes можуть включати:
id: str
self.name = name
Class Diagram
Головна ідея ООП: інформаційні дані й поведінка, які логічно належать одній сутності, можуть жити разом.; Поняття
- створювати class для кожної маленької функції;
- робити всі fields public;
- не використовувати constructor для валідного стану;
- писати God class;
- називати класи `Manager` і `Helper`;
- надмірно використовувати inheritance;
- не розуміти різницю між class і object;
- плутати static і instance members;
- зберігати global state у static fields;
- не тестувати behavior;
- робити getters/setters для всього без логіки;
- змішувати database, UI і business logic в одному класі;
- копіювати Java-style classes у мову, де простіше використати functions.; істотно: не кожна функція має ставати класом.; І не кожен клас має існувати, якщо достатньо простої функції.; if (this.status !== "draft") {
!; this._name = name;
}
Constructor — спеціальний метод, який викликається під час створення об’єкта.;</syntaxhighlight> істотно: inheritance зручне, але його без зайвих зусиль переоцінити.; Класи використовуються в багатьох мовах: </syntaxhighlight>
Клас або interface `PaymentGateway` описує спосіб приймати платежі, а конкретні реалізації працюють із Stripe, PayPal або іншим provider.; } const user = new User("Anna");
self.name = name
Приклад:
async save(user: User): Promise<void> {
- організація коду;
- моделювання предметної області;
- поєднання state і behavior;
- encapsulation;
- reuse;
- polymorphism;
- abstraction;
- testability у хорошому дизайні;
- супровід великих систем;
- зрозумілі APIs;
- type safety у типізованих мовах;
- контроль invariants;
- можливість inheritance або composition.;== Class і Module ==
Single Responsibility Principle
def initialize(name)
Value Object Class
public string Name { get; }
} Основні переважні аспекти класів: class Success(val id: String) : PaymentResult() class Order {
Order class
</syntaxhighlight>
return `Hello, ${this.name}`;
У деяких мовах є собою спеціальні конструкції для класів, які переважно зберігають інформаційні дані.; ) {} BillingService
handle() {
Слабкі назви: - створює користувачів
Найлюдяніший факт: клас — це спосіб дати частині програми ім’я, пам’ять і поведінку.; Приклад:
'''Module''' і '''class''' теж різні.;<syntaxhighlight lang="typescript">
</div>
class Money { Composition часто формулюють як:
Fields описують стан об’єкта:
Mutable classes корисні для:
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
== State і Behavior ==
def __init__(self):
`Vehicle` — base class, `Car` — derived class.; '''Практична порада:''' не використовуйте setter, якщо зміна значення має складну бізнес-логіку.; def greet(self):
<syntaxhighlight lang="typescript">
DTO має змогу використовуватися для:
Практична роль: abstraction надає можливість користуватися класом через зрозумілий public interface, не занурюючись у внутрішню реалізацію.; User.count += 1
|-
| Class
| Шаблон або характеристика
| `User`
|-
| Object
| Конкретний екземпляр класу
| користувач системи Anna з email `anna@example.com`
|}
'''істотно:''' overriding має зберігати очікуваний контракт методу.; System.out.println("Meow");
Приклад:
}
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
end
* `Order`;
* `Customer`;
* `Invoice`;
* `Payment`;
* `Shipment`;
* `Product`;
* `Subscription`;
* `Account`;
* `Booking`.; class User:
* один простий use case розкиданий по 15 класах;
* багато classes мають по одному методу;
* назви стають штучними;
* важко знайти реальну логіку;
* абстракції створені “про запас”;
* code navigation стає болючою.; public void run() {
'''Repository class''' приховує доступ до даних і надає доменний інтерфейс для збереження або пошуку objects.; Назва класу має пояснювати, що він представляє або робить.;== Загальний характеристика ==
== Class Explosion ==
PaymentCaptureService
Invariant
std::string greet() {
Ознаки:
}
Цікаві факти про Class
return `Area: ${this.area()}`;
'''Static members''' належать класу, а не конкретному object instance.; Суть
!; class Vehicle {
== Хороші практики Class ==
'''Практична роль:''' sealed class надає можливість моделювати закритий набір станів або результатів без випадкових сторонніх subclasses.; Інакше ієрархія оперативно стає заплутаною.; з цієї причини головне — не без ускладнень створювати класи, а моделювати ними реальні поняття й відповідальності системи.; Якщо потрібен лише контракт, interface часто простіший.;</div>
</div>
anna = User("Anna")
Приклад:
}
Приклад ідеї:
Приклад:
}
'''Class''' — це шаблон для створення об’єктів, який описує їхній стан, поведінку, правила й взаємодію з іншими частинами системи.; '''Практична роль:''' у Java майже весь application code організовується навколо classes.; У класі зазвичай визначаються інформаційні дані забезпечується через '''Class''' або '''клас'''.; '''Controller class''' часто застосовують, коли потрібно в web frameworks для обробки HTTP-запитів.; Їй істотно, що є собою метод `speak`.; Поганий ООП-код має змогу бути таким самим хаотичним, як і поганий процедурний код.;<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
<syntaxhighlight lang="typescript">
doStuff() {
return this.items.length;
== Class у JavaScript ==
<syntaxhighlight lang="cpp">
Class і Record/Data Class
Класи можуть створювати проблеми.;</syntaxhighlight>
}
public class User
JavaScript має class syntax, але під капотом використовує prototype-based inheritance.; process() {
throw new Error("Only draft orders can be paid");
this.status = "paid";
Access modifiers визначають, хто має змогу бачити або змінювати members класу.; {| class="wikitable"
Entity Class
// does many unrelated things
- читати значення;
- змінювати значення;
- виконувати validation;
- обчислювати значення;
- приховувати внутрішнє поле.; }
}
}
static double(value: number) {
Клас зазвичай містить: class User {
} Практична роль: polymorphism надає можливість писати код, який функціонує з поведінкою, а не з конкретною реалізацією.; throw new Error("Name is required"); </syntaxhighlight>
class MathUtils {
Приклади:
- inheritance;
- composition;
- aggregation;
- associations;
- interfaces;
- dependencies;
- visibility;
- multiplicity.;</syntaxhighlight>
Приклад: Helper Service
}
oleh = User("Oleh")
Корисно, коли потрібно описати обмежений набір варіантів:
id: string; return "Hello, " + name;
Abstract class — клас, який не призначений для створення об’єктів напряму, а задає спільну основу для subclasses.; constructor(
</div>
<syntaxhighlight lang="typescript">
'''Перевага:''' клас надає можливість зібрати пов’язані інформаційні дані й дії разом, щоб код був організованішим і ближчим до реальної моделі задачі.; Поняття
'''істотно:''' mutable state не є собою злом, але його потрібно контролювати через methods і invariants.; class Car {
}
}
Приклад:
}
</div>
'''Практична роль:''' TypeScript class надає можливість поєднати JavaScript runtime-модель із compile-time перевіркою типів.; У такому випадку краще названий method, як ілюстрація `changeEmail`.;== Class у C++ ==
private brakes: Brakes
Класи й функції — різні способи організації логіки.; async welcomeUser(userId: string) {
System.out.println("Running");
error(message: string): void;
{| class="wikitable"
== Generic Class ==
застосовується для:
}
<div style="background:#f0eaff; border-left:6px solid #8e44ad; padding:12px; margin:12px 0;">
<div style="background:#fdecea; border-left:6px solid #e74c3c; padding:12px; margin:12px 0;">
class Animal:
{
'''істотно:''' різниця між class і struct залежить від мови.; * приймати request;
* викликати service;
* повертати response;
* робити validation;
* обробляти errors;
* керувати routing у частині frameworks.;== Multiple Inheritance ==
== Method ==
Приклад:
'''Практична роль:''' dependency injection надає можливість класу не створювати всі залежності самому, а отримувати їх як готові інструменти.; Приклад:
Чи має клас валідний стан після constructor?; error(message: string) {
private id: string,
}
constructor(
</div>
Приклад спрощено:
}
Можливі ризики:
</div>
'''Практична роль:''' base class задає спільну поведінку, а derived class уточнює або розширює її.;<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
Приклади entities:
== Class і Domain Model ==
Краще:
constructor(public readonly value: string) {
InvoiceCalculator
System.out.println("Sound");
Methods описують поведінку:
}
переважні аспекти:
UserService
- SQL;
- ORM;
- database driver;
- cache;
- mapping rows to objects;
- persistence details.; Class diagram має змогу показувати:
self.value = 0 this.name = name;
'''Небезпека:''' найчастіша помилка — думати, що ООП означає “все має бути класом”.;<syntaxhighlight lang="typescript">
У C++ class схожий на struct, але за замовчуванням members у class є собою private.; def greet(self):
'''Цікавий момент:''' сильний domain class не без ускладнень “має status”, а знає, коли цей status можна змінити.; '''Dependency injection''' — передача залежностей класу ззовні, часто через constructor.;</div>
Class і Function
Приклад TypeScript:
Java активно використовує:
self.balance += amount
"Hello, #{@name}"
<div style="background:#e7f3ff; border-left:6px solid #2b7cff; padding:12px; margin:12px 0;">
'''Практична роль:''' data class зменшує boilerplate для простих об’єктів даних.; '''Практична роль:''' fields відповідають на питання: “Що цей об’єкт знає або зберігає?”
return a + b;
def total_users(cls):
<div style="background:#fef2f2; border-left:6px solid #ef4444; padding:12px; margin:12px 0;">
== Static Members ==
Приклад:
<div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;">
* instance variables;
* methods;
* modules;
* mixins;
* inheritance;
* metaprogramming;
* open classes.; Зовнішній код не має змогу напряму змінити `balance`, а має використовувати метод `deposit`.; * У C++ class має змогу керувати ресурсами напряму через RAII.; }
domain(): string {
class User {
'''Практична роль:''' repository class надає можливість бізнес-логіці не знати деталей database access.;
- side effects;
- складніше debug;
- проблеми concurrency;
- неочікувані зміни state.; Приклад:
def deposit(self, amount):
<syntaxhighlight lang="typescript">
== Цікавий факт ==
Добрі назви:
async findById(id: string): Promise<User | null> {
<div style="background:#fef2f2; border-left:6px solid #ef4444; padding:12px; margin:12px 0;">
'''Проста різниця:''' interface — це обіцянка, class — це виконання цієї обіцянки.; this.items.push(item);
'''Проста різниця:''' module — це папка або розділ знань, class — це модель конкретної сутності.; '''Практична роль:''' encapsulation захищає об’єкт від неправильних змін і надає можливість контролювати правила роботи зі станом.; !;</div>
</div>
get name() {
public name: string
UserRepository
public string Greet()
Приклад:
<syntaxhighlight lang="typescript">
Проблеми:
* base class — базовий клас;
* parent class — батьківський клас;
* superclass — надклас;
* derived class — похідний клас;
* child class — дочірній клас;
* subclass — підклас.;<div style="background:#eafaf1; border-left:6px solid #2ecc71; padding:12px; margin:12px 0;">
User(std::string name) : name(name) {}
}
def speak(self):
Джерела
Repository має змогу приховувати: Static members використовують для:
'''Практична роль:''' generic class надає можливість писати reusable code без втрати type safety.; Entity важлива не тільки своїми полями, а й тим, що це “той самий об’єкт” у часі.; Мова
class AddNumbers {
User + TimestampMixin → User має createdAt і updatedAt behavior
</div>
'''Multiple inheritance''' — можливість класу наслідувати кілька parent classes.; JavaScript class syntax зручний для ООП-стилю, але істотно пам’ятати про:
'''Небезпека:''' God class стає центром гравітації хаосу: усе нове комфортно додати туди, поки клас не стає майже нерухомим.;
- Java;
- C#;
- C++;
- Python;
- JavaScript;
- TypeScript;
- Kotlin;
- Swift;
- Ruby;
- PHP;
- Scala;
- Dart;
- Objective-C;
- Smalltalk;
- Groovy.;
переважні аспекти: |- | Inheritance | є собою справжній зв’язок “is-a” | Жорстка ієрархія, fragile base class |- | Composition | Об’єкт складається з частин або поведінок | Потрібно більше явного wiring |}
public readonly currency: string
@dataclass class User {
def increment(self):
Приклад:
Проста аналогія: inheritance каже “Car є собою Vehicle”, composition каже “Car має Engine”.; * У Python клас сам є собою object.; Encapsulation або інкапсуляція — принцип приховування внутрішніх деталей класу й надання контрольованого доступу через methods або properties.; return f"Hello, {self.name}"
async getUser(request, response) {
public String greet() {
Добрий клас:
}
</syntaxhighlight>
@Override
return a + b;
- Money;
- EmailAddress;
- DateRange;
- Address;
- Coordinates;
- Percentage;
- Color.;
console.log("Beep"); <div style="background:#fff4e5; border-left:6px solid #f39c12; padding:12px; margin:12px 0;"> </div> '''істотно:''' abstract class корисний, коли є собою спільна поведінка.;</div> '''істотно:''' надмірне використання static methods має змогу зробити код менш гнучким для testing і dependency injection.; Modifier '''Class explosion''' — ситуація, коли створюється надто багато дрібних або зайвих classes.; Функція добре підходить, коли: == Encapsulation == '''DTO''' або '''Data Transfer Object''' — клас або структура для передачі даних між шарами або системами.; Назва й межі відповідальності мають бути чіткими.; class User {
Class добре підходить, коли:
constructor(public readonly value: string) {
String email;
};
this.name = name;
private:
}
}
Простіше: Погано:
Property
execute(a: number, b: number) {
Приклад: - генерує PDF
}
</syntaxhighlight> {{SEO
як ілюстрація:
const numberBox = new Box<number>(123); </syntaxhighlight>
Коли варто створювати Class
- Object-Oriented Programming
- Object
- Instance
- Constructor
- Method
- Property
- Field
- Encapsulation
- Inheritance
- Polymorphism
- Abstraction
- Interface
- Abstract Class
- Composition
- SOLID
- Single Responsibility Principle
- Design Patterns
- Domain Model
- Entity
- Value Object
- Repository Pattern
- Dependency Injection
- UML
- Class Diagram
- Java
- Python
- JavaScript
- TypeScript
- C++
- C#
- Ruby
- Документація
private userRepository: UserRepository