ГлавнаяБлогУбираем геттеры: инкапсуляция бизнес-логики
Python

Убираем геттеры: инкапсуляция бизнес-логики

Узнайте, как избавиться от запаха кода с геттерами и перенести бизнес-логику внутрь объектов. Практические примеры на Python и советы по рефакторингу.

Al
Редакция Algolitalgolit.ru
5 мин чтения21 августа 2026 г.

Почему геттеры разрушают инкапсуляцию

Представьте: у вас есть объект Food с геттером use_by_date() для отображения срока годности на этикетке. Всё законно. Но затем вам нужно удалить просроченные продукты — и вы пишете функцию, которая дёргает этот геттер и сравнивает дату с сегодняшней. Потом появляется ещё одна функция с похожей логикой — и вот уже два места в коде решают, что значит «просрочено», а сам объект Food остаётся в стороне. Это классический запах кода, который ведёт к дублированию и хрупкому рефакторингу.

В этой статье разберём, почему переиспользование геттера для новой бизнес-логики — ловушка, и как правильно добавить метод в объект, следуя принципу «Tell, Don't Ask».

Проблема: геттер как костыль

Когда вы используете геттер для вычислений вне объекта, вы нарушаете инкапсуляцию: объект перестаёт контролировать свои данные. Каждый вызывающий код интерпретирует значение по-своему, что ведёт к рассинхронизации правил. Рассмотрим пример на Python.

Неправильный подход: внешние сравнения

class Food:
    def __init__(self, name, use_by_date):
        self.name = name
        self._use_by_date = use_by_date

    def use_by_date(self):
        return self._use_by_date

# Внешняя функция: удаляем просроченные
def remove_expired_food(shelf, today):
    return [food for food in shelf if food.use_by_date() < today]

# Другая функция: почти та же логика
def flag_near_expiry(shelf, today, warning_days):
    result = []
    for food in shelf:
        days_left = (food.use_by_date() - today).days
        if 0 <= days_left <= warning_days:
            result.append(food)
    return result

Здесь remove_expired_food и flag_near_expiry сами решают, что такое «просрочено» или «скоро истечёт». Если завтра правила изменятся (например, просрочка считается по-другому), придётся править обе функции. А объект Food остаётся просто хранилищем данных.

Решение: методы вместо геттеров

Правильный путь — добавить в объект методы, которые отвечают на вопросы о его состоянии. Тогда логика живёт там, где данные, и все вызывающие используют единую реализацию.

Правильный подход: инкапсулируем правила

from datetime import date, timedelta

class Food:
    def __init__(self, name, use_by_date):
        self.name = name
        self._use_by_date = use_by_date

    def use_by_date(self):
        # Геттер остаётся только для отображения
        return self._use_by_date

    def is_expired_on(self, today):
        return self._use_by_date < today

    def days_until_expiry(self, today):
        return (self._use_by_date - today).days

# Теперь внешние функции просто используют методы
def remove_expired_food(shelf, today):
    return [food for food in shelf if food.is_expired_on(today)]

def flag_near_expiry(shelf, today, warning_days):
    return [food for food in shelf
            if 0 <= food.days_until_expiry(today) <= warning_days]

Теперь логика сравнения находится внутри Food. Если правила изменятся, вы правите только класс. Все вызывающие используют один и тот же метод, поэтому рассинхронизация исключена.

Как обнаружить этот запах

Это ручная проверка — линтер не поможет. Ищите геттеры, которые вызываются в нескольких местах, и каждый раз вокруг них строится своя логика сравнения (if, filter, сортировка). Если два вызова читают один и тот же геттер и по-разному интерпретируют результат — объекту не хватает метода.

Исключения

DTO (Data Transfer Objects) иногда используют геттеры для передачи данных, но это не оправдание: даже в DTO можно добавить методы, если появляется бизнес-логика. Запах возникает, когда вы переиспользуете геттер как костыль, вместо того чтобы добавить метод.

Практический вывод

Прямо сейчас: найдите в своём коде геттер, который используется для сравнения или фильтрации вне класса. Замените внешние сравнения методами объекта. Начните с одного класса — и вы увидите, как код станет чище и устойчивее к изменениям.

#геттеры#инкапсуляция#рефакторинг#python
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →