برنامه نویسی

پیاده سازی الگوی Specification در Node.js با TypeScript

الگوی مشخصات یک الگوی طراحی نرم افزار است که به شما امکان می دهد قوانین تجاری را در قالبی قابل خواندن و قابل استفاده مجدد تعریف کنید. این به ویژه در برنامه هایی مفید است که نیاز به پیاده سازی قوانین پیچیده تجاری شامل چندین نهاد دارند. در این مقاله قصد داریم نحوه پیاده سازی الگوی Specification را در یک اپلیکیشن ببینیم. Node.js com TypeScript.

تعریف موجودیت

برای مثال استفاده از الگوی Specification، اجازه دهید یک موجودیت ساده به نام ایجاد کنیم Transaction. دارای سه خاصیت است: amount (مقدار تراکنش)، date (تاریخ معامله) و description (شرح معامله).

یک فایل به نام ایجاد کنید transaction.ts آن پاستا src/entities با محتوای زیر:

export class Transaction {
  constructor(
    public readonly amount: number,
    public readonly date: Date,
    public readonly description: string,
  ) {}
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کلاس یک تراکنش مالی با ویژگی های زیر را نشان می دهد:

amount: مبلغ معامله
date: تاریخ معامله
description: شرح معامله

ایجاد قوانین کسب و کار

اکنون که موجودیت تراکنش را داریم، بیایید قوانین تجاری را ایجاد کنیم تا بررسی کنیم که آیا تراکنش معتبر است یا خیر. یک فایل به نام ایجاد کنید specification.ts آن پاستا src/specifications با محتوای زیر:

export interface Specification<T> {
  isSatisfiedBy(candidate: T): boolean;
  and(other: Specification<T>): Specification<T>;
  or(other: Specification<T>): Specification<T>;
  not(): Specification<T>;
}

export class CompositeSpecification<T> implements Specification<T> {
  public isSatisfiedBy(candidate: T): boolean {
    throw new Error("Not implemented");
  }

  public and(other: Specification<T>): Specification<T> {
    return new AndSpecification(this, other);
  }

  public or(other: Specification<T>): Specification<T> {
    return new OrSpecification(this, other);
  }

  public not(): Specification<T> {
    return new NotSpecification(this);
  }
}

class AndSpecification<T> extends CompositeSpecification<T> {
  constructor(
    private readonly left: Specification<T>,
    private readonly right: Specification<T>
  ) {
    super();
  }

  public isSatisfiedBy(candidate: T): boolean {
    return (
      this.left.isSatisfiedBy(candidate) && this.right.isSatisfiedBy(candidate)
    );
  }
}

export class OrSpecification<T> extends CompositeSpecification<T> {
  constructor(
    private readonly left: Specification<T>,
    private readonly right: Specification<T>
  ) {
    super();
  }

  public isSatisfiedBy(candidate: T): boolean {
    return (
      this.left.isSatisfiedBy(candidate) || this.right.isSatisfiedBy(candidate)
    );
  }
}

export class NotSpecification<T> extends CompositeSpecification<T> {
  constructor(private readonly specification: Specification<T>) {
    super();
  }

  public isSatisfiedBy(candidate: T): boolean {
    return !this.specification.isSatisfiedBy(candidate);
  }
}


وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این فایل یک رابط Specification تعریف می کند که یک قانون تجاری را نشان می دهد و یک کلاس CompositeSpecification که منطق ترکیب قوانین تجاری را پیاده سازی می کند.

کلاس‌های AndSpecification، OrSpecification و NotSpecification زیر کلاس‌های CompositeSpecification هستند که به ترتیب عملیات‌های منطقی AND، OR و NOT را پیاده‌سازی می‌کنند.

یک فایل به نام ایجاد کنید transaction.ts آن پاستا src/specifications با محتوای زیر:


import { Transaction } from "../entities/transaction";
import { CompositeSpecification } from "./specification";

export class TransactionSpecification extends CompositeSpecification<Transaction> {
  public isSatisfiedBy(candidate: Transaction): boolean {
    return TransactionSpecification.amountIsGreaterThan(50)
      .and(TransactionSpecification.dateIsGreaterThan(new Date(2022, 0, 1)))
      .and(TransactionSpecification.descriptionContains("supermercado"))
      .isSatisfiedBy(candidate);
  }

