Əsas məzmuna keçin

State Design Pattern

Obyektin daxili vəziyyəti dəyişdikdə onun davranışını da dəyişdirməyə imkan verir. Bu pattern, obyektin class-ının dəyişdiyi təəssüratını yaradır.

State pattern, real həyatda bir çox nümunələrə bənzəyir. Məsələn, mobil telefonunuz səssiz rejimdə olanda zəng səslərini vermir, amma normal rejimdə verir - bu, telefonun vəziyyətinə görə davranışının dəyişməsidir.

State Pattern-nin Əsas Xüsusiyyətləri

  • State-based Behavior: Vəziyyətə əsaslanan davranış
  • Dynamic Behavior Change: Dinamik davranış dəyişikliyi
  • State Encapsulation: Hər vəziyyət öz davranışını özündə saxlayır
  • Context Independence: Kontekst vəziyyət dəyişikliklərindən xəbərsizdir

State Pattern-nin Strukturu

  1. Context: Hazırki vəziyyəti saxlayan və client-ə interface təqdim edən class
  2. State: Bütün konkret vəziyyətlər üçün ümumi interface
  3. ConcreteState: Müəyyən vəziyyətdə obyektin davranışını təyin edən class-lar

Java-da State Pattern İmplementasiyası

Media Player Nümunəsi

Koda bax
// State interface
interface PlayerState {
void play(MediaPlayer player);
void pause(MediaPlayer player);
void stop(MediaPlayer player);
String getStateName();
}

// Concrete States
class StoppedState implements PlayerState {
@Override
public void play(MediaPlayer player) {
System.out.println("Starting playback...");
player.setState(new PlayingState());
}

@Override
public void pause(MediaPlayer player) {
System.out.println("Cannot pause. Player is stopped.");
}

@Override
public void stop(MediaPlayer player) {
System.out.println("Player is already stopped.");
}

@Override
public String getStateName() {
return "Stopped";
}
}

class PlayingState implements PlayerState {
@Override
public void play(MediaPlayer player) {
System.out.println("Player is already playing.");
}

@Override
public void pause(MediaPlayer player) {
System.out.println("Pausing playback...");
player.setState(new PausedState());
}

@Override
public void stop(MediaPlayer player) {
System.out.println("Stopping playback...");
player.setState(new StoppedState());
}

@Override
public String getStateName() {
return "Playing";
}
}

class PausedState implements PlayerState {
@Override
public void play(MediaPlayer player) {
System.out.println("Resuming playback...");
player.setState(new PlayingState());
}

@Override
public void pause(MediaPlayer player) {
System.out.println("Player is already paused.");
}

@Override
public void stop(MediaPlayer player) {
System.out.println("Stopping playback...");
player.setState(new StoppedState());
}

@Override
public String getStateName() {
return "Paused";
}
}

// Context class
class MediaPlayer {
private PlayerState currentState;

public MediaPlayer() {
this.currentState = new StoppedState();
}

public void setState(PlayerState state) {
this.currentState = state;
System.out.println("State changed to: " + state.getStateName());
}

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

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

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

public String getCurrentState() {
return currentState.getStateName();
}
}

// Client code
public class StatePatternDemo {
public static void main(String[] args) {
MediaPlayer player = new MediaPlayer();

System.out.println("Initial state: " + player.getCurrentState());
System.out.println();

// Try to play
player.play();
System.out.println();

// Try to play again
player.play();
System.out.println();

// Pause the player
player.pause();
System.out.println();

// Try to pause again
player.pause();
System.out.println();

// Resume playing
player.play();
System.out.println();

// Stop the player
player.stop();
System.out.println();

// Try to stop again
player.stop();
}
}

Çıxış:

Initial state: Stopped

Starting playback...
State changed to: Playing

Player is already playing.

Pausing playback...
State changed to: Paused

Player is already paused.

Resuming playback...
State changed to: Playing

Stopping playback...
State changed to: Stopped

Player is already stopped.

Vending Machine Nümunəsi

