Tuesday, August 12, 2014

Programming Design Pattern - State Pattern Applied - Best Practise

Hi there!

Today i'm gonna show the state design pattern in action. The state design pattern is a very useful programming design pattern while dealing with state maschines.

I'm assuming here you already know the concepts and i'll be focusing on practise. The example i will provide is a nice way to show it how it could looks like. You can always come back here, take it, adapt it and use it in your applictions as you may need. So be sure you bookmark it or join the group here on the right side of this post subscribing it.

First of all, let's take a look at the UML diagram of it. After that we will take the analogy for our example.

The simpliest UML State Pattern

Pay close attention, because once you understand that, everything will become clear and simple to understand. That's the reason I'm putting always the UML first. That way you'll get an eye for it with the time.

The State Interface

Here we can see how simple it is. Let's implement some real states from our ticket automat to get more familiar with. The MoneyState will be set, when the user has paid for the ticket and will calculate the exchange if some.

public interface State {
    void handle();
}
public class MoneyState implements State {
    private TicketAutomat context;
    public MoneyState(TicketAutomat context) {
        this.context = context;
    }
    @Override
    public void handle() {
        System.out.println("PAYMENT RECEIVED! CALCULATING EXCHANGE ...");
        context.setCurrentState(context.getSoldState());
        context.getCurrentState().handle();
    }
}

The TicketSoldState

This state says to the user that the ticket has been sold out successfully and sets the NoMoneyState asking the user to pay for a ticket if we still have tickets available, otherwise will set the SoldOutStore which shows to the user, that all tickets are sold out.

public class TicketSoldState implements State {
    private TicketAutomat context;
    public TicketSoldState(TicketAutomat context) {
        this.context = context;
    }
    @Override
    public void handle() {
        context.updateTicketsAvailable();
        context.setPaid(false);
        System.out.println("YOUR TICKET WAS PRINTED OUT!");
        if(context.isTicketAvailable()){
            context.setCurrentState(context.getNoMoneyState());
        }else{
            context.setCurrentState(context.getSoldOutState());
            context.getCurrentState().handle();
        }
    }
}

TicketsSoldOutState

This state says, "Sorry no more tickets available" or sets the NoMoneyState if we have tickets available.

public class TicketsSoldOutState implements State {
    private TicketAutomat context;
    public TicketsSoldOutState(TicketAutomat context) {
        this.context = context;
    }
    @Override
    public void handle() {
        if(context.isTicketAvailable()){
            context.getNoMoneyState().handle();
        }else{
            System.out.println("SORRY! THERE IS NO MORE TICKETS AVAILABLE!");
            context.setCurrentState(context.getSoldOutState()); 
        }
    }
}

NoMoneyState

This state is the first message the user will see, if we have tickets to sell. It sets the MoneyState to show to the user, that it has received the money and it is processing it.

public class NoMoneyState implements State {
    private TicketAutomat context;
    public NoMoneyState(TicketAutomat context) {
        this.context = context;
    }
    @Override
    public void handle() {
        System.out.println("PLEASE PAY FOR THE TICKET YOU WANT!");
        context.setCurrentState(context.getMoneyState());
        context.getCurrentState().handle();
    }
}

The Context - TicketAutomat

This is the context class. It contais all states and has the some simple logic in it

// THE TICKET AUTOMAT IS THE CONTEXT
public class TicketAutomat {
    
    private State soldOutState;
    private State noMoneyState;
    private State moneyState;
    private State soldState;
    private State currentState;
    
    private int ticketsAvailable = 10;
    private boolean paid=false;
    
    TicketAutomat(int ticketsAvailable){
        soldState =  new TicketSoldState(this);
        soldOutState =  new TicketsSoldOutState(this);
        noMoneyState =  new NoMoneyState(this);
        moneyState =  new MoneyState(this);
        initCurrentState(ticketsAvailable);
    }
    
    private void initCurrentState(int ticketsAvailable){
        this.ticketsAvailable=ticketsAvailable;
        if(this.ticketsAvailable>0){
            setCurrentState(noMoneyState);
        }else{
            setCurrentState(soldOutState);
        }
    }
        
    public State getSoldOutState() {return soldOutState;}
    public State getNoMoneyState() {return noMoneyState;}
    public State getMoneyState() {return moneyState;}
    public State getSoldState() {return soldState;}
    public State getCurrentState() {return currentState;}
    public void setCurrentState(State currentState) {this.currentState = currentState;}
    public int getTicketsAvailable() {return ticketsAvailable;}
    public void setTicketsAvailable(int ticketsAvailable) {this.ticketsAvailable = ticketsAvailable;}
    public void updateTicketsAvailable(){this.ticketsAvailable-=1;}
    public boolean isTicketAvailable(){return this.ticketsAvailable>0;}
    public boolean hasPaid(){return paid;}
    public void setPaid(boolean paid){this.paid=paid;}
}

Testing it

Finally our client which tests it. With a Thread we are simulating a full cycle waiting 5 seconds between each state.

public class Client {
    public static void main(String[] args) {
        new Thread(){
            int ticketsAvailable = 5;
            final TicketAutomat automat = new TicketAutomat(ticketsAvailable);
            public void run() {
                while(automat.isTicketAvailable()){
                    automat.setPaid(true);
                    automat.getCurrentState().handle();
                    try {
                        sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        }.start();
    }
}
That's all! Hope you like it!

😱👇 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘‡

Be sure to read, it will change your life!
Show your work by Austin Kleonhttps://amzn.to/34NVmwx

This book is a must read - it will put you in another level! (Expert)
Agile Software Development, Principles, Patterns, and Practiceshttps://amzn.to/30WQSm2

Write cleaner code and stand out!
Clean Code - A Handbook of Agile Software Craftsmanship: https://amzn.to/33RvaSv

This book is very practical, straightforward and to the point! Worth every penny!
Kotlin for Android App Development (Developer's Library): https://amzn.to/33VZ6gp

Needless to say, these are top right?
Apple AirPods Pro: https://amzn.to/2GOICxy

😱👆 PROMOTIONAL DISCOUNT: BOOKS AND IPODS PRO ðŸ˜±ðŸ‘†