The command patternOpen in a new tab helps us encapsulate requests in order to perform certain operations, like logging, queuing and filtering.
We start with the interface:
export interface Command<T> {
execute(): Promise<T>
}
And then we can look at a specific command, for example the one used to retrieve this article:
import { Command } from '../../infrastructure/Command'
import { Article, ArticlesRepository } from '../../domain/articles'
import { Id } from '../../domain'
import { Locale, Translator } from '../../domain/language'
import { ArticlesFileRepository } from '../../infrastructure/articles/ArticlesFileRepository'
import { FileLoader } from '../../infrastructure/FileLoader'
import { TranslationService } from '../../domain/TranslationService'
export class GetArticle implements Command<Article> {
constructor(
private readonly articlesRepository: ArticlesRepository,
private readonly id: Id,
private readonly locale: Locale,
) {}
async execute(): Promise<Article> {
return this.articlesRepository.findOneByLocale(this.id, this.locale)
}
static create(context: { id: Id; locale: Locale }) {
return new GetArticle(
new ArticlesFileRepository(FileLoader.create(), TranslationService.create(Translator.create())),
context.id,
context.locale,
)
}
}
This command is responsible for obtaining a certain article using a repositoryOpen in a new tab, where and how do we get this data we neither know nor care, that's responsibility of another class.
This command represents a Use CaseOpen in a new tab of my application. Right now it only needs to get the article from the repository but in the feature it could handle if a user has read the article, or if the user is a PRO user and then can read all articles instead of a subset of articles or anything we'd like.
Who builds the command? Whoever uses it:
const article = await GetArticle.create({
id: 'use-cases-and-commands',
locale: Locale.EN,
}).execute()
I'm using inversion of controlOpen in a new tab to provide the dependencies needed for the GetArticle use case to work. In this case I'm going from an abstraction (ArticlesRepository) to a concreation (ArticlesFileRepository). If tomorrow I decide to serve the articles via API I would only need to change the factory.
What is also interesting about commands is that they are easily augmented. For example we can log when a command is executed without touching any commands using the Decorator PatternOpen in a new tab:
import { Command } from './Command'
import { Logger } from './Logger'
export class LoggerCommandDecorator<T> implements Command<T> {
constructor(
private readonly decoratedCommand: Command<T>,
private readonly logger: Logger,
) {}
execute(): Promise<T> {
this.logger.log(
(this.decoratedCommand as Object).constructor.name + ' - ' + Object.getOwnPropertyNames(this.decoratedCommand),
)
return this.decoratedCommand.execute()
}
}
Then, using a UserCaseDecorator I specify which decorators I want for all my use cases:
import { Command } from '../../infrastructure/Command'
import { LoggerCommandDecorator } from '../../infrastructure/LoggerCommandDecorator'
import { Logger } from '../../infrastructure/Logger'
export class UseCaseDecorator {
private static readonly logger = Logger.create({
stdout: { error: console.error, info: console.log, warn: console.warn },
})
static decorate<T>(command: Command<T>) {
return new LoggerCommandDecorator<T>(command, UseCaseDecorator.logger)
}
}
And then in each use case we use the UseCaseDecorator like so:
import { Command } from '../../infrastructure/Command'
import { Article, ArticlesRepository } from '../../domain/articles'
import { Id } from '../../domain'
import { Locale, Translator } from '../../domain/language'
import { UseCaseDecorator } from './UseCaseDecorator'
import { ArticlesFileRepository } from '../../infrastructure/articles/ArticlesFileRepository'
import { FileLoader } from '../../infrastructure/FileLoader'
import { TranslationService } from '../../domain/TranslationService'
export class GetArticle implements Command<Article> {
constructor(
private readonly articlesRepository: ArticlesRepository,
private readonly id: Id,
private readonly locale: Locale,
) {}
async execute(): Promise<Article> {
return this.articlesRepository.findOneByLocale(this.id, this.locale)
}
static create(context: { id: Id; locale: Locale }) {
return UseCaseDecorator.decorate(
new GetArticle(
new ArticlesFileRepository(FileLoader.create(), TranslationService.create(Translator.create())),
context.id,
context.locale,
),
)
}
}
And we could create as many decorators as we want and use composition to give more behaviour to our commands.


