State (Состояние)
Шаблон проектирования "Состояние" (State) позволяет объекту изменять свое поведение в зависимости от его внутреннего состояния. Этот паттерн позволяет избежать большого количества условных операторов и делает код более чистым и понятным. Он особенно полезен, когда объект может находиться в одном из нескольких состояний, и поведение объекта зависит от текущего состояния.
Основные компоненты паттерна "Состояние":
- Контекст (Context): класс, который содержит текущее состояние и делегирует поведение этому состоянию.
- Состояние (State): интерфейс, который определяет методы, которые должны быть реализованы конкретными состояниями.
- Конкретные состояния (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(); // Попытка остановить уже остановленный плеер
}
}
Объяснение кода:
- Интерфейс
State
определяет методыplay
,pause
иstop
, которые будут реализованы конкретными состояниями. - Класс
MusicPlayer
является контекстом, который содержит текущее состояние и делегирует поведение этому состоянию. Он может изменять свое состояние с помощью методаsetState
. - Конкретные состояния (
PlayingState
,PausedState
,StoppedState
) реализуют интерфейсState
и определяют поведение для каждого состояния. - В методе
main
мы создаем экземплярMusicPlayer
и выполняем различные действия, которые изменяют состояние плеера.
Таким образом, паттерн "Состояние" позволяет легко добавлять новые состояния и изменять поведение объекта в зависимости от его состояния, что делает код более гибким и поддерживаемым.