أنماط التصميم في JavaScript مع أمثلة: من الألف إلى الياء
أنماط التصميم (design patterns) هي حلول مثبتة للمشكلات النمطية التي تظهر أثناء تطوير البرمجيات. في JavaScript، خاصة في بيئة Node.js، يساعد فهم هذه القوالب في كتابة كود أكثر نظافة ونمطية وقابلية للتوسع. في هذه المقالة، سنستعرض الفئات الرئيسية لأنماط التصميم مع أمثلة توضيحية.
1. أنماط الإنشاء (Creational Patterns)
تدير هذه الأنماط عملية إنشاء الكائنات، مما يجعل النظام مستقلاً عن طريقة إنشائها.
1.1. المفرد (Singleton)
يضمن أن الفئة لها مثيل واحد فقط، ويوفر نقطة وصول عالمية إليه. في Node.js، يتم تخزين الوحدات النمطية مؤقتًا افتراضيًا، مما يبسط التنفيذ.
class DatabaseConnection { constructor() { if (DatabaseConnection.instance) { return DatabaseConnection.instance; } this.connection = null; DatabaseConnection.instance = this; }
connect() { if (!this.connection) { this.connection = { status: 'connected' }; console.log('اتصال جديد بقاعدة البيانات'); } return this.connection; }}
const db1 = new DatabaseConnection();const db2 = new DatabaseConnection();console.log(db1 === db2); // true1.2. طريقة المصنع (Factory Method)
تحدد واجهة لإنشاء كائن، ولكنها تسمح للفئات الفرعية بتغيير نوع الكائن الذي يتم إنشاؤه. مثالية لإنشاء أنواع مختلفة من المسجلات (loggers).
class LoggerFactory { createLogger(type) { switch (type) { case 'console': return new ConsoleLogger(); case 'file': return new FileLogger(); default: throw new Error('نوع مسجل غير معروف'); } }}
class ConsoleLogger { log(message) { console.log(message); }}
class FileLogger { log(message) { console.log(`[ملف]: ${message}`); }}
const factory = new LoggerFactory();const logger = factory.createLogger('console');logger.log('رسالة اختبارية');2. أنماط الهيكلة (Structural Patterns)
تصف طرق دمج الفئات والكائنات لإنشاء هياكل أكبر.
2.1. المُزَخْرِف (Decorator)
يضيف ديناميكيًا مسؤوليات جديدة إلى الكائن. في JavaScript، غالبًا ما يتم تنفيذ المُزَخْرِفات من خلال دوال عالية المستوى أو النماذج الأولية (prototypes).
class Coffee { cost() { return 10; } description() { return 'قهوة'; }}
function withMilk(coffee) { coffee.cost = () => coffee.cost() + 5; coffee.description = () => coffee.description() + ', مع حليب'; return coffee;}
function withSugar(coffee) { coffee.cost = () => coffee.cost() + 2; coffee.description = () => coffee.description() + ', مع سكر'; return coffee;}
let myCoffee = new Coffee();myCoffee = withMilk(myCoffee);myCoffee = withSugar(myCoffee);console.log(`${myCoffee.description()}: ${myCoffee.cost()} روبل`); // قهوة, مع حليب, مع سكر: 17 روبل2.2. المُكَيِّف (Adapter)
يحول واجهة فئة إلى واجهة أخرى يتوقعها العميل. مفيد بشكل خاص عند دمج المكتبات الخارجية.
class OldAPI { getUserData() { return { name: 'إيفان', age: 25, email: 'ivan@example.com' }; }}
class NewAPI { fetchUser() { return { fullName: 'إيفان بيتروف', yearsOld: 26, contact: 'ivan@example.com' }; }}
class UserAdapter { constructor(api) { this.api = api; }
getUserData() { const data = this.api.fetchUser(); return { name: data.fullName, age: data.yearsOld, email: data.contact }; }}
const adapter = new UserAdapter(new NewAPI());console.log(adapter.getUserData()); // { name: 'إيفان بيتروف', age: 26, email: 'ivan@example.com' }3. أنماط السلوك (Behavioral Patterns)
تحدد الخوارزم