Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Cohesion?
Cohesion (Связность) - это принцип проектирования кода, который показывает, насколько функции, методы и переменные в модуле, классе или компоненте связаны между собой и сосредоточены на одной цели.
Просто говоря: высокая связность (High Cohesion) означает, что все элементы в блоке кода работают вместе для достижения одной цели. Низкая связность (Low Cohesion) означает, что элементы не связаны и делают разные вещи.
Определение высокой связности (High Cohesion)
Модуль с высокой связностью:
- Все функции и переменные решают одну задачу
- Элементы используют друг друга
- Легко понять назначение модуля
- Легко переиспользовать
- Легко тестировать
Определение низкой связности (Low Cohesion)
Модуль с низкой связностью:
- Содержит несвязанные функции
- Элементы не используют друг друга
- Непонятно, что делает модуль
- Сложно переиспользовать
- Сложно тестировать
- Часто нужно изменять при разных причинах
Примеры: React компоненты
Пример 1: НИЗКАЯ связность (плохо)
// UserProfileBadly.tsx - делает слишком много разного
function UserProfileBadly() {
// Управление профилем
const [name, setName] = useState('');
const [email, setEmail] = useState('');
// Управление постами
const [posts, setPosts] = useState([]);
// Управление комментариями
const [comments, setComments] = useState([]);
// Управление авторизацией
const [token, setToken] = useState('');
// Управление уведомлениями
const [notifications, setNotifications] = useState([]);
// Функции для разных целей
const updateProfile = () => { /* ... */ };
const deletePost = () => { /* ... */ };
const approveComment = () => { /* ... */ };
const logout = () => { /* ... */ };
const sendNotification = () => { /* ... */ };
return (
<div>
{/* управление профилем */}
{/* управление постами */}
{/* управление комментариями */}
{/* управление авторизацией */}
{/* управление уведомлениями */}
</div>
);
}
// ПРОБЛЕМЫ:
// - Компонент делает 5 разных вещей
// - Сложно тестировать
// - Сложно переиспользовать (нужно весь этот код)
// - Часто нужно изменять (по разным причинам)
Пример 2: ВЫСОКАЯ связность (хорошо)
// UserProfile.tsx - только управление профилем
interface UserProfileProps {
userId: string;
onUpdate: (user: User) => void;
}
function UserProfile({ userId, onUpdate }: UserProfileProps) {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
fetchUser(userId);
}, [userId]);
const fetchUser = async (id: string) => {
setIsLoading(true);
const data = await apiClient.getUser(id);
setUser(data);
setIsLoading(false);
};
const handleSave = async (updatedUser: User) => {
await apiClient.updateUser(updatedUser);
setUser(updatedUser);
onUpdate(updatedUser);
};
if (isLoading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;
return (
<form onSubmit={(e) => {
e.preventDefault();
handleSave(user);
}}>
<input
value={user.name}
onChange={(e) => setUser({...user, name: e.target.value})}
/>
<input
value={user.email}
onChange={(e) => setUser({...user, email: e.target.value})}
/>
<button type="submit">Save</button>
</form>
);
}
// ПРЕИМУЩЕСТВА:
// - Компонент делает ОДНО: управляет профилем
// - Всё что здесь - нужно для профиля
// - Легко тестировать
// - Легко переиспользовать
// - Легко поддерживать
Другие примеры низкой и высокой связности
Низкая связность: функция с разными целями
// processUserData - делает слишком много
function processUserData(user: User) {
// Валидирует юзера
if (!user.email.includes('@')) {
throw new Error('Invalid email');
}
// Логирует в файл
fs.writeFileSync('/logs/user.log', user.name);
// Отправляет на сервер
fetch('/api/users', { body: JSON.stringify(user) });
// Обновляет UI
document.getElementById('user-info').textContent = user.name;
// Отправляет аналитику
analytics.track('user_processed');
return user;
}
// ПРОБЛЕМЫ:
// - Функция делает валидацию, логирование, запросы, обновление UI, аналитику
// - Сложно тестировать
// - Сложно переиспользовать
Высокая связность: функции с одной целью
// Каждая функция делает ОДНО
function validateUser(user: User): boolean {
return user.email.includes('@');
}
function fetchUserToServer(user: User): Promise<Response> {
return fetch('/api/users', { body: JSON.stringify(user) });
}
function updateUserInUI(user: User): void {
document.getElementById('user-info').textContent = user.name;
}
function trackUserProcessed(): void {
analytics.track('user_processed');
}
class UserLogger {
log(user: User): void {
fs.writeFileSync('/logs/user.log', user.name);
}
}
// ПРЕИМУЩЕСТВА:
// - Каждая функция делает одно и делает его хорошо
// - Легко тестировать
// - Легко переиспользовать
// - Легко заменить реализацию (например, логирование в БД вместо файла)
Cohesion и Coupling (взаимное переплетение)
Cohesion и Coupling часто упоминаются вместе:
- High Cohesion: элементы в модуле тесно связаны
- Low Coupling: модули мало зависят друг от друга
// ПЛОХО: High Coupling + Low Cohesion
class UserManager {
database: Database;
logger: Logger;
emailService: EmailService;
paymentProcessor: PaymentProcessor;
// Всё зависит от всего
async createUser(data: any) {
// нужна БД
// нужен логгер
// нужен email сервис
// нужен платёжный процессор
}
}
// ХОРОШО: High Cohesion + Low Coupling
class User {
id: string;
name: string;
email: string;
}
class UserRepository {
// Только работа с БД для юзеров
async create(user: User) { }
async findById(id: string) { }
async update(user: User) { }
}
class UserService {
constructor(private repository: UserRepository) {}
// Только бизнес-логика
async registerUser(data: UserData) {
// валидирует
// создаёт юзера
// возвращает результат
}
}
// Других сервисов не знает
Практические преимущества высокой связности
1. Легче понять код
// Высокая связность
function calculateDiscount(subtotal: number, code: string): number {
// Ясно: функция считает скидку
const discounts: { [key: string]: number } = { 'SAVE10': 0.1, 'SAVE20': 0.2 };
return subtotal * (discounts[code] || 0);
}
// Низкая связность
function handleCheckout(subtotal: number, code: string) {
// Считает скидку
const discount = subtotal * (code === 'SAVE10' ? 0.1 : 0);
// Отправляет на сервер
fetch('/api/checkout', { body: JSON.stringify({ subtotal, discount, code }) });
// Обновляет UI
document.getElementById('total').textContent = (subtotal - discount).toString();
// Логирует
console.log('Checkout:', { subtotal, discount, code });
// Отправляет аналитику
analytics.track('checkout_processed');
}
2. Легче тестировать
// Высокая связность - легко тестировать
test('calculateDiscount returns 10% for SAVE10', () => {
expect(calculateDiscount(100, 'SAVE10')).toBe(10);
});
// Низкая связность - сложно тестировать (нужно мокировать всё)
test('handleCheckout works', () => {
jest.mock('fetch');
jest.mock('document');
jest.mock('analytics');
// ... 20 линий мокирования ...
handleCheckout(100, 'SAVE10');
// ... проверять разные вещи ...
});
3. Легче переиспользовать
// Высокая связность - переиспользуемо
const discount = calculateDiscount(1000, 'SAVE20'); // Используй где угодно
// Низкая связность - нельзя переиспользовать
handleCheckout(1000, 'SAVE20'); // Работает только для чекаута, не для предпросмотра
Как достичь высокой связности
1. Single Responsibility Principle (SRP)
- Каждый модуль должен иметь одну причину для изменения
2. Разделяй на модули по функциям
- User Profile -> управление профилем
- User Posts -> управление постами
- User Comments -> управление комментариями
3. Используй dependency injection
- Зависимости передавай через параметры, не создавай их внутри
4. Избегай god objects
- Не создавай объекты/компоненты, которые делают слишком много
5. Группируй связанные данные
- Переменные и функции, которые работают вместе, должны быть рядом
Вывод
Cohesion - это важный принцип чистого кода. Высокая связность означает:
- Все элементы в модуле работают на одну цель
- Легче понять
- Легче тестировать
- Легче переиспользовать
- Легче поддерживать
Стремись к высокой связности (High Cohesion) и низкому связыванию (Low Coupling) - это основа качественной архитектуры.