명령, 책임 사슬 및 템플릿 방법
I 행동 패턴 개체 간의 통신 및 책임을 관리합니다. 명령 요청을 객체로 캡슐화합니다(실행 취소/다시 실행). 책임의 사슬 핸들러 체인(미들웨어)을 따라 요청을 전달합니다. 템플릿 방법 정의하다 사용자 정의 가능한 단계를 갖춘 알고리즘 뼈대입니다.
🎯 무엇을 배울 것인가
- 명령 패턴: 작업을 객체로 캡슐화
- 명령으로 실행 취소/다시 실행 구현
- 책임 체인: 핸들러 체인
- 템플릿 방법: 후크 포인트가 있는 알고리즘
명령 패턴
Il 명령 패턴 요청을 객체로 캡슐화하여 다음을 수행할 수 있습니다. 작업, 대기열 요청 및 지원 작업을 사용하여 메서드를 매개변수화합니다. 실행 취소할 수 있습니다(실행 취소/다시 실행).
// Interfaccia Command
interface Command {{ '{' }}
execute(): void;
undo(): void;
{{ '}' }}
// Receiver: oggetto che esegue l'azione reale
class Light {{ '{' }}
private isOn: boolean = false;
turnOn(): void {{ '{' }}
this.isOn = true;
console.log("💡 Luce accesa");
{{ '}' }}
turnOff(): void {{ '{' }}
this.isOn = false;
console.log("🌑 Luce spenta");
{{ '}' }}
getState(): boolean {{ '{' }}
return this.isOn;
{{ '}' }}
{{ '}' }}
// Concrete Commands
class TurnOnCommand implements Command {{ '{' }}
constructor(private light: Light) {{ '{' }}{{ '}' }}
execute(): void {{ '{' }}
this.light.turnOn();
{{ '}' }}
undo(): void {{ '{' }}
this.light.turnOff();
{{ '}' }}
{{ '}' }}
class TurnOffCommand implements Command {{ '{' }}
constructor(private light: Light) {{ '{' }}{{ '}' }}
execute(): void {{ '{' }}
this.light.turnOff();
{{ '}' }}
undo(): void {{ '{' }}
this.light.turnOn();
{{ '}' }}
{{ '}' }}
// Invoker: esegue i comandi
class RemoteControl {{ '{' }}
private history: Command[] = [];
executeCommand(command: Command): void {{ '{' }}
command.execute();
this.history.push(command);
{{ '}' }}
undo(): void {{ '{' }}
const command = this.history.pop();
if (command) {{ '{' }}
command.undo();
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Utilizzo
const light = new Light();
const remote = new RemoteControl();
remote.executeCommand(new TurnOnCommand(light)); // "💡 Luce accesa"
remote.executeCommand(new TurnOffCommand(light)); // "🌑 Luce spenta"
remote.undo(); // "💡 Luce accesa" (annulla spegnimento)
전체 실행 취소/다시 실행을 사용한 명령
여러 실행 취소/다시 실행을 통한 고급 구현:
class TextEditor {{ '{' }}
private content: string = "";
getContent(): string {{ '{' }}
return this.content;
{{ '}' }}
setContent(content: string): void {{ '{' }}
this.content = content;
{{ '}' }}
append(text: string): void {{ '{' }}
this.content += text;
{{ '}' }}
delete(length: number): void {{ '{' }}
this.content = this.content.slice(0, -length);
{{ '}' }}
{{ '}' }}
class AppendCommand implements Command {{ '{' }}
constructor(
private editor: TextEditor,
private text: string
) {{ '{' }}{{ '}' }}
execute(): void {{ '{' }}
this.editor.append(this.text);
{{ '}' }}
undo(): void {{ '{' }}
this.editor.delete(this.text.length);
{{ '}' }}
{{ '}' }}
class DeleteCommand implements Command {{ '{' }}
private deletedText: string = "";
constructor(
private editor: TextEditor,
private length: number
) {{ '{' }}{{ '}' }}
execute(): void {{ '{' }}
const content = this.editor.getContent();
this.deletedText = content.slice(-this.length);
this.editor.delete(this.length);
{{ '}' }}
undo(): void {{ '{' }}
this.editor.append(this.deletedText);
{{ '}' }}
{{ '}' }}
class CommandManager {{ '{' }}
private history: Command[] = [];
private redoStack: Command[] = [];
execute(command: Command): void {{ '{' }}
command.execute();
this.history.push(command);
this.redoStack = []; // Pulisci redo stack su nuova azione
{{ '}' }}
undo(): void {{ '{' }}
const command = this.history.pop();
if (command) {{ '{' }}
command.undo();
this.redoStack.push(command);
{{ '}' }}
{{ '}' }}
redo(): void {{ '{' }}
const command = this.redoStack.pop();
if (command) {{ '{' }}
command.execute();
this.history.push(command);
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Utilizzo
const editor = new TextEditor();
const manager = new CommandManager();
manager.execute(new AppendCommand(editor, "Hello "));
manager.execute(new AppendCommand(editor, "World"));
console.log(editor.getContent()); // "Hello World"
manager.undo();
console.log(editor.getContent()); // "Hello "
manager.redo();
console.log(editor.getContent()); // "Hello World"
책임 패턴의 사슬
Il 책임의 사슬 여러 객체가 요청을 처리할 수 있도록 허용 발신자는 어느 쪽이 그것을 처리할지 알지 못한 채. 요청은 체인을 따라 전달됩니다. 누군가 그것을 관리합니다.
// Handler astratto
abstract class Handler {{ '{' }}
protected next: Handler | null = null;
setNext(handler: Handler): Handler {{ '{' }}
this.next = handler;
return handler; // Fluent interface
{{ '}' }}
handle(request: string): void {{ '{' }}
if (this.canHandle(request)) {{ '{' }}
this.process(request);
{{ '}' }} else if (this.next) {{ '{' }}
this.next.handle(request);
{{ '}' }} else {{ '{' }}
console.log(`❌ Nessun handler per: ${{ '{' }}request{{ '}' }}`);
{{ '}' }}
{{ '}' }}
protected abstract canHandle(request: string): boolean;
protected abstract process(request: string): void;
{{ '}' }}
// Concrete Handlers
class SupportLevel1 extends Handler {{ '{' }}
protected canHandle(request: string): boolean {{ '{' }}
return request.includes("password");
{{ '}' }}
protected process(request: string): void {{ '{' }}
console.log("👤 Level 1: Reset password inviato");
{{ '}' }}
{{ '}' }}
class SupportLevel2 extends Handler {{ '{' }}
protected canHandle(request: string): boolean {{ '{' }}
return request.includes("bug");
{{ '}' }}
protected process(request: string): void {{ '{' }}
console.log("🔧 Level 2: Investigazione bug iniziata");
{{ '}' }}
{{ '}' }}
class SupportLevel3 extends Handler {{ '{' }}
protected canHandle(request: string): boolean {{ '{' }}
return request.includes("crash");
{{ '}' }}
protected process(request: string): void {{ '{' }}
console.log("🚨 Level 3: Crash critico escalato a engineering");
{{ '}' }}
{{ '}' }}
// Setup della catena
const level1 = new SupportLevel1();
const level2 = new SupportLevel2();
const level3 = new SupportLevel3();
level1.setNext(level2).setNext(level3);
// Utilizzo
level1.handle("Ho dimenticato la password"); // "👤 Level 1: Reset password inviato"
level1.handle("C'è un bug nel form"); // "🔧 Level 2: Investigazione bug iniziata"
level1.handle("L'app crasha"); // "🚨 Level 3: Crash critico escalato a engineering"
level1.handle("Domanda generica"); // "❌ Nessun handler per: Domanda generica"
책임 사슬: HTTP 미들웨어
실제 예: HTTP 요청을 처리하는 미들웨어 파이프라인:
interface Request {{ '{' }}
url: string;
method: string;
headers: Record<string, string>;
body?: any;
{{ '}' }}
type NextFunction = () => void;
abstract class Middleware {{ '{' }}
protected next: Middleware | null = null;
setNext(middleware: Middleware): Middleware {{ '{' }}
this.next = middleware;
return middleware;
{{ '}' }}
handle(req: Request, next: NextFunction): void {{ '{' }}
this.process(req, () => {{ '{' }}
if (this.next) {{ '{' }}
this.next.handle(req, next);
{{ '}' }} else {{ '{' }}
next();
{{ '}' }}
{{ '}' }});
{{ '}' }}
protected abstract process(req: Request, next: NextFunction): void;
{{ '}' }}
class AuthMiddleware extends Middleware {{ '{' }}
protected process(req: Request, next: NextFunction): void {{ '{' }}
console.log("🔐 Checking authentication...");
if (req.headers['authorization']) {{ '{' }}
console.log("✅ Authenticated");
next();
{{ '}' }} else {{ '{' }}
console.log("❌ Unauthorized - blocking request");
{{ '}' }}
{{ '}' }}
{{ '}' }}
class LoggingMiddleware extends Middleware {{ '{' }}
protected process(req: Request, next: NextFunction): void {{ '{' }}
console.log(`📝 ${{ '{' }}req.method{{ '}' }} ${{ '{' }}req.url{{ '}' }}`);
next();
{{ '}' }}
{{ '}' }}
class ValidationMiddleware extends Middleware {{ '{' }}
protected process(req: Request, next: NextFunction): void {{ '{' }}
console.log("✔️ Validating request...");
if (req.method === 'POST' && !req.body) {{ '{' }}
console.log("❌ Validation failed: missing body");
{{ '}' }} else {{ '{' }}
console.log("✅ Validation passed");
next();
{{ '}' }}
{{ '}' }}
{{ '}' }}
// Setup middleware chain
const auth = new AuthMiddleware();
const logging = new LoggingMiddleware();
const validation = new ValidationMiddleware();
auth.setNext(logging).setNext(validation);
// Utilizzo
const request: Request = {{ '{' }}
url: '/api/users',
method: 'POST',
headers: {{ '{' }} authorization: 'Bearer token123' {{ '}' }},
body: {{ '{' }} name: 'Alice' {{ '}' }}
{{ '}' }};
auth.handle(request, () => console.log("🎯 Request processed!"));
// Output:
// 🔐 Checking authentication...
// ✅ Authenticated
// 📝 POST /api/users
// ✔️ Validating request...
// ✅ Validation passed
// 🎯 Request processed!
템플릿 메소드 패턴
Il 템플릿 방법 기본 클래스에서 알고리즘의 뼈대를 정의합니다. 일부 단계를 하위 클래스에 위임합니다. 서브클래스는 특정 단계를 재정의하지 않고 전체적인 구조를 바꿔보세요.
abstract class DataProcessor {{ '{' }}
// Template method: definisce l'algoritmo
public process(): void {{ '{' }}
this.readData();
this.processData();
this.saveData();
this.sendNotification(); // Hook opzionale
{{ '}' }}
// Passi astratti (da implementare)
protected abstract readData(): void;
protected abstract processData(): void;
protected abstract saveData(): void;
// Hook: metodo con implementazione di default
protected sendNotification(): void {{ '{' }}
// Default: non fa nulla (le sottoclassi possono override)
{{ '}' }}
{{ '}' }}
// Concrete implementation
class CSVProcessor extends DataProcessor {{ '{' }}
protected readData(): void {{ '{' }}
console.log("📄 Reading CSV file...");
{{ '}' }}
protected processData(): void {{ '{' }}
console.log("🔄 Parsing CSV rows...");
{{ '}' }}
protected saveData(): void {{ '{' }}
console.log("💾 Saving to database...");
{{ '}' }}
protected sendNotification(): void {{ '{' }}
console.log("📧 Email notification sent");
{{ '}' }}
{{ '}' }}
class JSONProcessor extends DataProcessor {{ '{' }}
protected readData(): void {{ '{' }}
console.log("📄 Reading JSON file...");
{{ '}' }}
protected processData(): void {{ '{' }}
console.log("🔄 Parsing JSON objects...");
{{ '}' }}
protected saveData(): void {{ '{' }}
console.log("💾 Saving to cache...");
{{ '}' }}
// Non override sendNotification (usa default)
{{ '}' }}
// Utilizzo
const csvProcessor = new CSVProcessor();
csvProcessor.process();
// 📄 Reading CSV file...
// 🔄 Parsing CSV rows...
// 💾 Saving to database...
// 📧 Email notification sent
const jsonProcessor = new JSONProcessor();
jsonProcessor.process();
// 📄 Reading JSON file...
// 🔄 Parsing JSON objects...
// 💾 Saving to cache...
// (nessuna notifica)
고급 템플릿 방법: 테스트 프레임워크
실제 예: 설정/해제 기능을 갖춘 자동화된 테스트 프레임워크:
abstract class TestCase {{ '{' }}
// Template method
public run(): void {{ '{' }}
this.setUp();
try {{ '{' }}
this.runTest();
console.log("✅ Test passed");
{{ '}' }} catch (error) {{ '{' }}
console.log(`❌ Test failed: ${{ '{' }}error{{ '}' }}`);
{{ '}' }} finally {{ '{' }}
this.tearDown();
{{ '}' }}
{{ '}' }}
// Hook methods
protected setUp(): void {{ '{' }}
console.log("🔧 Setting up test...");
{{ '}' }}
protected tearDown(): void {{ '{' }}
console.log("🧹 Cleaning up...");
{{ '}' }}
// Passo astratto: ogni test definisce il proprio
protected abstract runTest(): void;
{{ '}' }}
// Test concreti
class DatabaseTest extends TestCase {{ '{' }}
private connection: any;
protected setUp(): void {{ '{' }}
super.setUp();
console.log("🔌 Connecting to test database...");
this.connection = {{ '{' }} connected: true {{ '}' }};
{{ '}' }}
protected runTest(): void {{ '{' }}
console.log("🧪 Testing database queries...");
if (!this.connection.connected) {{ '{' }}
throw new Error("Connection failed");
{{ '}' }}
{{ '}' }}
protected tearDown(): void {{ '{' }}
console.log("🔌 Closing database connection...");
this.connection = null;
super.tearDown();
{{ '}' }}
{{ '}' }}
class APITest extends TestCase {{ '{' }}
protected setUp(): void {{ '{' }}
super.setUp();
console.log("🌐 Starting mock API server...");
{{ '}' }}
protected runTest(): void {{ '{' }}
console.log("🧪 Testing API endpoints...");
// Test logic here
{{ '}' }}
protected tearDown(): void {{ '{' }}
console.log("🛑 Stopping mock server...");
super.tearDown();
{{ '}' }}
{{ '}' }}
// Utilizzo
new DatabaseTest().run();
// 🔧 Setting up test...
// 🔌 Connecting to test database...
// 🧪 Testing database queries...
// ✅ Test passed
// 🔌 Closing database connection...
// 🧹 Cleaning up...
new APITest().run();
// 🔧 Setting up test...
// 🌐 Starting mock API server...
// 🧪 Testing API endpoints...
// ✅ Test passed
// 🛑 Stopping mock server...
// 🧹 Cleaning up...
각 패턴을 사용하는 경우
✅ 다음과 같은 경우에 명령을 사용하세요:
- 유용하다 실행 취소/다시 실행 응용 프로그램에서
- 당신이 원하는 대기줄 작업(작업 대기열)
- 작업을 사용하여 개체를 매개변수화해야 합니다.
- 로깅 및 트랜잭션: 실행된 명령 기록
✅ 다음과 같은 경우 책임 사슬을 사용하세요.
- 여러 개체가 요청을 처리할 수 있지만 당신은 어느 쪽인지 몰라요
- 당신이 원하는 미들웨어/파이프라인 순차적 처리를 위해
- 핸들러 세트는 동적으로 변경될 수 있습니다.
- 이벤트 관리, 로깅, 인증
✅ 다음과 같은 경우 템플릿 방법을 사용하세요.
- 당신은 알고리즘을 가지고 있습니다 공통된 구조이지만 다른 단계
- 유사한 코드의 중복을 피하고 싶습니다.
- 하위 클래스가 재정의할 수 있는 단계를 제어해야 합니다.
- 프레임워크: 뼈대 정의, 사용자 구현 세부 사항
실제 예: 결제 시스템
// COMMAND: Transazioni con undo
interface PaymentCommand {{ '{' }}
execute(): void;
undo(): void;
{{ '}' }}
class ChargeCommand implements PaymentCommand {{ '{' }}
constructor(
private account: string,
private amount: number
) {{ '{' }}{{ '}' }}
execute(): void {{ '{' }}
console.log(`💳 Charged ${{ '{' }}this.amount{{ '}' }} to ${{ '{' }}this.account{{ '}' }}`);
{{ '}' }}
undo(): void {{ '{' }}
console.log(`↩️ Refunded ${{ '{' }}this.amount{{ '}' }} to ${{ '{' }}this.account{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// CHAIN: Validazione pagamento
abstract class PaymentHandler {{ '{' }}
protected next: PaymentHandler | null = null;
setNext(handler: PaymentHandler): PaymentHandler {{ '{' }}
this.next = handler;
return handler;
{{ '}' }}
handle(amount: number): boolean {{ '{' }}
if (this.validate(amount)) {{ '{' }}
return this.next ? this.next.handle(amount) : true;
{{ '}' }}
return false;
{{ '}' }}
protected abstract validate(amount: number): boolean;
{{ '}' }}
class AmountValidator extends PaymentHandler {{ '{' }}
protected validate(amount: number): boolean {{ '{' }}
if (amount > 0) {{ '{' }}
console.log("✅ Amount valid");
return true;
{{ '}' }}
console.log("❌ Invalid amount");
return false;
{{ '}' }}
{{ '}' }}
class FraudDetector extends PaymentHandler {{ '{' }}
protected validate(amount: number): boolean {{ '{' }}
if (amount < 10000) {{ '{' }}
console.log("✅ No fraud detected");
return true;
{{ '}' }}
console.log("🚨 Potential fraud");
return false;
{{ '}' }}
{{ '}' }}
// TEMPLATE METHOD: Processamento pagamento
abstract class PaymentProcessor {{ '{' }}
public processPayment(amount: number): void {{ '{' }}
if (!this.validatePayment(amount)) return;
this.deductAmount(amount);
this.sendReceipt();
{{ '}' }}
protected abstract validatePayment(amount: number): boolean;
protected abstract deductAmount(amount: number): void;
protected sendReceipt(): void {{ '{' }}
console.log("📧 Receipt sent");
{{ '}' }}
{{ '}' }}
class CreditCardProcessor extends PaymentProcessor {{ '{' }}
private validator = new AmountValidator();
constructor() {{ '{' }}
super();
this.validator.setNext(new FraudDetector());
{{ '}' }}
protected validatePayment(amount: number): boolean {{ '{' }}
return this.validator.handle(amount);
{{ '}' }}
protected deductAmount(amount: number): void {{ '{' }}
console.log(`💳 Card charged ${{ '{' }}amount{{ '}' }}`);
{{ '}' }}
{{ '}' }}
// Utilizzo combinato
const processor = new CreditCardProcessor();
processor.processPayment(500);
// ✅ Amount valid
// ✅ No fraud detected
// 💳 Card charged 500
// 📧 Receipt sent
결론
이 세 가지 행동 패턴은 서로 다르지만 상호보완적인 문제를 해결합니다. 명령 실행 취소/다시 실행 및 대기열에 대한 작업을 캡슐화합니다. 체인 책임 유연한 핸들러 파이프라인 생성, e 템플릿 방법 재사용 가능한 알고리즘으로 중복을 줄입니다. 이들을 결합하면 우아한 건축물이 탄생합니다. 유지 관리가 가능합니다.
🎯 핵심 포인트
- 명령 = 객체로 요청, 실행 취소/다시 실행, 작업 대기열
- 책임 체인 = 핸들러 체인, 미들웨어
- 템플릿 방법 = 뼈대 알고리즘, 후크 포인트
- 실행 취소할 수 없는 작업에 명령 사용
- 파이프라인 처리에 체인 사용
- 중복을 피하기 위해 템플릿 방법을 사용하십시오.







