← Назад к вопросам

Изучал ли абстракции

1.6 Junior🔥 122 комментариев
#Архитектура и паттерны

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Изучал ли абстракции

Да, я активно изучал и применяю абстракции в разработке. Абстракция — это один из ключевых принципов программирования, который позволяет скрывать сложность и создавать более понятный и поддерживаемый код.

Понимание абстракции

Абстракция — это процесс выделения сущностных характеристик объекта и отвлечения от несущественных деталей. В программировании это значит:

  • Скрывать сложную реализацию за простым интерфейсом
  • Предоставлять только необходимую информацию
  • Избегать излишних деталей, которые отвлекают от основной задачи

Примеры абстракций в JavaScript/Frontend

1. Функции как абстракция

// Без абстракции — много повторяющегося кода
const button1 = document.querySelector(".btn-1");
button1.addEventListener("click", () => {
  const request = new XMLHttpRequest();
  request.open("POST", "/api/action1");
  request.onload = () => console.log(request.response);
  request.send();
});

const button2 = document.querySelector(".btn-2");
button2.addEventListener("click", () => {
  const request = new XMLHttpRequest();
  request.open("POST", "/api/action2");
  request.onload = () => console.log(request.response);
  request.send();
});

// С абстракцией — простая функция скрывает сложность
function setupButton(selector, endpoint) {
  const button = document.querySelector(selector);
  button.addEventListener("click", async () => {
    const response = await fetch(endpoint, { method: "POST" });
    console.log(await response.json());
  });
}

setupButton(".btn-1", "/api/action1");
setupButton(".btn-2", "/api/action2");

2. Компоненты как абстракция (React)

// Низкая абстракция — логика размазана
function ProfilePage() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    setLoading(true);
    fetch("/api/user")
      .then(res => res.json())
      .then(data => setUser(data))
      .catch(err => setError(err))
      .finally(() => setLoading(false));
  }, []);
  
  if (loading) return <Spinner />;
  if (error) return <Error message={error.message} />;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
      <button onClick={() => { /* delete logic */ }}>Delete</button>
    </div>
  );
}

// Высокая абстракция — логика в отдельные компоненты и хуки
function useUser(userId) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    setLoading(true);
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data))
      .catch(err => setError(err))
      .finally(() => setLoading(false));
  }, [userId]);
  
  return { user, loading, error };
}

function ProfileCard({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

function ProfilePage({ userId }) {
  const { user, loading, error } = useUser(userId);
  
  if (loading) return <Spinner />;
  if (error) return <Error message={error.message} />;
  
  return <ProfileCard user={user} />;
}

3. API слой как абстракция

// Без абстракции — fetch вызовы везде
function getUserPosts(userId) {
  return fetch(`/api/users/${userId}/posts`)
    .then(res => res.json());
}

function updateUser(userId, data) {
  return fetch(`/api/users/${userId}`, {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data)
  }).then(res => res.json());
}

// С абстракцией — чистый API
class ApiClient {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }
  
  async request(endpoint, options = {}) {
    const url = `${this.baseUrl}${endpoint}`;
    const response = await fetch(url, {
      headers: {
        "Content-Type": "application/json",
        ...options.headers
      },
      ...options
    });
    
    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }
    
    return response.json();
  }
}

class UserAPI extends ApiClient {
  getPosts(userId) {
    return this.request(`/users/${userId}/posts`);
  }
  
  update(userId, data) {
    return this.request(`/users/${userId}`, {
      method: "PUT",
      body: JSON.stringify(data)
    });
  }
}

const api = new UserAPI("https://api.example.com");
api.getPosts(123);
api.update(123, { name: "John" });

4. Утилиты как абстракция

// Без абстракции — сложная логика в компонентах
function DateComponent() {
  const date = new Date("2024-01-15");
  return (
    <div>
      {date.getDate()} {months[date.getMonth()]} {date.getFullYear()}
    </div>
  );
}

// С абстракцией — логика в утилите
function formatDate(date, locale = "en-US") {
  return new Intl.DateTimeFormat(locale, {
    year: "numeric",
    month: "long",
    day: "numeric"
  }).format(new Date(date));
}

function DateComponent() {
  return <div>{formatDate("2024-01-15")}</div>;
}

Уровни абстракции

Низкая абстракция

Много деталей видно, но легко контролировать:

// Много деталей
const response = await fetch("/api/users", {
  method: "GET",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${token}`
  }
});
const data = await response.json();

Высокая абстракция

Детали скрыты, но может быть сложнее модифицировать:

// Детали скрыты
const data = await apiClient.getUsers();

Правильный уровень абстракции

Не нужно чрезмерно абстрагировать:

// ❌ Оверинжиниринг
function createLogger(namespace) {
  return {
    log: (message, level = "info") => {
      console.log(`[${namespace}] [${level}] ${message}`);
    },
    error: (message) => this.log(message, "error"),
    warn: (message) => this.log(message, "warn"),
    info: (message) => this.log(message, "info")
  };
}

const logger = createLogger("MyApp");
logger.log("Hello", "info");

// ✅ Просто
console.log("[MyApp] [info] Hello");

Нужна абстракция, когда:

// ✅ Повторяется код
function request(endpoint, options) {
  return fetch(`${API_BASE}${endpoint}`, {
    headers: { "Authorization": `Bearer ${getToken()}` },
    ...options
  }).then(res => res.json());
}

// ✅ Сложная логика, которая нужна в разных местах
function useFormValidation(initialValues, onSubmit) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  // ...
  return { values, errors, handleSubmit };
}

SOLID принципы и абстракция

Single Responsibility — каждый модуль отвечает за одно:

// ✅ UserService отвечает за логику пользователя
class UserService {
  getUser(id) { /* ... */ }
  updateUser(id, data) { /* ... */ }
}

// ✅ ApiClient отвечает за HTTP запросы
class ApiClient {
  request(url, options) { /* ... */ }
}

Dependency Inversion — зависимости от абстракций, не от конкретики:

// ❌ Зависимость от конкретики
class UserService {
  constructor() {
    this.api = new RestAPI(); // Привязана к REST
  }
}

// ✅ Зависимость от абстракции
class UserService {
  constructor(api) { // Любой API подойдёт
    this.api = api;
  }
}

const restService = new UserService(new RestAPI());
const graphqlService = new UserService(new GraphQLAPI());

Резюме

Абстракция — это навык, который я постоянно развиваю. Она помогает:

  • Упростить код — скрыть сложность за простым интерфейсом
  • Снизить связанность — компоненты меньше зависят друг от друга
  • Улучшить тестируемость — легче тестировать абстрактные интерфейсы
  • Облегчить поддержку — изменения в реализации не влияют на использование

Но нужно избегать чрезмерной абстракции — KISS (Keep It Simple, Stupid) тоже важен.