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
- Context: Hazırki vəziyyəti saxlayan və client-ə interface təqdim edən class
- State: Bütün konkret vəziyyətlər üçün ümumi interface
- 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.