An Interest In:
Web News this Week
- April 28, 2024
- April 27, 2024
- April 26, 2024
- April 25, 2024
- April 24, 2024
- April 23, 2024
- April 22, 2024
Implementando o padro Specification no Node.js com TypeScript
O padro Specification um padro de projeto de software que permite definir regras de negcio em um formato legvel e reutilizvel. Ele particularmente til em aplicaes que precisam implementar regras de negcio complexas que envolvem mltiplas entidades. Neste artigo, vamos ver como implementar o padro Specification em uma aplicao Node.js
com TypeScript.
Definindo a entidade
Para exemplificar o uso do padro Specification, vamos criar uma entidade simples chamada Transaction
. Ela possui trs propriedades: amount
(valor da transao), date
(data da transao) e description
(descrio da transao).
Crie um arquivo chamado transaction.ts
na pasta src/entities
com o seguinte contedo:
export class Transaction { constructor( public readonly amount: number, public readonly date: Date, public readonly description: string, ) {}}
Esta classe representa uma transao financeira com os seguintes atributos:
amount
: o valor da transaodate
: a data da transaodescription
: uma descrio da transao
Criando as regras de negcio
Agora que temos a entidade de transao, vamos criar as regras de negcio para verificar se uma transao vlida ou no. Crie um arquivo chamado specification.ts
na pasta src/specifications
com o seguinte contedo:
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); }}
Este arquivo define uma interface Specification que representa uma regra de negcio e uma classe CompositeSpecification que implementa a lgica de combinao de regras de negcio.
As classes AndSpecification, OrSpecification e NotSpecification so subclasses de CompositeSpecification que implementam as operaes lgicas AND, OR e NOT, respectivamente.
Crie um arquivo chamado transaction.ts
na pasta src/specifications
com o seguinte contedo:
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); } })(); }}
A classe TransactionSpecification uma subclasse de CompositeSpecification que define as regras de negcio especficas para a entidade Transaction.
As funes estticas amountIsGreaterThan, amountIsLessThan, dateIsGreaterThan, dateIsLessThan e descriptionContains retornam instncias de TransactionSpecification que representam cada uma das regras de negcio. O mtodo isSatisfiedBy
contem a composio da regra. a classe esta com as subsclasses publica a modo que ao criar uma outra regra pode ser apenas ajustada e extendida para compor.
Utilizando as regras de negcio
Agora que temos as regras de negcio definidas, podemos utiliz-las para validar uma transao. Crie um arquivo chamado transaction.ts
na pasta src/validators
com o seguinte contedo:
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 validatorconst transaction = new Transaction(100, new Date(), 'Compra no supermercado');const validator = new TransactionValidator()console.log(validator.validate(transaction)); // true
Este arquivo define a classe TransactionValidator
, que recebe uma instncia de Specification<Transaction>
no construtor e possui um mtodo validate que recebe uma transao e retorna um valor booleano indicando se a transao vlida ou no.
No exemplo acima, criamos uma transao com valor 100, data new Date() e descrio 'Compra no supermercado'. Em seguida, criamos uma instncia de TransactionValidator
as regra de negcio verifica se o valor da transao maior que 50, se a data da transao maior que 01/01/2022 e se a descrio da transao contm a palavra 'supermercado'. Finalmente, chamamos o mtodo validate passando a transao criada e exibimos o resultado no console.
Concluso
Neste artigo, vimos como implementar o padro Specification
em uma aplicao Node.js
com TypeScript
. Criamos uma entidade Transaction
, definimos regras de negcio para validar uma transao utilizando a classe TransactionSpecification
e criamos um validador de transaes utilizando a classe TransactionValidator.
O padro Specification
pode ser aplicado em diversos contextos e uma boa opo quando precisamos implementar regras de negcio complexas que envolvem mltiplas entidades. Com ele, podemos tornar o cdigo mais modular, fcil de manter e extensvel.
Segue exemplo no github: https://github.com/jhonesgoncalves/example-specification-ts
Original Link: https://dev.to/jhonesgoncalves/implementando-o-padrao-specification-no-nodejs-com-typescript-15m0
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To