Difference between revisions of "State Pattern (padrão de desenho)/Exercício 01: Semáforo"

From Wiki**3

< State Pattern (padrão de desenho)
 
(8 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
= Problema =
 
= Problema =
  
Um semáforo tem um temporizador que emite impulsos a intervalos regulares. Estes impulsos chegam ao controlador do semáforo sob a forma de chamadas ao método '''tick'''. O semáforo tem ainda vários botões para controlo de situações especiais. Assim, o botão de pânico que faz com que o controlador mude o semáforo para a cor vermelha, qualquer que seja a anterior (método '''panic'''). O botão ''off'' faz com que o semáforo mude imediatamente para amarelo intermitente (método '''off'''). Esta situação é interrompida através dos botões ''on'' (volta ao comportamento normal; método '''on''') ou de pânico. O botão ''on'' é a única forma de fazer semáforo sair da situação de pânico e recuperar o funcionamento normal. Além do código de controlo, o semáforo tem ainda um método ('''status''') que permite saber a cor actual do semáforo. O semáforo começa intermitente e quando recupera das situações de intermitência e de pânico fica vermelho.
+
Um semáforo tem um temporizador que emite impulsos a intervalos regulares. Estes impulsos chegam ao controlador do semáforo sob a forma de chamadas ao método '''tick'''. Em funcionamento normal, um '''tick''' faz com que o semáforo passe da cor vermelha para a verde, da verde para a amarela e da amarela para a vermelha, reiniciando o ciclo. O semáforo tem ainda vários botões para controlo de situações especiais. Assim, o botão de pânico que faz com que o controlador mude o semáforo para a cor vermelha, qualquer que seja a anterior (método '''panic'''). O botão ''off'' faz com que o semáforo mude imediatamente para amarelo intermitente (método '''off'''). Esta situação é interrompida através dos botões ''on'' (volta ao comportamento normal; método '''on''') ou de pânico. O botão ''on'' é a única forma de fazer semáforo sair da situação de pânico e recuperar o funcionamento normal. Além do código de controlo, o semáforo tem ainda um método ('''status''') que permite saber a cor actual do semáforo. O semáforo começa intermitente e quando recupera das situações de intermitência e de pânico fica vermelho.
  
 
Implemente o semáforo e a sua máquina de estados.
 
Implemente o semáforo e a sua máquina de estados.
Line 8: Line 8:
 
= Solução =
 
= Solução =
  
== Classe TrafficLight (externa) e TrafficLight.State (interna) ==
+
A solução apresentada considera que a superclasse dos estados é interna (tem, desse modo, acesso ao estado interno do semáforo e não é necessário exportar nenhuma interface para gestão de estados.
  
<java5>
+
Notar os aspectos de herança de classes internas e a forma especial de chamada ao contrutor da superclasse interna. Notar ainda como uma classe interna (State) pode aceder ao objecto actual da classe externa (TrafficLight.this).
/**
+
 
* @author David Martins de Matos
+
Notar ainda que não é estritamente necessário que a superclasse das classes dos estados seja interna à classe detentora do estado ('''TrafficLight'''). Optou-se por definir a classe como interna para demonstrar como a classe interna pode aceder a estado privado da folha.
*/
+
 
 +
{{CollapsedCode|Ficheiro '''TrafficLight.java''' (classe TrafficLight (externa) e TrafficLight.State (interna))|
 +
<source lang="java">
 
public class TrafficLight {
 
public class TrafficLight {
  
/**
+
    /** The traffic light's state. */
* The traffic light's state.
+
    private State _state;
*/
 
private State _state;
 
 
 
/**
 
* Abstract state class.
 
*
 
* This class is internal so that it has access to the traffic light's
 
* internal state. Actual states are subclasses which must use this class'
 
* protected interface.
 
*/
 
public abstract class State {
 
  
/**
+
    /**
* Tick behavior.
+
    * Abstract state class.
*/
+
    *
public abstract void tick();
+
    * This class is internal so that it has access to the traffic light's
 +
    * internal state. Actual states are subclasses which must use this class'
 +
    * protected interface.
 +
    */
 +
    public abstract class State {
  
/**
+
        /** Tick behavior. */
* Panic behavior.
+
        public abstract void tick();
*/
 
public abstract void panic();
 
  
/**
+
        /** Panic behavior. */
* "On" behavior.
+
        public abstract void panic();
*/
 
public void on() {
 
// ignore
 
}
 
  
/**
+
        /** "On" behavior. */
* "Off" behavior.
+
        public void on() { /* ignore by default */ }
*/
 
public abstract void off();
 
  
/**
+
        /** "Off" behavior. */
* @return traffic light status.
+
        public abstract void off();
*/
 
public abstract String status();
 
  
/**
+
        /** @return traffic light status. */
* Define the traffic light's new state.
+
        public abstract String status();
*
 
* @param newState
 
*            the new state.
 
*/
 
protected void setState(State newState) {
 
_state = newState;
 
}
 
  
/**
+
        /**
* This method is needed so that new states can be created.
+
        * Define the traffic light's new state.
*  
+
        *
* @return the traffic light.
+
        * @param newState
*/
+
        *            the new state.
protected TrafficLight getLight() {
+
        */
return TrafficLight.this;
+
        protected void setState(State newState) {
}
+
            _state = newState;
}
+
        }
  
/**
+
        /**
* Initialize traffic light. Starts blinking.
+
        * This method is needed so that new states can be created.
*/
+
        *
public TrafficLight() {
+
        * @return the traffic light.
_state = new Blinking(this);
+
        */
}
+
        protected TrafficLight getLight() {
 +
            return TrafficLight.this;
 +
        }
 +
    }
  
/**
+
    /** Initialize traffic light. Starts blinking. */
* Process on button press.
+
    public TrafficLight() {
*/
+
        _state = new Blinking(this);
@SuppressWarnings("nls")
+
    }
public void on() {
 
System.out.print("[" + status() + "]");
 
_state.on();
 
System.out.println(" --(on)-> [" + status() + "]");
 
}
 
  
/**
+
    /** Process on button press. */
* Process off button press.
+
    public void on() {
*/
+
        System.out.print("[" + status() + "]");
@SuppressWarnings("nls")
+
        _state.on();
public void off() {
+
        System.out.println(" --(on)-> [" + status() + "]");
System.out.print("[" + status() + "]");
+
    }
_state.off();
 
System.out.println(" --(off)-> [" + status() + "]");
 
}
 
  
/**
+
    /** Process off button press. */
* Process panic button press.
+
    public void off() {
*/
+
        System.out.print("[" + status() + "]");
@SuppressWarnings("nls")
+
        _state.off();
public void panic() {
+
        System.out.println(" --(off)-> [" + status() + "]");
System.out.print("[" + status() + "] --(panic)-> ");
+
    }
_state.panic();
 
System.out.println("[" + status() + "]");
 
}
 
  
/**
+
    /** Process panic button press. */
* Process tick: switch light color.
+
    public void panic() {
*/
+
        System.out.print("[" + status() + "] --(panic)-> ");
@SuppressWarnings("nls")
+
        _state.panic();
public void tick() {
+
        System.out.println("[" + status() + "]");
System.out.print("[" + status() + "] --(tick)-> ");
+
    }
_state.tick();
 
System.out.println("[" + status() + "]");
 
}
 
  
/**
+
    /** Process tick: switch light color. */
* @return traffic light status.
+
    public void tick() {
*/
+
        System.out.print("[" + status() + "] --(tick)-> ");
public String status() {
+
        _state.tick();
return _state.status();
+
        System.out.println("[" + status() + "]");
}
+
    }
  
 +
    /** @return traffic light status. */
 +
    public String status() {
 +
        return _state.status();
 +
    }
 
}
 
}
</java5>
+
</source>
 +
}}
  
== Classe Ticking ==
 
  
 
Abstract class for representing normal behavior. See also the next section (color classes).
 
Abstract class for representing normal behavior. See also the next section (color classes).
  
<java5>
+
Ticking states are those corresponding to the usual three colors.
/**
+
 
* Ticking states are those corresponding to the usual three colors.
+
{{CollapsedCode|Ficheiro '''Ticking.java'''|
*/
+
<source lang="java">
 
public abstract class Ticking extends TrafficLight.State {
 
public abstract class Ticking extends TrafficLight.State {
  
/**
+
    /**
* @param light
+
    * @param light
*/
+
    */
Ticking(TrafficLight light) {
+
    Ticking(TrafficLight light) {
light.super();
+
        light.super();
}
+
    }
  
/**
+
    /**
* All colors switch to blinking when "off" is pressed.
+
    * All colors switch to blinking when "off" is pressed.
*  
+
    *
* @see TrafficLight.State#off()
+
    * @see TrafficLight.State#off()
*/
+
    */
@Override
+
    @Override
public void off() {
+
    public void off() {
setState(new Blinking(getLight()));
+
        setState(new Blinking(getLight()));
}
+
    }
 
 
/**
 
* All colors switch to panic when the button is pressed.
 
*
 
* @see TrafficLight.State#panic()
 
*/
 
@Override
 
public void panic() {
 
setState(new Panic(getLight()));
 
}
 
  
 +
    /**
 +
    * All colors switch to panic when the button is pressed.
 +
    *
 +
    * @see TrafficLight.State#panic()
 +
    */
 +
    @Override
 +
    public void panic() {
 +
        setState(new Panic(getLight()));
 +
    }
 
}
 
}
</java5>
+
</source>
 
+
}}
== Classes Red, Yellow, Green ==
 
  
 