Koda bax
// Vending Machine State interface
interface VendingState {
void insertCoin(VendingMachine machine);
void selectProduct(VendingMachine machine);
void dispenseProduct(VendingMachine machine);
void returnCoin(VendingMachine machine);
String getStateName();
}

// Concrete States for Vending Machine
class NoCoinState implements VendingState {
@Override
public void insertCoin(VendingMachine machine) {
System.out.println("Coin inserted.");
machine.setState(new HasCoinState());
}

@Override
public void selectProduct(VendingMachine machine) {
System.out.println("Please insert coin first.");
}

@Override
public void dispenseProduct(VendingMachine machine) {
System.out.println("Please insert coin and select product first.");
}

@Override
public void returnCoin(VendingMachine machine) {
System.out.println("No coin to return.");
}

@Override
public String getStateName() {
return "No Coin";
}
}

class HasCoinState implements VendingState {
@Override
public void insertCoin(VendingMachine machine) {
System.out.println("Coin already inserted.");
}

@Override
public void selectProduct(VendingMachine machine) {
System.out.println("Product selected. Dispensing...");
machine.setState(new DispensingState());
}

@Override
public void dispenseProduct(VendingMachine machine) {
System.out.println("Please select a product first.");
}

@Override
public void returnCoin(VendingMachine machine) {
System.out.println("Coin returned.");
machine.setState(new NoCoinState());
}

@Override
public String getStateName() {
return "Has Coin";
}
}

class DispensingState implements VendingState {
@Override
public void insertCoin(VendingMachine machine) {
System.out.println("Please wait, dispensing in progress.");
}

@Override
public void selectProduct(VendingMachine machine) {
System.out.println("Already dispensing product.");
}

@Override
public void dispenseProduct(VendingMachine machine) {
System.out.println("Product dispensed. Thank you!");
machine.setState(new NoCoinState());
}

@Override
public void returnCoin(VendingMachine machine) {
System.out.println("Cannot return coin while dispensing.");
}

@Override
public String getStateName() {
return "Dispensing";
}
}

// Context class
class VendingMachine {
private VendingState currentState;

public VendingMachine() {
this.currentState = new NoCoinState();
}

public void setState(VendingState state) {
this.currentState = state;
System.out.println("Machine state: " + state.getStateName());
}

public void insertCoin() {
currentState.insertCoin(this);
}

public void selectProduct() {
currentState.selectProduct(this);
}

public void dispenseProduct() {
currentState.dispenseProduct(this);
}

public void returnCoin() {
currentState.returnCoin(this);
}

public String getCurrentState() {
return currentState.getStateName();
}
}

State Pattern-nin Üstünlükləri

  • Clean Code: Vəziyyət-əsaslı şərti məntiqin eliminasiyası
  • Single Responsibility: Hər vəziyyət öz davranışından məsuldir
  • Easy Extension: Yeni vəziyyətlər asanlıqla əlavə edilə bilər
  • State Isolation: Vəziyyətlər bir-birindən ayrıdır

State Pattern-nin Çatışmazlıqları

  • Code Complexity: Çox sayda class yaradır
  • Memory Usage: Hər vəziyyət üçün obyekt yaradılmalıdır
  • Overkill: Sadə state machine-lər üçün həddən artıq ola bilər

İstifadə Halları

  • UI Components: Button, checkbox və digər UI elementlərinin davranışı
  • Game Development: Oyun personajının müxtəlif vəziyyətləri
  • State Machines: Mürəkkəb vəziyyət maşınları
  • Workflow Systems: İş proseslərinin müxtəlif mərhələləri

State vs Strategy Pattern

  • State: Obyektin vəziyyəti dəyişdikcə davranışını dəyişdirir
  • Strategy: Client tərəfindən seçilən algoritmanı dəyişdirir

State Pattern, mürəkkəb vəziyyət əsaslı davranışları təşkil etmək üçün çox faydalı bir pattern-dir və xüsusilə state machine-lər tələb olunan aplikasiyalarda geniş istifadə olunur.