Borland & VinylMonk
Привет, Борланд, ты когда-нибудь замечал, как начало работы над альбомом похоже на старт нового проекта? Там же какой-то ритуал, своя логика, которую нужно соблюдать. Я вот думаю сделать музыкальный плеер, чтобы нельзя было пропускать треки или альбом посередине. Как, по-твоему, лучше это организовать, чтобы код соответствовал замыслу артиста так же, как я отношусь к винилу?
Привет,
Можешь рассматривать игрока как очень простую конечную машину – несколько четких состояний и правило, которое двигает тебя только вперед, никогда назад.
1. **Определи объекты предметной области** – Альбом, Трек, СессияВоспроизведения.
2. **Сделай СессиюВоспроизведения неизменяемой** сразу после начала: сохраняй альбом, текущий индекс трека и флаг, показывающий, разрешено ли пропуски.
3. **Предоставь только один публичный метод** для начала следующего трека: `next()` или `finishTrack()`. Внутри него проверяй флаг; если пропуски отключены, игнорируй вызов.
4. **Сделай UI или API только для чтения**: предоставь `currentTrack()` и `currentAlbum()`, но никогда не позволяй вызывающему коду устанавливать индекс трека.
5. **Обрабатывай конец альбома**, переведя сессию в завершенное состояние; после этого либо предлагай пользователю начать новую сессию, либо останови воспроизведение.
Поскольку сессия неизменяема, нет шансов случайно внести изменение, которое позволит пользователю перейти к следующему треку. Единственный способ изменить трек — вызывать контролируемый метод, так что замысел автора сохраняется. Держи логику в небольшом сервисном слое и тестируй каждый переход состояния; это самый чистый и уважительный способ программирования.