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

From Wiki**3

< State Pattern (padrão de desenho)
 
(5 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 12: Line 12:
 
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 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).
  
== Classe TrafficLight (externa) e TrafficLight.State (interna) ==
+
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.
  
<java5>
+
{{CollapsedCode|Ficheiro '''TrafficLight.java''' (classe TrafficLight (externa) e TrafficLight.State (interna))|
/**
+
<source lang="java">
* @author David Martins de Matos
 
*/
 
 
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.
+
    * Abstract state class.
*  
+
    *
* This class is internal so that it has access to the traffic light's
+
    * 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'
+
    * internal state. Actual states are subclasses which must use this class'
* protected interface.
+
    * protected interface.
*/
+
    */
public abstract class State {
+
    public abstract class State {
  
/**
+
        /** Tick behavior. */
* Tick behavior.
+
        public abstract void tick();
*/
 
public abstract void tick();
 
  
/**
+
        /** Panic behavior. */
* Panic behavior.
+
        public abstract void panic();
*/
 
public abstract void panic();
 
  
/**
+
        /** "On" behavior. */
* "On" behavior.
+
        public void on() { /* ignore by default */ }
*/
 
public void on() {
 
// ignore
 
}
 
  
/**
+
        /** "Off" behavior. */
* "Off" behavior.
+
        public abstract void off();
*/
 
public abstract void off();
 
  
/**
+
        /** @return traffic light status. */
* @return traffic light status.
+
        public abstract String status();
*/
 
public abstract String status();
 
  
/**
+
        /**
* Define the traffic light's new state.
+
        * Define the traffic light's new state.
*  
+
        *
* @param newState
+
        * @param newState
*            the new state.
+
        *            the new state.
*/
+
        */
protected void setState(State newState) {
+
        protected void setState(State newState) {
_state = newState;
+
            _state = newState;
}
+
        }
  
/**
+
        /**
* This method is needed so that new states can be created.
+
        * This method is needed so that new states can be created.
*  
+
        *
* @return the traffic light.
+
        * @return the traffic light.
*/
+
        */
protected TrafficLight getLight() {
+
        protected TrafficLight getLight() {
return TrafficLight.this;
+
            return TrafficLight.this;
}
+
        }
}
+
    }
  
/**
+
    /** Initialize traffic light. Starts blinking. */
* Initialize traffic light. Starts blinking.
+
    public TrafficLight() {
*/
+
        _state = new Blinking(this);
public TrafficLight() {
+
    }
_state = new Blinking(this);
 
}
 
  
/**
+
    /** Process on button press. */
* Process on button press.
+
    public void on() {
*/
+
        System.out.print("[" + status() + "]");
@SuppressWarnings("nls")
+
        _state.on();
public void on() {
+
        System.out.println(" --(on)-> [" + status() + "]");
System.out.print("[" + status() + "]");
+
    }
_state.on();
 
System.out.println(" --(on)-> [" + status() + "]");
 
}
 
  
/**
+
    /** Process off button press. */
* Process off button press.
+
    public void off() {
*/
+
        System.out.print("[" + status() + "]");
@SuppressWarnings("nls")
+
        _state.off();
public void off() {
+
        System.out.println(" --(off)-> [" + status() + "]");
System.out.print("[" + status() + "]");
+
    }
_state.off();
 
System.out.println(" --(off)-> [" + status() + "]");
 
}
 
  
/**
+
    /** Process panic button press. */
* Process panic button press.
+
    public void panic() {
*/
+
        System.out.print("[" + status() + "] --(panic)-> ");
@SuppressWarnings("nls")
+
        _state.panic();
public void panic() {
+
        System.out.println("[" + status() + "]");
System.out.print("[" + status() + "] --(panic)-> ");
+
    }
_state.panic();
 
System.out.println("[" + status() + "]");
 
}
 
  
/**
+
    /** Process tick: switch light color. */
* Process tick: switch light color.
+
    public void tick() {
*/
+
        System.out.print("[" + status() + "] --(tick)-> ");
@SuppressWarnings("nls")
+
        _state.tick();
public void tick() {
+
        System.out.println("[" + status() + "]");
System.out.print("[" + status() + "] --(tick)-> ");
+
    }
_state.tick();
 
System.out.println("[" + status() + "]");
 
}
 
 
 
/**
 
* @return traffic light status.
 
*/
 
public String status() {
 
return _state.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 =

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]