---
title: 'Хватит пихать final в каждый класс'
url: 'https://graker.ru/news/2025/01/20/stop-putting-final-in-every-class'
language: ru
type: post
author: 'Роман Грачев'
published: '2025-01-20T13:20:00+03:00'
updated: '2025-01-20T13:27:15+03:00'
categories:
  - Программирование
---

# Хватит пихать final в каждый класс

![Хватит пихать final в каждый класс](https://graker.ru/sites/default/files/styles/max_1300x1300/public/uploads/2025-01/greta.jpg.webp?itok=kTvjQDnn)

Вот нашёл я библиотеку, неплохая вроде библиотека, позволяет делать, условно говоря, кофе. Описываешь рецепты, вызываешь `$coffeeManager→makeCoffee('espresso')`, и все работает. Но вот незадача — в библиотеке все рецепты кофе хранятся и загружаются из конфиг-файлов (типа `.env`). А мне вот хочется, чтобы пользователи могли добавлять свои рецепты, чтобы их было много, чтобы раф с бананом на молоке единорогов, и это вот всё. А хранить их тогда надо в базе данных.

Казалось бы, можно унаследовать класс `CoffeeManager` и перегрузить метод загрузки рецептов, чтоб вместо `Config::get()` там было обращение к БД. Но вот разработчик хрен пойми зачем объявил класс как `final CoffeeManager { …` Зачем? А хер его знает. Прочитал наверное где-то про страшные длинные цепочки наследований и подумал, что это к его библиотеке как-то относится. А до конца не дочитал, подумал — поставлю final и черт с ним, пусть пользуются как я задумал.

И теперь ни перегрузить не получится, ни класс замокать, если мы его интеграцию протестировать захотим.

А всего-то надо было, если душа требует `final`, сделать интерфейс, который этот класс реализует, и нормальную вставку зависимостей через этот интерфейс:

```
final CoffeeManager implements CoffeeManagerInterface {
    // ...
}
```

и тогда я мог бы просто свою реализацию интерфейса написать и в контейнере сервисов подменить.

А без интерфейса — либо свой форк делать, либо другую библиотеку использовать. Не надо так.