  public static amountIsGreaterThan(value: number): TransactionSpecification {
    return new (class extends TransactionSpecification {
      public isSatisfiedBy(candidate: Transaction): boolean {
        return candidate.amount > value;
      }
    })();
  }

  public static amountIsLessThan(value: number): TransactionSpecification {
    return new (class extends TransactionSpecification {
      public isSatisfiedBy(candidate: Transaction): boolean {
        return candidate.amount < value;
      }
    })();
  }

  public static dateIsGreaterThan(value: Date): TransactionSpecification {
    return new (class extends TransactionSpecification {
      public isSatisfiedBy(candidate: Transaction): boolean {
        return candidate.date > value;
      }
    })();
  }

  public static dateIsLessThan(value: Date): TransactionSpecification {
    return new (class extends TransactionSpecification {
      public isSatisfiedBy(candidate: Transaction): boolean {
        return candidate.date < value;
      }
    })();
  }

  public static descriptionContains(value: string): TransactionSpecification {
    return new (class extends TransactionSpecification {
      public isSatisfiedBy(candidate: Transaction): boolean {
        return candidate.description.includes(value);
      }
    })();
  }
}


وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کلاس TransactionSpecification یک زیر کلاس از CompositeSpecification است که قوانین تجاری خاصی را برای موجودیت Transaction تعریف می کند.

توابع ثابت مقدار مقدارIsGreaterThan، مقدارIsLessThan، dateIsGreaterThan، dateIsLessThan و description حاوی نمونه های بازگشتی TransactionSpecification است که هر یک از قوانین تجاری را نشان می دهد. روش isSatisfiedBy شامل ترکیب قانون است. کلاس در زیر کلاس عمومی قرار می گیرد تا هنگام ایجاد قانون دیگری بتوان آن را تغییر داد و برای نوشتن گسترش داد.

استفاده از قوانین کسب و کار

اکنون که قوانین تجاری را تعریف کرده ایم، می توانیم از آنها برای تأیید اعتبار یک تراکنش استفاده کنیم. یک فایل به نام ایجاد کنید transaction.ts آن پاستا src/validators با محتوای زیر:

import { Transaction } from './Transaction';
import { TransactionSpecification, Specification } from './TransactionSpecification';

export class TransactionValidator {
  constructor(private readonly specification: Specification<Transaction>) {}

  public validate(transaction: Transaction): boolean {
    return this.specification.isSatisfiedBy(transaction);
  }
}

// testando o validator
const transaction = new Transaction(100, new Date(), 'Compra no supermercado');

const validator = new TransactionValidator()

console.log(validator.validate(transaction)); // true

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این فایل کلاس را تعریف می کند TransactionValidator، که یک نمونه از Specification<Transaction> در سازنده و دارای یک متد اعتبارسنجی است که یک تراکنش را دریافت می کند و یک مقدار بولی را برمی گرداند که نشان می دهد آیا تراکنش معتبر است یا خیر.

در مثال بالا، ما یک تراکنش با مقدار 100، داده جدید Date() و توضیحات “خرید در سوپرمارکت” ایجاد کردیم. سپس یک نمونه از TransactionValidator قانون تجارت بررسی می‌کند که آیا ارزش معامله بیشتر از 50 است، آیا تاریخ معامله بزرگ‌تر از 01/01/2022 است و آیا توضیحات معامله حاوی کلمه “سوپرمارکت” است. در نهایت متد اعتبارسنجی را که تراکنش ایجاد شده را ارسال می کند فراخوانی می کنیم و نتیجه را در کنسول نمایش می دهیم.

نتیجه

در این مقاله نحوه پیاده سازی الگو را دیدیم Specification در یک برنامه کاربردی Node.js com TypeScript. ما یک موجودیت ایجاد می کنیم Transaction، ما قوانین تجاری را برای تأیید یک تراکنش با استفاده از کلاس تعریف می کنیم TransactionSpecification و با استفاده از کلاس TransactionValidator یک اعتبارسنجی تراکنش ایجاد می کنیم.

استاندارد Specification آن را می توان در زمینه های مختلف اعمال کرد و زمانی که نیاز به پیاده سازی قوانین پیچیده تجاری که شامل چندین نهاد است، گزینه خوبی است. با آن می‌توانیم کد را ماژولارتر، قابل نگهداری و توسعه‌پذیرتر کنیم.

در اینجا یک مثال در github آورده شده است: https://github.com/jhonesgoncalves/example-specification-ts

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا