Design Patterns: Yazılım Tasarım Kalıpları
Design patterns, yazılım geliştirmede karşılaşılan yaygın problemlere kanıtlanmış çözümlerdir.
Creational Patterns
Singleton
Tek bir instance garanti eder:
class Database {
static instance = null;
constructor() {
if (Database.instance) {
return Database.instance;
}
this.connection = this.connect();
Database.instance = this;
}
connect() {
console.log('Connecting to database...');
return { connected: true };
}
}
const db1 = new Database();
const db2 = new Database();
console.log(db1 === db2); // true
Factory
Object oluşturmayı abstraktlar:
class UserFactory {
createUser(type, data) {
switch (type) {
case 'admin':
return new AdminUser(data);
case 'customer':
return new CustomerUser(data);
case 'guest':
return new GuestUser(data);
default:
throw new Error('Unknown user type');
}
}
}
const factory = new UserFactory();
const admin = factory.createUser('admin', { name: 'John' });
Builder
Complex object construction:
class QueryBuilder {
constructor() {
this.query = {};
}
select(fields) {
this.query.select = fields;
return this;
}
from(table) {
this.query.from = table;
return this;
}
where(condition) {
this.query.where = condition;
return this;
}
build() {
return `SELECT ${this.query.select} FROM ${this.query.from} WHERE ${this.query.where}`;
}
}
const query = new QueryBuilder()
.select('*')
.from('users')
.where('age > 18')
.build();
Structural Patterns
Decorator
Dinamik olarak functionality ekler:
class Coffee {
cost() {
return 5;
}
description() {
return 'Coffee';
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
description() {
return this.coffee.description() + ', Milk';
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1;
}
description() {
return this.coffee.description() + ', Sugar';
}
}
let myCoffee = new Coffee();
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);
console.log(myCoffee.description()); // Coffee, Milk, Sugar
console.log(myCoffee.cost()); // 8
Adapter
Incompatible interface’leri uyumlu hale getirir:
// Old API
class OldPaymentSystem {
processOldPayment(amount) {
console.log(`Processing $${amount} via old system`);
}
}
// New API
class NewPaymentSystem {
processPayment({ amount, currency }) {
console.log(`Processing ${amount} ${currency}`);
}
}
// Adapter
class PaymentAdapter {
constructor(oldSystem) {
this.oldSystem = oldSystem;
}
processPayment({ amount, currency }) {
// Convert new format to old format
this.oldSystem.processOldPayment(amount);
}
}
const oldSystem = new OldPaymentSystem();
const adapter = new PaymentAdapter(oldSystem);
adapter.processPayment({ amount: 100, currency: 'USD' });
Behavioral Patterns
Observer (Pub/Sub)
Event-driven communication:
class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
}
const emitter = new EventEmitter();
emitter.on('userLoggedIn', (user) => {
console.log(`Welcome ${user.name}!`);
});
emitter.on('userLoggedIn', (user) => {
console.log('Logging user activity...');
});
emitter.emit('userLoggedIn', { name: 'John' });
Strategy
Algorithm’ları runtime’da değiştir:
class PaymentStrategy {
pay(amount) {
throw new Error('Must implement pay method');
}
}
class CreditCardPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paid $${amount} with credit card`);
}
}
class PayPalPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paid $${amount} with PayPal`);
}
}
class CryptoPayment extends PaymentStrategy {
pay(amount) {
console.log(`Paid $${amount} with cryptocurrency`);
}
}
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
processPayment(amount) {
this.strategy.pay(amount);
}
}
const processor = new PaymentProcessor(new CreditCardPayment());
processor.processPayment(100);
processor.setStrategy(new PayPalPayment());
processor.processPayment(200);
Command
Request’leri object olarak encapsulate et:
class Command {
execute() {}
undo() {}
}
class AddTextCommand extends Command {
constructor(editor, text) {
super();
this.editor = editor;
this.text = text;
}
execute() {
this.editor.content += this.text;
}
undo() {
this.editor.content = this.editor.content.slice(0, -this.text.length);
}
}
class TextEditor {
constructor() {
this.content = '';
this.history = [];
}
executeCommand(command) {
command.execute();
this.history.push(command);
}
undo() {
const command = this.history.pop();
if (command) command.undo();
}
}
const editor = new TextEditor();
editor.executeCommand(new AddTextCommand(editor, 'Hello '));
editor.executeCommand(new AddTextCommand(editor, 'World!'));
console.log(editor.content); // Hello World!
editor.undo();
console.log(editor.content); // Hello
Design patterns ile maintainable kod yazın!