Для каких кейсов какие паттерны проектирования используются
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерны проектирования в Frontend: кейсы применения
Как Frontend Developer, я регулярно использую различные паттерны проектирования. Рассмотрю конкретные примеры для разных ситуаций.
1. Singleton Pattern
Кейс: Единственный экземпляр класса, используется везде
class ApiClient {
private static instance;
private baseUrl;
private constructor(baseUrl) {
this.baseUrl = baseUrl;
}
static getInstance() {
if (!ApiClient.instance) {
ApiClient.instance = new ApiClient(process.env.API_URL || '');
}
return ApiClient.instance;
}
async get(endpoint) {
const response = await fetch(`${this.baseUrl}${endpoint}`);
return response.json();
}
}
export const api = ApiClient.getInstance();
const data = await api.get('/posts');
Где использую: API Client, Logger, Configuration Manager Плюсы: Одна точка входа Минусы: Сложнее тестировать
2. Factory Pattern
Кейс: Создание объектов разных типов по условиям
class ComponentFactory {
static create(type, props) {
switch (type) {
case 'button':
return <Button {...props} />;
case 'link':
return <Link {...props} />;
case 'icon-button':
return <IconButton {...props} />;
default:
throw new Error(`Unknown component type: ${type}`);
}
}
}
function Menu({ items }) {
return (
<nav>
{items.map(item => (
<div key={item.id}>
{ComponentFactory.create(item.componentType, item.props)}
</div>
))}
</nav>
);
}
Когда использую: Создание компонентов по типам Плюсы: Гибкость, централизованная логика
3. Observer Pattern (Pub/Sub)
Кейс: Реагирование на события, подписка на изменения
class EventBus {
constructor() {
this.listeners = new Map();
}
subscribe(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
return () => {
const callbacks = this.listeners.get(event);
const index = callbacks.indexOf(callback);
if (index > -1) callbacks.splice(index, 1);
};
}
emit(event, data) {
const callbacks = this.listeners.get(event);
callbacks?.forEach(callback => callback(data));
}
}
const eventBus = new EventBus();
function NotificationCenter() {
useEffect(() => {
const unsubscribe = eventBus.subscribe('notification:show', (message) => {
console.log('New notification:', message);
});
return unsubscribe;
}, []);
}
function savePost() {
api.post('/posts', data).then(() => {
eventBus.emit('notification:show', 'Post saved!');
});
}
Где использую: Event handling, WebSocket, уведомления Плюсы: Слабая связь между компонентами
4. Strategy Pattern
Кейс: Разные алгоритмы сортировки, фильтрации
const sortByDate = {
sort: (items) => [...items].sort((a, b) => b.date - a.date)
};
const sortByName = {
sort: (items) => [...items].sort((a, b) => a.name.localeCompare(b.name))
};
const sortByRating = {
sort: (items) => [...items].sort((a, b) => b.rating - a.rating)
};
function Posts() {
const [sortStrategy, setSortStrategy] = useState(sortByDate);
const [posts, setPosts] = useState([]);
const sortedPosts = sortStrategy.sort(posts);
return (
<div>
<select onChange={(e) => {
const strategies = {
date: sortByDate,
name: sortByName,
rating: sortByRating
};
setSortStrategy(strategies[e.target.value]);
}}>
<option value="date">By Date</option>
<option value="name">By Name</option>
<option value="rating">By Rating</option>
</select>
{sortedPosts.map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
);
}
Где использую: Фильтрация, сортировка, валидация
5. Adapter Pattern
Кейс: Адаптация разных источников данных к единому интерфейсу
const wordPressAdapter = (wpPost) => ({
id: wpPost.ID,
title: wpPost.post_title,
author: wpPost.post_author_name,
createdAt: wpPost.post_date
});
const mediumAdapter = (mediumPost) => ({
id: parseInt(mediumPost.id),
title: mediumPost.title,
author: mediumPost.creator.name,
createdAt: mediumPost.createdAt
});
async function getAllPosts() {
const wpPosts = await fetchWordPress();
const mediumPosts = await fetchMedium();
return [
...wpPosts.map(wordPressAdapter),
...mediumPosts.map(mediumAdapter)
];
}
Где использую: Интеграция разных API, миграция
6. Decorator Pattern (HOC)
Кейс: Добавление функциональности без изменения компонента
function withAuthentication(Component) {
return (props) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
checkAuth().then(setIsAuthenticated);
}, []);
if (!isAuthenticated) {
return <Redirect to="/login" />;
}
return <Component {...props} />;
};
}
const ProtectedPage = withAuthentication(Dashboard);
Где использую: Auth protection, logging, analytics
7. Command Pattern
Кейс: Отмена операций (Undo/Redo)
class AddTodoCommand {
constructor(todos, todo) {
this.todos = todos;
this.todo = todo;
}
execute() {
this.todos.push(this.todo);
}
undo() {
const index = this.todos.indexOf(this.todo);
if (index > -1) this.todos.splice(index, 1);
}
}
class CommandHistory {
constructor() {
this.history = [];
this.currentIndex = -1;
}
execute(command) {
command.execute();
this.history = this.history.slice(0, this.currentIndex + 1);
this.history.push(command);
this.currentIndex++;
}
undo() {
if (this.currentIndex >= 0) {
this.history[this.currentIndex].undo();
this.currentIndex--;
}
}
}
Где использую: Undo/Redo функциональность
8. Middleware Pattern
Кейс: Обработка запросов перед/после основной логики
class RequestHandler {
constructor() {
this.middlewares = [];
}
use(middleware) {
this.middlewares.push(middleware);
return this;
}
async handle(ctx) {
let index = -1;
const dispatch = async (i) => {
if (i <= index) return;
index = i;
const middleware = this.middlewares[i];
if (!middleware) return;
await middleware(ctx, () => dispatch(i + 1));
};
await dispatch(0);
}
}
const handler = new RequestHandler();
handler
.use(async (ctx, next) => {
console.log('Before');
await next();
console.log('After');
})
.use(async (ctx) => {
ctx.body = await api.get(ctx.url);
});
Матрица: Паттерны и их применение
| Паттерн | Кейс | Пример |
|---|---|---|
| Singleton | Единственный экземпляр | API Client |
| Factory | Создание объектов | Component generation |
| Observer | Реакция на события | Event Bus |
| Strategy | Разные алгоритмы | Сортировка |
| Adapter | Унификация интерфейсов | Разные API |
| Decorator | Добавление функций | HOC |
| Command | Отмена операций | Undo/Redo |
| Middleware | Обработка flow | Request handling |
Когда я НЕ использую паттерны
- Когда они усложняют, а не упрощают код
- Когда нет реальной проблемы для их решения
- Когда код можно решить проще
Принцип KISS (Keep It Simple, Stupid) важнее формального следования паттернам.
Итого
Паттерны проектирования — это инструменты для:
- Организации кода
- Упрощения тестирования
- Масштабируемости
- Переиспользования
Усло использовать паттерны для реальных проблем, не добавлять их просто так. В Frontend они нужны меньше чем в Backend, но критичны для больших приложений.