Skip to content

State (Состояние)

Шаблон проектирования "Состояние" (State) позволяет объекту изменять свое поведение в зависимости от его внутреннего состояния. Этот паттерн позволяет избежать большого количества условных операторов и делает код более чистым и понятным. Он особенно полезен, когда объект может находиться в одном из нескольких состояний, и поведение объекта зависит от текущего состояния.

Основные компоненты паттерна "Состояние":

  1. Контекст (Context): класс, который содержит текущее состояние и делегирует поведение этому состоянию.
  2. Состояние (State): интерфейс, который определяет методы, которые должны быть реализованы конкретными состояниями.
  3. Конкретные состояния (Concrete States): классы, реализующие интерфейс состояния и определяющие поведение для конкретного состояния.

Пример на Java

Рассмотрим пример, в котором у нас есть музыкальный плеер, который может находиться в разных состояниях: "Воспроизведение", "Пауза" и "Остановлено".

// Интерфейс состояния
interface State {
    void play(MusicPlayer player);
    void pause(MusicPlayer player);
    void stop(MusicPlayer player);
}

// Контекст
class MusicPlayer {
    private State state;

    public MusicPlayer() {
        state = new StoppedState(); // Начальное состояние
    }

    public void setState(State state) {
        this.state = state;
    }

    public void play() {
        state.play(this);
    }

    public void pause() {
        state.pause(this);
    }

    public void stop() {
        state.stop(this);
    }
}

// Конкретное состояние: Воспроизведение
class PlayingState implements State {
    @Override
    public void play(MusicPlayer player) {
        System.out.println("Музыка уже воспроизводится.");
    }

    @Override
    public void pause(MusicPlayer player) {
        System.out.println("Музыка приостановлена.");
        player.setState(new PausedState());
    }

    @Override
    public void stop(MusicPlayer player) {
        System.out.println("Музыка остановлена.");
        player.setState(new StoppedState());
    }
}

// Конкретное состояние: Пауза
class PausedState implements State {
    @Override
    public void play(MusicPlayer player) {
        System.out.println("Музыка возобновлена.");
        player.setState(new PlayingState());
    }

    @Override
    public void pause(MusicPlayer player) {
        System.out.println("Музыка уже на паузе.");
    }

    @Override
    public void stop(MusicPlayer player) {
        System.out.println("Музыка остановлена.");
        player.setState(new StoppedState());
    }
}

// Конкретное состояние: Остановлено
class StoppedState implements State {
    @Override
    public void play(MusicPlayer player) {
        System.out.println("Музыка начала воспроизводиться.");
        player.setState(new PlayingState());
    }

    @Override
    public void pause(MusicPlayer player) {
        System.out.println("Музыка остановлена, не может быть приостановлена.");
    }

    @Override
    public void stop(MusicPlayer player) {
        System.out.println("Музыка уже остановлена.");
    }
}

// Пример использования
public class StatePatternExample {
    public static void main(String[] args) {
        MusicPlayer player = new MusicPlayer();

        player.play(); // Начало воспроизведения
        player.pause(); // Пауза
        player.play(); // Возобновление воспроизведения
        player.stop(); // Остановка
        player.stop(); // Попытка остановить уже остановленный плеер
    }
}

Объяснение кода:

  1. Интерфейс State определяет методы play, pause и stop, которые будут реализованы конкретными состояниями.
  2. Класс MusicPlayer является контекстом, который содержит текущее состояние и делегирует поведение этому состоянию. Он может изменять свое состояние с помощью метода setState.
  3. Конкретные состояния (PlayingState, PausedState, StoppedState) реализуют интерфейс State и определяют поведение для каждого состояния.
  4. В методе main мы создаем экземпляр MusicPlayer и выполняем различные действия, которые изменяют состояние плеера.

Таким образом, паттерн "Состояние" позволяет легко добавлять новые состояния и изменять поведение объекта в зависимости от его состояния, что делает код более гибким и поддерживаемым.