🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

أنماط تصميم TypeScript 2026: Singleton، Factory، Observer، Repository

⏱️6 min read  ·  1,146 words

تستفيد أنماط تصميم TypeScript في عام 2026 من القوة الكاملة لنظام الكتابة لإنشاء تعليمات برمجية ذاتية التوثيق وآمنة وقابلة للتوسيع. يغطي هذا الدليل الأنماط الأكثر قيمة لتطبيقات TypeScript في العالم الحقيقي، بدءًا من الأنماط الإبداعية الأساسية وحتى التقنيات الوظيفية المتقدمة.

نمط سينجلتون

class DatabasePool {
  private static instance: DatabasePool | null = null;
  private connections: Connection[] = [];

  private constructor(private readonly config: DBConfig) {
    // Private constructor prevents direct instantiation
  }

  static getInstance(config?: DBConfig): DatabasePool {
    if (!DatabasePool.instance) {
      if (!config) throw new Error("Config required for first initialization");
      DatabasePool.instance = new DatabasePool(config);
    }
    return DatabasePool.instance;
  }

  async query<T>(sql: string, params: unknown[]): Promise<T[]> {
    const conn = await this.acquire();
    try {
      return await conn.execute<T>(sql, params);
    } finally {
      this.release(conn);
    }
  }

  private async acquire(): Promise<Connection> {
    // Get available connection from pool
    return this.connections.pop() ?? await createConnection(this.config);
  }

  private release(conn: Connection): void {
    this.connections.push(conn);
  }
}

// Usage
const db = DatabasePool.getInstance({ host: "localhost", port: 5432 });
const users = await db.query<User>("SELECT * FROM users WHERE id = $1", [1]);

نمط البناء

interface QueryConfig {
  table: string;
  conditions: string[];
  columns: string[];
  limit?: number;
  offset?: number;
  orderBy?: { column: string; direction: "ASC" | "DESC" };
}

class QueryBuilder {
  private config: QueryConfig;

  constructor(table: string) {
    this.config = { table, conditions: [], columns: [] };
  }

  select(...columns: string[]): this {
    this.config.columns.push(...columns);
    return this;
  }

  where(condition: string): this {
    this.config.conditions.push(condition);
    return this;
  }

  orderBy(column: string, direction: "ASC" | "DESC" = "ASC"): this {
    this.config.orderBy = { column, direction };
    return this;
  }

  limit(n: number): this {
    this.config.limit = n;
    return this;
  }

  offset(n: number): this {
    this.config.offset = n;
    return this;
  }

  build(): string {
    const cols = this.config.columns.length ? this.config.columns.join(", ") : "*";
    let query = `SELECT ${cols} FROM ${this.config.table}`;
    if (this.config.conditions.length) {
      query += ` WHERE ${this.config.conditions.join(" AND ")}`;
    }
    if (this.config.orderBy) {
      query += ` ORDER BY ${this.config.orderBy.column} ${this.config.orderBy.direction}`;
    }
    if (this.config.limit) query += ` LIMIT ${this.config.limit}`;
    if (this.config.offset) query += ` OFFSET ${this.config.offset}`;
    return query;
  }
}

const query = new QueryBuilder("users")
  .select("id", "name", "email")
  .where("active = true")
  .where("role = 'admin'")
  .orderBy("created_at", "DESC")
  .limit(10)
  .build();

نمط المصنع

interface NotificationSender {
  send(to: string, message: string): Promise<void>;
}

class EmailSender implements NotificationSender {
  async send(to: string, message: string): Promise<void> {
    await sendEmail({ to, subject: "Notification", body: message });
  }
}

class SMSSender implements NotificationSender {
  async send(to: string, message: string): Promise<void> {
    await sendSMS({ to, message: message.slice(0, 160) });
  }
}

class PushSender implements NotificationSender {
  async send(to: string, message: string): Promise<void> {
    await sendPushNotification({ userId: to, body: message });
  }
}

type NotificationType = "email" | "sms" | "push";

function createNotificationSender(type: NotificationType): NotificationSender {
  const senders: Record<NotificationType, () => NotificationSender> = {
    email: () => new EmailSender(),
    sms: () => new SMSSender(),
    push: () => new PushSender(),
  };
  const factory = senders[type];
  if (!factory) throw new Error(`Unknown notification type: ${type}`);
  return factory();
}

// Usage
const sender = createNotificationSender("email");
await sender.send("alice@example.com", "Your order has shipped!");

نمط باعث المراقب/الحدث

type EventMap = {
  "user:created": { id: number; email: string };
  "order:placed": { orderId: string; total: number; userId: number };
  "payment:failed": { orderId: string; error: string };
};

type EventHandler<T> = (data: T) => void | Promise<void>;

class TypedEventEmitter<Events extends Record<string, unknown>> {
  private handlers: Partial<{
    [K in keyof Events]: EventHandler<Events[K]>[];
  }> = {};

  on<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this {
    if (!this.handlers[event]) {
      (this.handlers[event] as EventHandler<Events[K]>[]) = [];
    }
    (this.handlers[event] as EventHandler<Events[K]>[]).push(handler);
    return this;
  }

