Command паттерн — это поведенческий шаблон проектирования, который позволяет инкапсулировать запрос как объект, отделяя отправителя запроса от его получателя. В контексте фреймворка Lit этот паттерн становится особенно полезным при организации сложной логики компонентов, обработке событий и управлении состоянием.
Command (Команда) Представляет собой абстракцию
действия, которое может быть выполнено. В Lit команда часто реализуется
как класс или объект с методом execute().
class Command {
execute() {
throw new Error('Метод execute должен быть реализован в подклассе');
}
}ConcreteCommand (Конкретная команда) Реализует конкретное действие, связывая его с объектом-получателем (Receiver).
class AddItemCommand extends Command {
constructor(receiver, item) {
super();
this.receiver = receiver;
this.item = item;
}
execute() {
this.receiver.addItem(this.item);
}
}Receiver (Получатель) Объект, который выполняет фактическую работу. В Lit это может быть компонент или сервис, отвечающий за изменение состояния, выполнение анимации или отправку запроса на сервер.
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(item) {
this.items.push(item);
console.log(`Добавлен товар: ${item}`);
}
}Invoker (Инициатор) Компонент, который вызывает команды. В Lit это может быть обработчик событий, метод жизненного цикла или кнопка интерфейса.
class ButtonInvoker {
constructor() {
this.command = null;
}
setCommand(command) {
this.command = command;
}
click() {
if (this.command) {
this.command.execute();
}
}
}Lit-компоненты строятся на основе классов, расширяющих
LitElement. Command паттерн помогает:
Пример интеграции:
import { LitElement, html, css } from 'lit';
class ShoppingCartElement extends LitElement {
static styles = css`
button { margin: 5px; padding: 10px; }
`;
constructor() {
super();
this.cart = new ShoppingCart();
this.invoker = new ButtonInvoker();
}
addItemHandler(item) {
const command = new AddItemCommand(this.cart, item);
this.invoker.setCommand(command);
this.invoker.click();
}
render() {
return html`
<button @click=${() => this.addItemHandler('Яблоко')}>Добавить яблоко</button>
<button @click=${() => this.addItemHandler('Банан')}>Добавить банан</button>
`;
}
}
customElements.define('shopping-cart-element', ShoppingCartElement);
В этом примере:
ShoppingCart, выполняет
добавление товара.AddItemCommand,
связывает действие с получателем.ButtonInvoker, инициирует
выполнение команды.ShoppingCartElement, формирует команду и передает её
инициатору.Поддержка отмены действий (Undo/Redo) Command паттерн позволяет легко реализовать историю действий:
class UndoableCommand extends Command {
undo() {
throw new Error('Метод undo должен быть реализован');
}
}
class AddItemUndoableCommand extends AddItemCommand {
undo() {
this.receiver.items.pop();
console.log(`Отменено добавление товара: ${this.item}`);
}
}
Хранение очереди команд Команды можно помещать в очередь для последовательного выполнения, что удобно для асинхронных операций или анимаций:
class CommandQueue {
constructor() {
this.queue = [];
}
add(command) {
this.queue.push(command);
}
run() {
while(this.queue.length > 0) {
const command = this.queue.shift();
command.execute();
}
}
}
Command паттерн в Lit позволяет строить компоненты с чистой архитектурой, отделяя UI от бизнес-логики и создавая гибкую систему управления действиями.