Red light.
 
Red light.
  
<java5>
+
{{CollapsedCode|Ficheiro '''Red.java'''|
/**
+
<source lang="java">
* The red light.
 
*/
 
 
public class Red extends Ticking {
 
public class Red extends Ticking {
  
/**
+
    /**
* @param light
+
    * @param light
*/
+
    */
Red(TrafficLight light) {
+
    Red(TrafficLight light) {
super(light);
+
        super(light);
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#tick()
+
    * @see TrafficLight.State#tick()
*/
+
    */
@Override
+
    @Override
public void tick() {
+
    public void tick() {
setState(new Green(getLight()));
+
        setState(new Green(getLight()));
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#status()
+
    * @see TrafficLight.State#status()
*/
+
    */
@Override
+
    @Override
@SuppressWarnings("nls")
+
    public String status() {
public String status() {
+
        return "Red";
return "Red";
+
    }
}
 
 
}
 
}
</java5>
+
</source>
 +
}}
  
 
Yellow light.
 
Yellow light.
  
<java5>
+
{{CollapsedCode|Ficheiro '''Yellow.java'''|
/**
+
<source lang="java">
* The yellow light.
 
*/
 
 
public class Yellow extends Ticking {
 
public class Yellow extends Ticking {
  
/**
+
    /**
* @param light
+
    * @param light
*/
+
    */
Yellow(TrafficLight light) {
+
    Yellow(TrafficLight light) {
super(light);
+
        super(light);
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#tick()
+
    * @see TrafficLight.State#tick()
*/
+
    */
@Override
+
    @Override
public void tick() {
+
    public void tick() {
setState(new Red(getLight()));
+
        setState(new Red(getLight()));
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#status()
+
    * @see TrafficLight.State#status()
*/
+
    */
@Override
+
    @Override
@SuppressWarnings("nls")
+
    public String status() {
public String status() {
+
        return "Yellow";
return "Yellow";
+
    }
}
 
 
}
 
}
</java5>
+
</source>
 +
}}
  
 
Green light.
 
Green light.
  
<java5>
+
{{CollapsedCode|Ficheiro '''Green.java'''|
/**
+
<source lang="java">
* The green light.
 
*/
 
 
public class Green extends Ticking {
 
public class Green extends Ticking {
  
/**
+
    /**
* @param light
+
    * @param light
*/
+
    */
Green(TrafficLight light) {
+
    Green(TrafficLight light) {
super(light);
+
        super(light);
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#tick()
+
    * @see TrafficLight.State#tick()
*/
+
    */
@Override
+
    @Override
public void tick() {
+
    public void tick() {
setState(new Yellow(getLight()));
+
        setState(new Yellow(getLight()));
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#status()
+
    * @see TrafficLight.State#status()
*/
+
    */
@Override
+
    @Override
@SuppressWarnings("nls")
+
    public String status() {
public String status() {
+
        return "Green";
return "Green";
+
    }
}
 
 
}
 
}
</java5>
+
</source>
 +
}}
  
== Classe Panic ==
+
Panic state.
  
<java5>
+
{{CollapsedCode|Ficheiro '''Panic.java'''|
/**
+
<source lang="java">
* Panic state.
 
*/
 
 
public class Panic extends TrafficLight.State {
 
public class Panic extends TrafficLight.State {
  
/**
+
    /**
* @param light
+
    * @param light
*/
+
    */
Panic(TrafficLight light) {
+
    Panic(TrafficLight light) {
light.super();
+
        light.super();
}
+
    }
  
/**
+
    /**
* Return to "ticking" (normal) mode.
+
    * Return to "ticking" (normal) mode.
*  
+
    *
* @see TrafficLight.State#on()
+
    * @see TrafficLight.State#on()
*/
+
    */
@Override
+
    @Override
public void on() {
+
    public void on() {
setState(new Red(getLight()));
+
        setState(new Red(getLight()));
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#off()
+
    * @see TrafficLight.State#off()
*/
+
    */
@Override
+
    @Override
public void off() {
+
    public void off() {
// do nothing: already off
+
        // do nothing: already off
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#panic()
+
    * @see TrafficLight.State#panic()
*/
+
    */
@Override
+
    @Override
public void panic() {
+
    public void panic() {
// do nothing: already in panic mode
+
        // do nothing: already in panic mode
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#tick()
+
    * @see TrafficLight.State#tick()
*/
+
    */
@Override
+
    @Override
public void tick() {
+
    public void tick() {
// do nothing: ignore ticks in panic mode
+
        // do nothing: ignore ticks in panic mode
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#status()
+
    * @see TrafficLight.State#status()
*/
+
    */
@Override
+
    @Override
@SuppressWarnings("nls")
+
    public String status() {
public String status() {
+
        return "Panic";
return "Panic";
+
    }
}
 
 
}
 
}
</java5>
+
</source>
 +
}}
  
== Classe Blinking ==
+
Blinking light (off).
  
<java5>
+
{{CollapsedCode|Ficheiro '''Blinking.java'''|
/**
+
<source lang="java">
* Blinking light (off).
 
*/
 
 
public class Blinking extends TrafficLight.State {
 
public class Blinking extends TrafficLight.State {
  
/**
+
    /**
* @param light
+
    * @param light
*/
+
    */
Blinking(TrafficLight light) {
+
    Blinking(TrafficLight light) {
light.super();
+
        light.super();
}
+
    }
  
/**
+
    /**
* Return to "ticking" (normal) mode.
+
    * Return to "ticking" (normal) mode.
*  
+
    *
* @see TrafficLight.State#on()
+
    * @see TrafficLight.State#on()
*/
+
    */
@Override
+
    @Override
public void on() {
+
    public void on() {
setState(new Red(getLight()));
+
        setState(new Red(getLight()));
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#off()
+
    * @see TrafficLight.State#off()
*/
+
    */
@Override
+
    @Override
public void off() {
+
    public void off() {
// do nothing: already off
+
        // do nothing: already off
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#panic()
+
    * @see TrafficLight.State#panic()
*/
+
    */
@Override
+
    @Override
public void panic() {
+
    public void panic() {
setState(new Panic(getLight()));
+
        setState(new Panic(getLight()));
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#tick()
+
    * @see TrafficLight.State#tick()
*/
+
    */
@Override
+
    @Override
public void tick() {
+
    public void tick() {
// do nothing: ignore ticks
+
        // do nothing: ignore ticks
}
+
    }
  
/**
+
    /**
* @see TrafficLight.State#status()
+
    * @see TrafficLight.State#status()
*/
+
    */
@Override
+
    @Override
@SuppressWarnings("nls")
+
    public String status() {
public String status() {
+
        return "Blinking";
return "Blinking";
+
    }
}
 
 
}
 
}
</java5>
+
</source>
 
+
}}
== Classe App ==
 
  
 
Simple application to illustrate the traffic light's state changes.
 
Simple application to illustrate the traffic light's state changes.
  
<java5>
+
{{CollapsedCode|Ficheiro '''App.java'''|
/**
+
<source lang="java">
* Simple application to illustrate changes of light states.
 
*/
 
 
public class App {
 
public class App {
/**
+
    /**
* @param args
+
    * @param args
*/
+
    */
public static void main(String[] args) {
+
    public static void main(String[] args) {
TrafficLight light = new TrafficLight();
+
        TrafficLight light = new TrafficLight();
System.out.println("Light status: " + light.status());
+
        System.out.println("Light status: " + light.status());
light.off();
+
        light.off();
light.panic();
+
        light.panic();
light.on();
+
        light.on();
light.tick();
+
        light.tick();
light.tick();
+
        light.tick();
light.tick();
+
        light.tick();
light.tick();
+
        light.tick();
light.panic();
+
        light.panic();
light.off();
+
        light.off();
light.on();
+
        light.on();
light.off();
+
        light.off();
}
+
    }
 
}
 
}
</java5>
+
</source>
 +
}}
  
 
= Compiling and Running =
 
= Compiling and Running =
Line 453: Line 409:
 
[[category:PO]]
 
[[category:PO]]
 
[[category:Ensino]]
 
[[category:Ensino]]
 +
[[category:PO Exemplos]]

Latest revision as of 20:54, 8 November 2018

Problema

Um semáforo tem um temporizador que emite impulsos a intervalos regulares. Estes impulsos chegam ao controlador do semáforo sob a forma de chamadas ao método tick. Em funcionamento normal, um tick faz com que o semáforo passe da cor vermelha para a verde, da verde para a amarela e da amarela para a vermelha, reiniciando o ciclo. O semáforo tem ainda vários botões para controlo de situações especiais. Assim, o botão de pânico que faz com que o controlador mude o semáforo para a cor vermelha, qualquer que seja a anterior (método panic). O botão off faz com que o semáforo mude imediatamente para amarelo intermitente (método off). Esta situação é interrompida através dos botões on (volta ao comportamento normal; método on) ou de pânico. O botão on é a única forma de fazer semáforo sair da situação de pânico e recuperar o funcionamento normal. Além do código de controlo, o semáforo tem ainda um método (status) que permite saber a cor actual do semáforo. O semáforo começa intermitente e quando recupera das situações de intermitência e de pânico fica vermelho.

Implemente o semáforo e a sua máquina de estados.

Solução

A solução apresentada considera que a superclasse dos estados é interna (tem, desse modo, acesso ao estado interno do semáforo e não é necessário exportar nenhuma interface para gestão de estados.

Notar os aspectos de herança de classes internas e a forma especial de chamada ao contrutor da superclasse interna. Notar ainda como uma classe interna (State) pode aceder ao objecto actual da classe externa (TrafficLight.this).

Notar ainda que não é estritamente necessário que a superclasse das classes dos estados seja interna à classe detentora do estado (TrafficLight). Optou-se por definir a classe como interna para demonstrar como a classe interna pode aceder a estado privado da folha.

Ficheiro TrafficLight.java (classe TrafficLight (externa) e TrafficLight.State (interna))
public class TrafficLight {

    /** The traffic light's state. */
    private State _state;

    /**
     * Abstract state class.
     *
     * This class is internal so that it has access to the traffic light's
     * internal state. Actual states are subclasses which must use this class'
     * protected interface.
     */
    public abstract class State {

        /** Tick behavior. */
        public abstract void tick();

        /** Panic behavior. */
        public abstract void panic();

        /** "On" behavior. */
        public void on() { /* ignore by default */ }

        /** "Off" behavior. */
        public abstract void off();

        /** @return traffic light status. */
        public abstract String status();

        /**
         * Define the traffic light's new state.
         *
         * @param newState
         *            the new state.
         */
        protected void setState(State newState) {
            _state = newState;
        }

        /**
         * This method is needed so that new states can be created.
         *
         * @return the traffic light.
         */
        protected TrafficLight getLight() {
            return TrafficLight.this;
        }
    }

    /** Initialize traffic light. Starts blinking. */
    public TrafficLight() {
        _state = new Blinking(this);
    }

    /** Process on button press. */
    public void on() {
        System.out.print("[" + status() + "]");
        _state.on();
        System.out.println(" --(on)-> [" + status() + "]");
    }

    /** Process off button press. */
    public void off() {
        System.out.print("[" + status() + "]");
        _state.off();
        System.out.println(" --(off)-> [" + status() + "]");
    }

    /** Process panic button press. */
    public void panic() {
        System.out.print("[" + status() + "] --(panic)-> ");
        _state.panic();
        System.out.println("[" + status() + "]");
    }

    /** Process tick: switch light color. */
    public void tick() {
        System.out.print("[" + status() + "] --(tick)-> ");
        _state.tick();
        System.out.println("[" + status() + "]");
    }

    /** @return traffic light status. */
    public String status() {
        return _state.status();
    }
}


Abstract class for representing normal behavior. See also the next section (color classes).

Ticking states are those corresponding to the usual three colors.

Ficheiro Ticking.java
public abstract class Ticking extends TrafficLight.State {

    /**
     * @param light
     */
    Ticking(TrafficLight light) {
        light.super();
    }

    /**
     * All colors switch to blinking when "off" is pressed.
     *
     * @see TrafficLight.State#off()
     */
    @Override
    public void off() {
        setState(new Blinking(getLight()));
    }

    /**
     * All colors switch to panic when the button is pressed.
     *
     * @see TrafficLight.State#panic()
     */
    @Override
    public void panic() {
        setState(new Panic(getLight()));
    }
}

Red light.

Ficheiro Red.java
public class Red extends Ticking {

    /**
     * @param light
     */
    Red(TrafficLight light) {
        super(light);
    }

    /**
     * @see TrafficLight.State#tick()
     */
    @Override
    public void tick() {
        setState(new Green(getLight()));
    }

    /**
     * @see TrafficLight.State#status()
     */
    @Override
    public String status() {
        return "Red";
    }
}

Yellow light.

Ficheiro Yellow.java
public class Yellow extends Ticking {

    /**
     * @param light
     */
    Yellow(TrafficLight light) {
        super(light);
    }

    /**
     * @see TrafficLight.State#tick()
     */
    @Override
    public void tick() {
        setState(new Red(getLight()));
    }

    /**
     * @see TrafficLight.State#status()
     */
    @Override
    public String status() {
        return "Yellow";
    }
}

Green light.

Ficheiro Green.java
public class Green extends Ticking {

    /**
     * @param light
     */
    Green(TrafficLight light) {
        super(light);
    }

    /**
     * @see TrafficLight.State#tick()
     */
    @Override
    public void tick() {
        setState(new Yellow(getLight()));
    }

    /**
     * @see TrafficLight.State#status()
     */
    @Override
    public String status() {
        return "Green";
    }
}

Panic state.

Ficheiro Panic.java
public class Panic extends TrafficLight.State {

    /**
     * @param light
     */
    Panic(TrafficLight light) {
        light.super();
    }

    /**
     * Return to "ticking" (normal) mode.
     *
     * @see TrafficLight.State#on()
     */
    @Override
    public void on() {
        setState(new Red(getLight()));
    }

    /**
     * @see TrafficLight.State#off()
     */
    @Override
    public void off() {
        // do nothing: already off
    }

    /**
     * @see TrafficLight.State#panic()
     */
    @Override
    public void panic() {
        // do nothing: already in panic mode
    }

    /**
     * @see TrafficLight.State#tick()
     */
    @Override
    public void tick() {
        // do nothing: ignore ticks in panic mode
    }

    /**
     * @see TrafficLight.State#status()
     */
    @Override
    public String status() {
        return "Panic";
    }
}

Blinking light (off).

Ficheiro Blinking.java
public class Blinking extends TrafficLight.State {

    /**
     * @param light
     */
    Blinking(TrafficLight light) {
        light.super();
    }

    /**
     * Return to "ticking" (normal) mode.
     *
     * @see TrafficLight.State#on()
     */
    @Override
    public void on() {
        setState(new Red(getLight()));
    }

    /**
     * @see TrafficLight.State#off()
     */
    @Override
    public void off() {
        // do nothing: already off
    }

    /**
     * @see TrafficLight.State#panic()
     */
    @Override
    public void panic() {
        setState(new Panic(getLight()));
    }

    /**
     * @see TrafficLight.State#tick()
     */
    @Override
    public void tick() {
        // do nothing: ignore ticks
    }

    /**
     * @see TrafficLight.State#status()
     */
    @Override
    public String status() {
        return "Blinking";
    }
}

Simple application to illustrate the traffic light's state changes.

Ficheiro App.java
public class App {
    /**
     * @param args
     */
    public static void main(String[] args) {
        TrafficLight light = new TrafficLight();
        System.out.println("Light status: " + light.status());
        light.off();
        light.panic();
        light.on();
        light.tick();
        light.tick();
        light.tick();
        light.tick();
        light.panic();
        light.off();
        light.on();
        light.off();
    }
}

Compiling and Running

Compiling

Running

java App

Result:

Light status: Blinking
[Blinking] --(off)-> [Blinking]
[Blinking] --(panic)-> [Panic]
[Panic] --(on)-> [Red]
[Red] --(tick)-> [Green]
[Green] --(tick)-> [Yellow]
[Yellow] --(tick)-> [Red]
[Red] --(tick)-> [Green]
[Green] --(panic)-> [Panic]
[Panic] --(off)-> [Panic]
[Panic] --(on)-> [Red]
[Red] --(off)-> [Blinking]