  off<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this {
    const handlers = this.handlers[event] as EventHandler<Events[K]>[] | undefined;
    if (handlers) {
      (this.handlers[event] as EventHandler<Events[K]>[]) = handlers.filter(h => h !== handler);
    }
    return this;
  }

  async emit<K extends keyof Events>(event: K, data: Events[K]): Promise<void> {
    const handlers = (this.handlers[event] as EventHandler<Events[K]>[] | undefined) ?? [];
    await Promise.all(handlers.map(h => h(data)));
  }
}

const emitter = new TypedEventEmitter<EventMap>();

emitter.on("user:created", async ({ email }) => {
  await sendWelcomeEmail(email);
});

emitter.on("order:placed", async ({ orderId, userId }) => {
  await sendOrderConfirmation(userId, orderId);
});

// TypeScript enforces correct event data types
await emitter.emit("user:created", { id: 1, email: "alice@example.com" });
// await emitter.emit("user:created", { id: 1 });  // TypeScript error!

نمط الاستراتيجية

interface PaymentStrategy {
  charge(amount: number, currency: string): Promise<PaymentResult>;
  refund(transactionId: string, amount: number): Promise<void>;
}

class StripeStrategy implements PaymentStrategy {
  constructor(private apiKey: string) {}

  async charge(amount: number, currency: string): Promise<PaymentResult> {
    const charge = await stripe.charges.create({ amount, currency });
    return { transactionId: charge.id, status: "success" };
  }

  async refund(transactionId: string, amount: number): Promise<void> {
    await stripe.refunds.create({ charge: transactionId, amount });
  }
}

class PayPalStrategy implements PaymentStrategy {
  async charge(amount: number, currency: string): Promise<PaymentResult> {
    const order = await paypal.orders.create({ amount, currency });
    return { transactionId: order.id, status: "success" };
  }

  async refund(transactionId: string, amount: number): Promise<void> {
    await paypal.captures.refund(transactionId, { amount });
  }
}

class PaymentProcessor {
  constructor(private strategy: PaymentStrategy) {}

  setStrategy(strategy: PaymentStrategy): void {
    this.strategy = strategy;
  }

  async processPayment(amount: number, currency: string): Promise<PaymentResult> {
    return this.strategy.charge(amount, currency);
  }
}

// Switch strategy at runtime
const processor = new PaymentProcessor(new StripeStrategy(process.env.STRIPE_KEY!));
const result = await processor.processPayment(9999, "AUD");

// Switch to PayPal for specific users
processor.setStrategy(new PayPalStrategy());

نمط المستودع مع الأدوية العامة

interface Repository<T, ID = number> {
  findById(id: ID): Promise<T | null>;
  findAll(options?: FindOptions): Promise<T[]>;
  create(data: Omit<T, "id" | "createdAt" | "updatedAt">): Promise<T>;
  update(id: ID, data: Partial<T>): Promise<T>;
  delete(id: ID): Promise<void>;
  count(where?: Partial<T>): Promise<number>;
}

interface FindOptions {
  limit?: number;
  offset?: number;
  orderBy?: string;
  where?: Record<string, unknown>;
}

// Base implementation
abstract class BaseRepository<T extends { id: number }> implements Repository<T> {
  constructor(
    protected readonly db: Database,
    protected readonly tableName: string
  ) {}

  async findById(id: number): Promise<T | null> {
    const result = await this.db.query<T>(
      `SELECT * FROM ${this.tableName} WHERE id = $1`, [id]
    );
    return result[0] ?? null;
  }

  async create(data: Omit<T, "id" | "createdAt" | "updatedAt">): Promise<T> {
    const keys = Object.keys(data);
    const values = Object.values(data);
    const placeholders = keys.map((_, i) => `$${i + 1}`).join(", ");
    const result = await this.db.query<T>(
      `INSERT INTO ${this.tableName} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`,
      values
    );
    return result[0];
  }

  // Other methods...
  async findAll(_opts?: FindOptions): Promise<T[]> { return []; }
  async update(_id: number, _data: Partial<T>): Promise<T> { return {} as T; }
  async delete(_id: number): Promise<void> {}
  async count(_where?: Partial<T>): Promise<number> { return 0; }
}

// Specific implementation
class UserRepository extends BaseRepository<User> {
  constructor(db: Database) { super(db, "users"); }

  async findByEmail(email: string): Promise<User | null> {
    const result = await this.db.query<User>(
      "SELECT * FROM users WHERE email = $1", [email]
    );
    return result[0] ?? null;
  }

  async findActive(): Promise<User[]> {
    return this.db.query<User>("SELECT * FROM users WHERE active = true");
  }
}

تعد أنماط تصميم TypeScript في عام 2026 قوية على وجه التحديد لأن نظام الكتابة يفرض الاستخدام الصحيح في وقت الترجمة – يلتقط نمط المراقب أعلاه بيانات الأحداث الخاطئة قبل وقت التشغيل، ويضمن نمط المستودع الوصول الآمن إلى قاعدة البيانات. قم بتطبيق الأنماط لحل المشكلات الحقيقية، وليس كنمط من أجل الهندسة المفرطة.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা