Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие знаешь паттерны?
Паттерны (patterns) — это проверенные решения для типичных проблем в программировании. Я знаю множество паттернов разных категорий. Расскажу о самых полезных для фронтенда.
Архитектурные паттерны
1. MVC (Model-View-Controller)
Разделение на три слоя:
- Model — бизнес-логика и данные
- View — интерфейс
- Controller — связь между ними
// Model — данные и логика
class UserModel {
constructor() {
this.users = []
}
addUser(name) {
this.users.push({ id: Date.now(), name })
}
}
// View — интерфейс
class UserView {
render(users) {
return `
<ul>
${users.map(u => `<li>${u.name}</li>`).join('')}
</ul>
`
}
}
// Controller — связь
class UserController {
constructor(model, view) {
this.model = model
this.view = view
}
addUser(name) {
this.model.addUser(name)
this.render()
}
render() {
const html = this.view.render(this.model.users)
document.body.innerHTML = html
}
}
2. MVVM (Model-View-ViewModel)
Используется в Vue и Angular. Двусторонняя привязка данных.
// Vue использует MVVM
const vm = new Vue({
el: '#app',
data() { // ViewModel
return { message: 'Hello' }
},
template: '<h1>{{ message }}</h1>' // View
})
// Изменение View -> ViewModel -> Model
// Изменение Model -> ViewModel -> View (автоматически)
3. Redux / Flux
Паттерн управления состоянием (state management).
// Action — событие
const ADD_USER = 'ADD_USER'
const addUser = (name) => ({ type: ADD_USER, payload: name })
// Reducer — обновляет состояние
const userReducer = (state = [], action) => {
if (action.type === ADD_USER) {
return [...state, { id: Date.now(), name: action.payload }]
}
return state
}
// Store — хранилище
const store = createStore(userReducer)
// Dispatch — отправляем action
store.dispatch(addUser('John'))
Поведенческие паттерны
1. Observer (Наблюдатель)
Объект уведомляет подписчиков об изменениях.
class EventEmitter {
constructor() {
this.events = {}
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(callback)
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(cb => cb(data))
}
}
}
const emitter = new EventEmitter()
emitter.on('user:login', (user) => {
console.log('User logged in:', user)
})
emitter.emit('user:login', { name: 'John' })
2. Strategy (Стратегия)
Выбор алгоритма во время выполнения.
const strategies = {
linear: (value) => value,
quad: (value) => value * value,
sqrt: (value) => Math.sqrt(value)
}
class Calculator {
constructor(strategy) {
this.strategy = strategy
}
calculate(value) {
return this.strategy(value)
}
}
const calc = new Calculator(strategies.quad)
console.log(calc.calculate(5)) // 25
3. Chain of Responsibility (Цепочка ответственности)
Передача запроса по цепочке обработчиков.
class Logger {
constructor(nextHandler) {
this.next = nextHandler
}
handle(request) {
if (request.type === 'log') {
console.log('Logging:', request.data)
}
if (this.next) {
this.next.handle(request)
}
}
}
class EmailHandler {
constructor(nextHandler) {
this.next = nextHandler
}
handle(request) {
if (request.type === 'email') {
console.log('Sending email:', request.data)
}
if (this.next) {
this.next.handle(request)
}
}
}
const logger = new Logger(new EmailHandler())
logger.handle({ type: 'log', data: 'Something happened' })
logger.handle({ type: 'email', data: 'Alert' })
Структурные паттерны
1. Decorator (Декоратор)
Добавляет функциональность к объекту динамически.
function withLogging(fn) {
return function(...args) {
console.log('Calling:', fn.name, args)
const result = fn(...args)
console.log('Result:', result)
return result
}
}
const add = (a, b) => a + b
const addWithLogging = withLogging(add)
addWithLogging(2, 3) // Логирует и вызывает
TypeScript декораторы:
function Log(target, propertyKey, descriptor) {
const original = descriptor.value
descriptor.value = function(...args) {
console.log('Calling:', propertyKey)
return original.apply(this, args)
}
return descriptor
}
class Calculator {
@Log
add(a: number, b: number) {
return a + b
}
}
2. Adapter (Адаптер)
Меняет интерфейс несовместимого объекта.
// Старая библиотека
class OldAPI {
fetchData() {
return { userData: { name: 'John' } }
}
}
// Адаптер
class APIAdapter {
constructor(oldAPI) {
this.api = oldAPI
}
getUser() {
const data = this.api.fetchData()
return data.userData // Преобразуем интерфейс
}
}
const adapter = new APIAdapter(new OldAPI())
console.log(adapter.getUser()) // { name: 'John' }
3. Facade (Фасад)
Упрощенный интерфейс к сложной подсистеме.
class ModuleA {
init() { console.log('A initialized') }
}
class ModuleB {
init() { console.log('B initialized') }
}
class ModuleC {
init() { console.log('C initialized') }
}
// Фасад
class AppFacade {
constructor() {
this.modules = [new ModuleA(), new ModuleB(), new ModuleC()]
}
initializeApp() {
this.modules.forEach(m => m.init()) // Инициализируем все сразу
}
}
const app = new AppFacade()
app.initializeApp()
React паттерны
1. Container / Presentational Component
// Presentational — чистый компонент (дуп props)
function UserList({ users, onDelete }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
<button onClick={() => onDelete(user.id)}>Delete</button>
</li>
))}
</ul>
)
}
// Container — логика и state
function UserListContainer() {
const [users, setUsers] = useState([...]) // Логика
const handleDelete = (id) => {
setUsers(users.filter(u => u.id !== id))
}
return <UserList users={users} onDelete={handleDelete} />
}
2. Render Props
class MouseTracker extends React.Component {
state = { x: 0, y: 0 }
handleMouseMove = (event) => {
this.setState({ x: event.clientX, y: event.clientY })
}
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.children(this.state)}
</div>
)
}
}
// Использование
<MouseTracker>
{({ x, y }) => <div>Mouse at {x}, {y}</div>}
</MouseTracker>
3. Compound Components
const Tabs = ({ children }) => {
const [activeTab, setActiveTab] = useState(0)
return (
<div>
{React.Children.map(children, (child, idx) => (
React.cloneElement(child, {
active: idx === activeTab,
onClick: () => setActiveTab(idx)
})
))}
</div>
)
}
Tabs.Tab = ({ children, active, onClick }) => (
<button className={active && 'active'} onClick={onClick}>
{children}
</button>
)
// Использование
<Tabs>
<Tabs.Tab>Tab 1</Tabs.Tab>
<Tabs.Tab>Tab 2</Tabs.Tab>
</Tabs>
JavaScript паттерны
1. Module Pattern
const UserModule = (() => {
const users = [] // Приватная переменная
return {
addUser(name) {
users.push(name)
},
getUsers() {
return [...users] // Публичный API
}
}
})()
UserModule.addUser('John')
console.log(UserModule.getUsers()) // ['John']
// users не доступна снаружи — инкапсуляция!
2. Singleton
const Logger = (() => {
let instance
return {
getInstance() {
if (!instance) {
instance = { logs: [] }
}
return instance
}
}
})()
const logger1 = Logger.getInstance()
const logger2 = Logger.getInstance()
console.log(logger1 === logger2) // true — один экземпляр
3. Factory
function createUser(name, role) {
return {
name,
role,
getPermissions() {
if (role === 'admin') return ['read', 'write', 'delete']
if (role === 'user') return ['read']
return []
}
}
}
const admin = createUser('John', 'admin')
const user = createUser('Jane', 'user')
CSS паттерны
1. BEM (Block Element Modifier)
<div class="button">
<span class="button__text">Click me</span>
</div>
<style>
.button { padding: 10px; background: blue; }
.button__text { color: white; }
.button--large { padding: 20px; }
.button--disabled { opacity: 0.5; }
</style>
2. Utility-First (Tailwind CSS)
<div class="flex items-center justify-center bg-blue-500 p-4 rounded-lg">
<span class="text-white font-bold">Button</span>
</div>
Что использую в практике
✅ Часто:
- Module Pattern (инкапсуляция)
- Observer (события)
- Strategy (выбор алгоритма)
- Container / Presentational (React)
- Factory (создание объектов)
✅ Периодически:
- Decorator (логирование, валидация)
- Adapter (интеграция)
- Facade (упрощение API)
- Singleton (одиночный экземпляр)
❌ Редко:
- Chain of Responsibility (слишком сложно)
- Visitor (очень специфичный)
Выбор паттерна зависит от конкретной проблемы. Не нужно использовать все паттерны везде — это усложнит код. Используй паттерны для решения реальных проблем.