Patterns
π ΠΠ³Π»Π°Π²Π»Π΅Π½ΠΈΠ΅
ΠΠΈΠ°Π³ΡΠ°ΠΌΠΌΠ° ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠΉ
ΠΠ°ΡΠ΅Π³ΠΎΡΠΈΡ | ΠΠ°ΡΡΠ΅ΡΠ½ | ΠΠΎΠ³Π΄Π° ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡ (ΡΠΈΠΌΠΏΡΠΎΠΌ) |
---|
ΠΠΎΡΠΎΠΆΠ΄Π°ΡΡΠΈΠ΅ | Singleton | ΠΡΠΆΠ΅Π½ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ, Π³Π»ΠΎΠ±Π°Π»ΡΠ½Π°Ρ ΡΠΎΡΠΊΠ° Π΄ΠΎΡΡΡΠΏΠ°, Π»Π΅Π½ΠΈΠ²Π°Ρ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ |
| Factory Method | ΠΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΊΠ»Π°ΡΡΠΎΠ² ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΌΠ΅ΠΉΡΡΠ²Π°; Π²ΡΠ±ΠΎΡ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΠΎΡΠ»ΠΎΠΆΠ΅Π½ Π² ΠΏΠΎΠ΄ΠΊΠ»Π°ΡΡ |
| Abstract Factory | Π‘ΠΎΠ³Π»Π°ΡΠΎΠ²Π°Π½Π½ΡΠ΅ ΡΠ΅ΠΌΠ΅ΠΉΡΡΠ²Π° ΠΏΡΠΎΠ΄ΡΠΊΡΠΎΠ² (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, GUI ΠΏΠΎΠ΄ ΡΠ°Π·Π½ΡΠ΅ ΠΠ‘) |
| Builder | Π‘Π»ΠΎΠΆΠ½Π°Ρ ΠΏΠΎΡΠ°Π³ΠΎΠ²Π°Ρ ΡΠ±ΠΎΡΠΊΠ° ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ²; Π½ΡΠΆΠ½Ρ ΡΠ°Π·Π½ΡΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΡΠΎΠ΄ΡΠΊΡΠ° |
| Prototype | Π§Π°ΡΡΠΎΠ΅ ΠΊΠ»ΠΎΠ½ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΡ
ΠΎΠΆΠΈΡ
ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ², Π΄ΠΎΡΠΎΠ³ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°ΡΡ «Ρ Π½ΡΠ»Ρ» |
Π‘ΡΡΡΠΊΡΡΡΠ½ΡΠ΅ | Adapter | ΠΠΎΠ΄ΡΡΠΆΠΈΡΡ Π½Π΅ΡΠΎΠ²ΠΌΠ΅ΡΡΠΈΠΌΡΠ΅ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΡ («ΠΎΠ±ΡΡΡΠΊΠ°») |
| Facade | Π‘ΠΏΡΡΡΠ°ΡΡ ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ ΠΏΠΎΠ΄ΡΠΈΡΡΠ΅ΠΌΡ Π·Π° ΠΏΡΠΎΡΡΠΎΠΉ API |
| Decorator | ΠΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π±Π΅Π· Π½Π°ΡΠ»Π΅Π΄ΠΎΠ²Π°Π½ΠΈΡ |
| Composite | ΠΠ΅ΡΠ°ΡΡ
ΠΈΡ «ΡΠ°ΡΡΡ-ΡΠ΅Π»ΠΎΠ΅»: Π΄Π΅ΡΠ΅Π²ΠΎ, Π³Π΄Π΅ Π»ΠΈΡΡ ΠΈ ΡΠ·Π΅Π» ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡΡΡ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎ |
| Proxy | ΠΠΎΠ½ΡΡΠΎΠ»Ρ Π΄ΠΎΡΡΡΠΏΠ°, ΠΊΡΡ, Π»Π΅Π½ΠΈΠ²Π°Ρ Π·Π°Π³ΡΡΠ·ΠΊΠ°, ΡΠ΄Π°Π»ΡΠ½Π½ΡΠΉ Π΄ΠΎΡΡΡΠΏ |
ΠΠΎΠ²Π΅Π΄Π΅Π½ΡΠ΅ΡΠΊΠΈΠ΅ | Strategy | Π‘Π΅ΠΌΠ΅ΠΉΡΡΠ²ΠΎ Π°Π»Π³ΠΎΡΠΈΡΠΌΠΎΠ², Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΠΌΠ΅Π½ΡΡΡ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΠΈΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ |
| Observer | ΠΠΎΠ΄ΠΏΠΈΡΠΊΠ°/ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²Π° ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² ΠΎΠ± ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡΡ
|
| Command | ΠΠ½ΠΊΠ°ΠΏΡΡΠ»ΡΡΠΈΡ Π·Π°ΠΏΡΠΎΡΠ° ΠΊΠ°ΠΊ ΠΎΠ±ΡΠ΅ΠΊΡΠ°; ΠΎΡΠΌΠ΅Π½Π°/ΠΈΡΡΠΎΡΠΈΡ |
| State | Π Π°Π·Π½ΡΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΎΠ±ΡΠ΅ΠΊΡΠ° → ΡΠ°Π·Π½ΡΠ΅ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΡ |
| Chain of Responsibility | ΠΠΈΠ±ΠΊΠ°Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ° Π·Π°ΠΏΡΠΎΡΠ° ΠΏΠΎ ΡΠ΅ΠΏΠΎΡΠΊΠ΅ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ² |
1) Singleton
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ΅Π½ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ (Π½Π°ΠΏΡ. ΠΊΠΎΠ½ΡΠΈΠ³/ΡΠ΅Π΅ΡΡΡ/ΠΊΠ΅Ρ) ΠΈ Π΅Π΄ΠΈΠ½Π°Ρ ΡΠΎΡΠΊΠ° Π΄ΠΎΡΡΡΠΏΠ°.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠ΄ΠΈΠ½ ΠΈ ΡΠΎΡ ΠΆΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡ ΡΠΎΠ·Π΄Π°ΡΡΡΡ Π² ΡΠ°Π·Π½ΡΡ
ΠΌΠ΅ΡΡΠ°Ρ
, ΡΠ°ΡΡΡΠ»Π°Π΅ΡΡΡ ΠΏΠΎ Π²ΡΠ΅ΠΌΡ ΠΊΠΎΠ΄Ρ ΡΠ΅ΡΠ΅Π· ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ/Π³Π»ΠΎΠ±Π°Π»ΠΈ.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
// ΠΠ΅Π·Π΄Π΅ new Config(), ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΡΠ°ΡΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·ΠΈΡΡΡΡΡΡ
class Config {
constructor(public env = process.env.NODE_ENV ?? 'prod') {
}
}
const a = new Config();
const b = new Config(); // Π΄ΡΡΠ³ΠΎΠ΅ ΠΌΠ΅ΡΡΠΎ
console.log(a.env === b.env); // ΠΌΠΎΠΆΠ΅Ρ ΡΠΎΠ²ΠΏΠ°ΡΡΡ ΡΠ»ΡΡΠ°ΠΉΠ½ΠΎ, Π½ΠΎ ΡΡΠΎ ΡΠ°Π·Π½ΡΠ΅ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΡ
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠΈΠ²Π°ΡΠ½ΡΠΉ ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡ + ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π³Π΅ΡΡΠ΅Ρ, Π»Π΅Π½ΠΈΠ²ΠΎ ΡΠΎΠ·Π΄Π°ΡΡΠΈΠΉ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΉ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
class Config {
private static instance?: Config;
private constructor(public readonly env = process.env.NODE_ENV ?? 'prod') {}
static getInstance(): Config {
if(!Config.instance){
Config.instance = new Config()
};
return Config.instance;
}
}
const cfg = Config.getInstance();
2) Factory Method
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: Π’ΠΈΠΏ ΡΠΎΠ·Π΄Π°Π²Π°Π΅ΠΌΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π·Π°ΡΠ°Π½Π΅Π΅ Π½Π΅ΠΈΠ·Π²Π΅ΡΡΠ΅Π½, Π½ΠΎ Ρ Π½Π΅Π³ΠΎ Π΅ΡΡΡ ΠΎΠ±ΡΠΈΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠΎΠ»ΡΡΠΈΠ΅ switch/if
ΠΏΠΎ ΡΠΈΠΏΡ ΠΏΡΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΠΈ.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
type PayType = 'card' | 'cash' | 'crypto';
function createPayment(type: PayType) {
if (type === 'card')
return {
pay: (a: number) => console.log('card', a)
};
if (type === 'cash')
return {
pay: (a: number) => console.log('cash', a)
};
if (type === 'crypto')
return {
pay: (a: number) => console.log('crypto', a)
};
throw new Error('Unknown');
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ΅Π»Π΅Π³ΠΈΡΠΎΠ²Π°ΡΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠΎΠ΄ΠΊΠ»Π°ΡΡΠ°ΠΌ/ΠΊΠ»Π°ΡΡΠ°ΠΌ-ΡΠΎΠ·Π΄Π°ΡΠ΅Π»ΡΠΌ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
abstract class Payment {
abstract pay(amount: number): void;
}
class CardPayment extends Payment {
pay(a: number) {
console.log(`ΠΠ°ΡΡΠ°: ${a}β½`);
}
}
class CashPayment extends Payment {
pay(a: number) {
console.log(`ΠΠ°Π»ΠΈΡΠ½ΡΠ΅: ${a}β½`);
}
}
abstract class PaymentCreator {
abstract create(): Payment;
}
class CardPaymentCreator extends PaymentCreator {
create() {
return new CardPayment();
}
}
const p = new CardPaymentCreator().create();
p.pay(1999);
3) Abstract Factory
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ½Ρ «ΡΠΎΠ³Π»Π°ΡΠΎΠ²Π°Π½Π½ΡΠ΅» ΡΠ΅ΠΌΠ΅ΠΉΡΡΠ²Π° ΠΏΡΠΎΠ΄ΡΠΊΡΠΎΠ² (Π½Π°ΠΏΡ., Π²ΠΈΠ΄ΠΆΠ΅ΡΡ GUI ΠΏΠΎΠ΄ Win/Mac).
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: Π ΠΊΠΎΠ΄Π΅ ΠΌΠ½ΠΎΠ³ΠΎ if (platform === 'win')
Π²ΠΎΠΊΡΡΠ³ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
function renderUI(platform: 'win' | 'mac') {
const btn = platform === 'win' ? 'WinButton' : 'MacButton';
const chk = platform === 'win' ? 'WinCheckbox' : 'MacCheckbox';
// Π΄ΡΠ±Π»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π»ΠΎΠ³ΠΈΠΊΠΈ Π²ΡΠ±ΠΎΡΠ° ΠΏΠΎ ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ΅ Π²Π΅Π·Π΄Π΅
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ²Π΅ΡΡΠΈ ΡΠ°Π±ΡΠΈΠΊΡ ΡΠ΅ΠΌΠ΅ΠΉΡΡΠ²Π° ΠΈ Π²ΡΠ±ΠΈΡΠ°ΡΡ ΡΠ°Π±ΡΠΈΠΊΡ ΠΎΠ΄ΠΈΠ½ ΡΠ°Π·.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface Button {
render(): string;
}
interface Checkbox {
check(): string;
}
class WinButton implements Button {
render() {
return 'WinButton';
}
}
class MacButton implements Button {
render() {
return 'MacButton';
}
}
class WinCheckbox implements Checkbox {
check() {
return 'WinCheckbox';
}
}
class MacCheckbox implements Checkbox {
check() {
return 'MacCheckbox';
}
}
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class WinFactory implements GUIFactory {
createButton() {
return new WinButton();
}
createCheckbox() {
return new WinCheckbox();
}
}
class MacFactory implements GUIFactory {
createButton() {
return new MacButton();
}
createCheckbox() {
return new MacCheckbox();
}
}
function buildUI(factory: GUIFactory) {
const btn = factory.createButton();
const chk = factory.createCheckbox();
console.log(btn.render(), chk.check());
}
buildUI(new WinFactory());
4) Builder
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΠ±ΡΠ΅ΠΊΡ ΡΠ»ΠΎΠΆΠ½ΡΠΉ (ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»Π΅ΠΉ, ΠΎΠΏΡΠΈΠΉ), ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡ ΡΠ°Π·ΡΠ°ΡΡΠ°Π΅ΡΡΡ.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠΎΠ½ΡΡΡΡΠΊΡΠΎΡΡ Ρ 10+ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠ°ΠΌΠΈ, ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ undefined/null
.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
// ΡΡΡΠ΄Π½ΠΎ ΡΠΈΡΠ°ΡΡ ΠΈ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡ
const report = new Report("Sales", true, undefined, undefined, "RU", 20, null, "A4", /* ... */);
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠΎΡΠ°Π³ΠΎΠ²Π°Ρ ΡΠ±ΠΎΡΠΊΠ° ΡΠ΅ΡΠ΅Π· ΡΠ΅ΠΏΠΎΡΠΊΡ Π²ΡΠ·ΠΎΠ²ΠΎΠ².
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
class Query {
constructor(
public select = '*',
public from?: string,
public where?: string
) {}
toString() {
return `SELECT ${this.select}
FROM ${this.from} ${this.where ? ` WHERE ${this.where}` : ''}`;
}
}
class QueryBuilder {
private q = new Query();
select(cols: string) {
this.q.select = cols;
return this;
}
from(tbl: string) {
this.q.from = tbl;
return this;
}
where(cond: string) {
this.q.where = cond;
return this;
}
build() {
return this.q;
}
}
const sql = new QueryBuilder()
.from('users')
.where('active=1')
.build();
5) Prototype
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: Π§Π°ΡΡΠΎ Π½ΡΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Π²Π°ΡΡ ΠΊΠΎΠΏΠΈΠΈ ΡΠΆΠ΅ Π½Π°ΡΡΡΠΎΠ΅Π½Π½ΡΡ
ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ².
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: Π ΡΡΠ½ΠΎΠ΅ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΠ»Π΅ΠΉ ΠΏΡΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΡΠΎΠ·Π΄Π°Π½ΠΈΠΈ.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
const baseTpl = { title: 'Π‘ΡΡΡ', vat: 20, footer: 'Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ' };
function cloneInvoiceTpl() {
return {
title: baseTpl.title,
vat: baseTpl.vat,
footer: baseTpl.footer
};
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ±ΡΠ΅ΠΊΡ ΡΠΌΠ΅Π΅Ρ ΡΠ°ΠΌ ΡΠ΅Π±Ρ ΠΊΠ»ΠΎΠ½ΠΈΡΠΎΠ²Π°ΡΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface Clonable<T> {
clone(): T;
}
class InvoiceTemplate implements Clonable<InvoiceTemplate> {
constructor(
public title: string,
public vat: number,
public footer: string,
public subTemplate?: InvoiceTemplate
) {}
clone() {
return new InvoiceTemplate(
this.title,
this.vat,
this.footer,
this.subTemplate ? subTemplate.clone() : undefined
);
}
}
const tpl = new InvoiceTemplate('Π‘ΡΡΡ', 20, 'Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ');
const tpl2 = tpl.clone();
6) Adapter
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΠ½Π΅ΡΠ½ΠΈΠΉ ΡΠ΅ΡΠ²ΠΈΡ ΠΈΠΌΠ΅Π΅Ρ «Π½Π΅ΡΠ΄ΠΎΠ±Π½ΡΠΉ» API.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: Π ΠΏΡΠΎΠ΅ΠΊΡΠ΅ Π²Π΅Π·Π΄Π΅ ΠΌΠ΅Π»ΠΊΠΈΠ΅ ΠΊΠΎΠ½Π²Π΅ΡΡΠ°ΡΠΈΠΈ ΠΊ ΡΡΠΎΠΌΡ API.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
// ΠΠ»ΠΈΠ΅Π½Ρ Π·Π½Π°Π΅Ρ Π΄Π΅ΡΠ°Π»ΠΈ ΡΡΠ°ΡΠΎΠ³ΠΎ API
class OldBankAPI {
sendMoney(sum: number) {
/* ... */
}
}
function pay(amount: number, bank: OldBankAPI) {
bank.sendMoney(amount); // ΡΠ²ΡΠ·Π°Π»ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ ΡΠΎ ΡΡΠ°ΡΡΠΌ API
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ²Π΅ΡΡΠΈ ΡΠ΅Π»Π΅Π²ΠΎΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ ΠΈ Π°Π΄Π°ΠΏΡΠ΅Ρ ΠΊ ΡΡΠ°ΡΠΎΠΌΡ API.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
class CardSystem {
sendMoney(sum: number) {
console.log('CardSystem bank:', sum);
}
}
class CryptoSystem {
sendCripto(hash: number) {
console.log('CryptoSystem bank:', hash);
}
}
class CardCryptoSystemAdapter extends CardSystem {
constructor(private readonly system: CryptoSystem)
sendMoney(sum: number) {
const hash = btoa(sum);
this.system.sendCripto(hash)
}
}
class Bank{
constructor(private system: CardSystem) {}
pay(amount: number) {
this.system.sendMoney(amount);
}
}
7) Facade
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΠ»ΠΈΠ΅Π½ΡΡ ΠΏΡΠΈΡ
ΠΎΠ΄ΠΈΡΡΡ Π·Π½Π°ΡΡ ΠΌΠ½ΠΎΠ³ΠΎ Π΄Π΅ΡΠ°Π»Π΅ΠΉ ΠΏΠΎΠ΄ΡΠΈΡΡΠ΅ΠΌΡ.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠ½ΠΎΠ³ΠΎ Π²ΡΠ·ΠΎΠ²ΠΎΠ² Π½ΠΈΠ·ΠΊΠΎΡΡΠΎΠ²Π½Π΅Π²ΡΡ
ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² ΠΈΠ· ΠΊΠ»ΠΈΠ΅Π½ΡΠ°.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
const cpu = new CPU();
const mem = new Memory();
const disk = new Disk();
const data = disk.read();
mem.load(0, data);
cpu.start(); // ΠΊΠ»ΠΈΠ΅Π½Ρ ΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ Π²ΡΠ΅ΠΌ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠΌ
Π Π΅ΡΠ΅Π½ΠΈΠ΅: Π‘ΠΏΡΡΡΠ°ΡΡ ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ Π·Π° ΠΏΡΠΎΡΡΠΎΠΉ API ΡΠ°ΡΠ°Π΄Π°.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
class CPU {
start() {
console.log('CPU start');
}
}
class Memory {
load(addr: number, data: string) {
console.log('load', addr, data);
}
}
class Disk {
read() {
return 'OS';
}
}
class ComputerFacade {
constructor(
private cpu = new CPU(),
private mem = new Memory(),
private disk = new Disk()
) {}
boot() {
this.mem.load(0, this.disk.read());
this.cpu.start();
}
}
new ComputerFacade().boot();
8) Decorator
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ½ΠΎ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ ΡΠΈΡΠΈ ΠΎΠ±ΡΠ΅ΠΊΡΡ.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ ΠΏΠΎΠ΄ΠΊΠ»Π°ΡΡΠΎΠ² «ΠΠΎΠΌΠ±ΠΈΠ½Π°ΡΠΈΡΠ+ΠΠΎΠ³ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅+ΠΠ΅Ρ+ΠΡΠ΄ΠΈΡ».
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
class OrderServiceWithLoggingAndCachingAndMetrics { /* ... ΠΌΠΎΠ½ΠΎΠ»ΠΈΡ ... */ }
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ±ΠΎΡΠ°ΡΠΈΠ²Π°ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡ Π² ΠΎΠ΄ΠΈΠ½ ΠΈΠ»ΠΈ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ Π΄Π΅ΠΊΠΎΡΠ°ΡΠΎΡΠΎΠ².
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface Notifier {
send(msg: string): void;
}
class BaseNotifier implements Notifier {
send(msg: string) {
console.log('Base:', msg);
}
}
class SMSDecorator implements Notifier {
constructor(private wrappee: Notifier) {}
send(msg: string) {
this.wrappee.send(msg);
console.log('SMS:', msg);
}
}
class EmailDecorator implements Notifier {
constructor(private wrappee: Notifier) {}
send(msg: string) {
this.wrappee.send(msg);
console.log('Email:', msg);
}
}
const notifier = new EmailDecorator(new SMSDecorator(new BaseNotifier()));
notifier.send('ΠΠΎΡΡΡΠΏΠΈΠ»Π° Π·Π°ΡΠ²ΠΊΠ°');
9) Composite
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ½ΠΎ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎ ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΡΡ Π΄Π΅ΡΠ΅Π²ΠΎ (ΠΏΠ°ΠΏΠΊΠΈ/ΡΠ°ΠΉΠ»Ρ, ΠΌΠ΅Π½Ρ/ΠΏΡΠ½ΠΊΡΡ).
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: Π ΠΊΠΎΠ΄Π΅ Π²Π΅Π·Π΄Π΅ if (leaf) else (node)
.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
type Node = { name: string; children?: Node[] };
function print(n: Node) {
if (!n.children) console.log(n.name);
else {
console.log(n.name);
n.children.forEach(print);
}
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠΈΡΡ ΠΈ ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ ΡΠ΅Π°Π»ΠΈΠ·ΡΡΡ ΠΎΠ±ΡΠΈΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface Component {
show(indent?: string): void;
}
class File implements Component {
constructor(private name: string) {}
show(indent = '') {
console.log(indent + this.name);
}
}
class Folder implements Component {
private children: Component[] = [];
constructor(private name: string) {}
add(c: Component) {
this.children.push(c);
}
show(indent = '') {
console.log(indent + this.name);
this.children.forEach((c) => c.show(indent + ' '));
}
}
const root = new Folder('root');// /root
root.add(new File('a.txt')); // /root/a.txt
const docs = new Folder('docs');// /roo
docs.add(new File('readme.md'));
root.add(docs);
root.show();
10) Proxy
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ΅Π½ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ Π΄ΠΎΡΡΡΠΏΠ°/ΠΊΠ΅Ρ/Π»Π΅Π½ΠΈΠ²Π°Ρ Π·Π°Π³ΡΡΠ·ΠΊΠ° Π²ΠΎΠΊΡΡΠ³ ΡΠ΅ΡΠ²ΠΈΡΠ°.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠ΅Ρ/ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ ΠΏΡΠ°Π² Π΄ΡΠ±Π»ΠΈΡΡΡΡΡΡ Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΌΠ΅ΡΡΠ΅ Π²ΡΠ·ΠΎΠ²Π°.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
const data = service.getData();
if (!cache["data"]) cache["data"] = data; // Π΄ΡΠ±Π»ΠΈΡΡΠ΅ΠΌ Π² ΠΊΠΎΠ½ΡΡΠΎΠ»Π»Π΅ΡΠ°Ρ
, ΡΠ΅ΡΠ²ΠΈΡΠ°Ρ
ΠΈ Ρ.Π΄.
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ²Π΅ΡΡΠΈ «Π·Π°ΠΌΠ΅ΡΡΠΈΡΠ΅Π»Ρ», ΠΈΠ½ΠΊΠ°ΠΏΡΡΠ»ΠΈΡΡΡΡΠ΅Π³ΠΎ ΡΠΊΠ²ΠΎΠ·Π½ΡΡ Π»ΠΎΠ³ΠΈΠΊΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface Service {
getData(): string;
}
class RealService implements Service {
getData() {
return 'ΡΠ΅ΠΊΡΠ΅Ρ';
}
}
class ServiceProxy implements Service {
private cache?: string;
constructor(private real = new RealService()) {}
getData() {
if (!this.cache) {
this.cache = this.real.getData();
console.log('real');
} else console.log('cache');
return this.cache;
}
}
const svc = new ServiceProxy();
svc.getData(); // real
svc.getData(); // cache
ΠΠΎΠ²Π΅Π΄Π΅Π½ΡΠ΅ΡΠΊΠΈΠ΅
11) Strategy
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ½ΠΎ ΠΏΠ΅ΡΠ΅ΠΊΠ»ΡΡΠ°ΡΡ Π°Π»Π³ΠΎΡΠΈΡΠΌΡ (ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠ°, ΡΠ΅Π½ΠΎΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅, Π΄ΠΎΡΡΠ°Π²ΠΊΠ°).
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠΎΠ»ΡΡΠΈΠ΅ if/else
ΠΏΠΎ ΡΠΈΠΏΡ Π°Π»Π³ΠΎΡΠΈΡΠΌΠ°.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
function price(base: number, region: 'EU' | 'US' | 'RU') {
if (region === 'EU') return base * 1.2;
if (region === 'US') return base * 1.1;
return base * 1.05;
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠ΄Π΅Π»ΠΈΡΡ ΡΡΡΠ°ΡΠ΅Π³ΠΈΠΈ, ΠΏΠΎΠ΄ΡΡΠ°Π²Π»ΡΡΡ Π½ΡΠΆΠ½ΡΡ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΠΈΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface PricingStrategy {
calc(base: number): number;
}
enum PricingType {
EU,
US
}
class EUPricing implements PricingStrategy {
calc(b: number) {
return b * 1.2;
}
}
class USPricing implements PricingStrategy {
calc(b: number) {
return b * 1.1;
}
}
class Checkout {
constructor(private readonly strategyTable: Map<PricingType, PricingStrategy>) {}
total(type: PricingType, base: number) {
return this.strategyTable.get(type)!.calc(base);
}
}
const checkout = new Checkout(
new Map<PricingType, PricingStrategy>([
[PricingType.EU, new EUPricing()],
[PricingType.US, new USPricing()]
])
);
checkout.total(PricingType.EU, 3000);
12) Observer
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΏΠΈΡΡΠΈΠΊΠΎΠ² Π΄ΠΎΠ»ΠΆΠ½Ρ ΡΠ΅Π°Π³ΠΈΡΠΎΠ²Π°ΡΡ Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ (ΡΠΎΠ±ΡΡΠΈΡ, ΠΊΡΡΡΡ Π²Π°Π»ΡΡ, ΠΈΠ½Π²Π΅Π½ΡΠ°ΡΡ).
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: Π ΡΡΠ½ΡΠ΅ Π²ΡΠ·ΠΎΠ²Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
function onPriceChange(v:number){
updateUI(v);
sendAnalytics(v);
notifyPartners(v); // ΡΠ°ΡΡΡΡ ΡΠΏΠΈΡΠΎΠΊ Π²ΡΠ·ΠΎΠ²ΠΎΠ²
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠΎΠ΄Π΅Π»Ρ «ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ°-ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅».
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
type Listener = (v: number) => void;
class Subject {
private observers = new Set<Listener>();
subscribe(l: Listener) {
this.observers.add(l);
}
unsubscribe(l: Listener) {
this.observers.delete(l);
}
notify(v: number) {
this.observers.forEach((l) => l(v));
}
}
const price$ = new Subject();
price$.subscribe((v) => console.log('UI:', v));
price$.subscribe((v) => console.log('Analytics:', v));
price$.notify(120);
13) Command
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΡΠΆΠ½Ρ undo/redo, ΠΎΡΠ΅ΡΠ΅Π΄Ρ Π·Π°Π΄Π°Ρ, Π»ΠΎΠ³ Π°ΡΠ΄ΠΈΡΠ°.
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠ΅ΠΉΡΡΠ²ΠΈΡ Π²ΡΠ·ΡΠ²Π°ΡΡΡΡ Π½Π°ΠΏΡΡΠΌΡΡ Π±Π΅Π· ΠΈΡΡΠΎΡΠΈΠΈ.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
class Cart { items:string[]=[]; add(i:string){ this.items.push(i);} }
const cart = new Cart();
cart.add("Π’Π΅Π»Π΅ΡΠΎΠ½");
// ΠΠ°ΠΊ ΠΎΡΠΊΠ°ΡΠΈΡΡ? ΠΡΡΠΎΡΠΈΠΈ Π½Π΅Ρ.
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ½ΠΊΠ°ΠΏΡΡΠ»ΠΈΡΠΎΠ²Π°ΡΡ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ Π² ΠΊΠΎΠΌΠ°Π½Π΄Ρ ΠΈ Ρ
ΡΠ°Π½ΠΈΡΡ ΠΈΡΡΠΎΡΠΈΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface Command {
execute(): void;
undo(): void;
}
class Cart {
items: string[] = [];
add(i: string) {
this.items.push(i);
}
remove(i: string) {
this.items = this.items.filter((x) => x !== i);
}
}
class AddItemCommand implements Command {
constructor(
private cart: Cart,
private item: string
) {}
execute() {
this.cart.add(this.item);
}
undo() {
this.cart.remove(this.item);
}
}
class Invoker {
private history: Command[] = [];
run(c: Command) {
c.execute();
this.history.push(c);
}
undo() {
this.history.pop()?.undo();
}
}
const inv = new Invoker();
const cart2 = new Cart();
inv.run(new AddItemCommand(cart2, 'Π’Π΅Π»Π΅ΡΠΎΠ½'));
inv.undo();
14) State
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π·Π°Π²ΠΈΡΠΈΡ ΠΎΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ (ΡΡΠ°ΡΡΡ Π·Π°ΠΊΠ°Π·Π°, Π΄Π²Π΅ΡΡ, Π΄ΠΎΠΊΡΠΌΠ΅Π½Ρ).
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠΈΠ³Π°Π½ΡΡΠΊΠΈΠΉ switch(state)
Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΌΠ΅ΡΠΎΠ΄Π΅.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
type DoorState = 'locked' | 'unlocked';
let state: DoorState = 'locked';
function click() {
if (state === 'locked') {
console.log('open');
state = 'unlocked';
} else {
console.log('close');
state = 'locked';
}
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠ½Π΅ΡΡΠΈ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ Π² ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠ΅ ΠΊΠ»Π°ΡΡΡ, ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ Π΄Π΅Π»Π΅Π³ΠΈΡΡΠ΅Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
interface State {
handle(ctx: Context): void;
}
class Context {
constructor(public state: State) {}
set(s: State) {
this.state = s;
}
request() {
this.state.handle(this);
}
}
class Locked implements State {
handle(ctx: Context) {
console.log('ΠΡΠΊΡΡΠ²Π°Π΅ΠΌ');
ctx.set(new Unlocked());
}
}
class Unlocked implements State {
handle(ctx: Context) {
console.log('ΠΠ°ΠΊΡΡΠ²Π°Π΅ΠΌ');
ctx.set(new Locked());
}
}
const door = new Context(new Locked());
door.request();
door.request();
15) Chain of Responsibility
ΠΡΠΎΠ±Π»Π΅ΠΌΠ°: ΠΠ°ΠΏΡΠΎΡ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΡΠΎΠΉΡΠΈ ΡΠ΅ΡΠ΅Π· ΡΠ΅ΠΏΠΎΡΠΊΡ ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ (Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ, Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ, Π±ΠΈΠ·Π½Π΅Ρ-ΠΏΡΠ°Π²ΠΈΠ»Π°).
Π‘ΠΈΠΌΠΏΡΠΎΠΌ: ΠΠ»ΠΎΠΆΠ΅Π½Π½ΡΠ΅ if
, ΡΠ°Π·ΠΌΠ°Π·Π°Π½Π½ΡΠ΅ ΠΏΠΎ ΠΌΠ΅ΡΠΎΠ΄Ρ.
ΠΠ»ΠΎΡ
ΠΎΠΉ ΠΏΡΠΈΠΌΠ΅Ρ (ΡΠΈΠΌΠΏΡΠΎΠΌ Π² ΠΊΠΎΠ΄Π΅):
function handle(req:string){
if (!req.includes("auth")) return "401";
if (!req.includes("payload")) return "400";
return "200";
}
Π Π΅ΡΠ΅Π½ΠΈΠ΅: Π‘Π±ΠΎΡΠΊΠ° ΡΠ΅ΠΏΠΎΡΠΊΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ² — ΠΊΠ°ΠΆΠ΄ΡΠΉ Π»ΠΈΠ±ΠΎ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ, Π»ΠΈΠ±ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ Π΄Π°Π»ΡΡΠ΅.
ΠΠΎΠ΄ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ:
abstract class Handler {
private next?: Handler;
setNext(h: Handler) {
this.next = h;
return h;
}
handle(req: string): string | undefined {
return this.next?.handle(req);
}
}
class AuthHandler extends Handler {
handle(req: string) {
if (!req.includes('auth')) return '401';
return super.handle(req);
}
}
class ValidationHandler extends Handler {
handle(req: string) {
if (!req.includes('payload')) return '400';
return super.handle(req) ?? '200';
}
}
// {} -> {} -> {} -> {}
const pipeline = new AuthHandler();
pipeline.setNext(new ValidationHandler());
console.log(pipeline.handle('auth+payload')); // 200
console.log(pipeline.handle('payload')); // 401
Last modified: 01 October 2025