Line 1: | Line 1: | ||
+ | {{TOCright}} | ||
= 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. | + | 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. |
Implemente o semáforo e a sua máquina de estados. | Implemente o semáforo e a sua máquina de estados. | ||
Line 7: | Line 8: | ||
= Solução = | = Solução = | ||
+ | == Classe TrafficLight (externa) e TrafficLight.State (interna) == | ||
+ | <java5> | ||
+ | /** | ||
+ | * @author David Martins de Matos | ||
+ | */ | ||
+ | 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 | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * "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. | ||
+ | */ | ||
+ | @SuppressWarnings("nls") | ||
+ | public void on() { | ||
+ | System.out.print("[" + status() + "]"); | ||
+ | _state.on(); | ||
+ | System.out.println(" --(on)-> [" + status() + "]"); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Process off button press. | ||
+ | */ | ||
+ | @SuppressWarnings("nls") | ||
+ | public void off() { | ||
+ | System.out.print("[" + status() + "]"); | ||
+ | _state.off(); | ||
+ | System.out.println(" --(off)-> [" + status() + "]"); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Process panic button press. | ||
+ | */ | ||
+ | @SuppressWarnings("nls") | ||
+ | public void panic() { | ||
+ | System.out.print("[" + status() + "] --(panic)-> "); | ||
+ | _state.panic(); | ||
+ | System.out.println("[" + status() + "]"); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Process tick: switch light color. | ||
+ | */ | ||
+ | @SuppressWarnings("nls") | ||
+ | public void tick() { | ||
+ | System.out.print("[" + status() + "] --(tick)-> "); | ||
+ | _state.tick(); | ||
+ | System.out.println("[" + status() + "]"); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @return traffic light status. | ||
+ | */ | ||
+ | public String status() { | ||
+ | return _state.status(); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | == Classe Ticking == | ||
+ | |||
+ | Abstract class for representing normal behavior. See also the next section (color classes). | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * Ticking states are those corresponding to the usual three colors. | ||
+ | */ | ||
+ | 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())); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | == Classes Red, Yellow, Green == | ||
+ | |||
+ | Red light. | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * The red light. | ||
+ | */ | ||
+ | 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 | ||
+ | @SuppressWarnings("nls") | ||
+ | public String status() { | ||
+ | return "Red"; | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | Yellow light. | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * The yellow light. | ||
+ | */ | ||
+ | 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 | ||
+ | @SuppressWarnings("nls") | ||
+ | public String status() { | ||
+ | return "Yellow"; | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | Green light. | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * The green light. | ||
+ | */ | ||
+ | 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 | ||
+ | @SuppressWarnings("nls") | ||
+ | public String status() { | ||
+ | return "Green"; | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | == Classe Panic == | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * Panic state. | ||
+ | */ | ||
+ | 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 | ||
+ | @SuppressWarnings("nls") | ||
+ | public String status() { | ||
+ | return "Panic"; | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | == Classe Blinking == | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * Blinking light (off). | ||
+ | */ | ||
+ | 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 | ||
+ | @SuppressWarnings("nls") | ||
+ | public String status() { | ||
+ | return "Blinking"; | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | == Classe App == | ||
+ | |||
+ | Simple application to illustrate the traffic light's state changes. | ||
+ | |||
+ | <java5> | ||
+ | /** | ||
+ | * Simple application to illustrate changes of light states. | ||
+ | */ | ||
+ | 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(); | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | = 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] | ||
[[category:PO]] | [[category:PO]] | ||
[[category:Ensino]] | [[category:Ensino]] |
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.
Implemente o semáforo e a sua máquina de estados.
<java5> /**
* @author David Martins de Matos */
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 }
/** * "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. */ @SuppressWarnings("nls") public void on() { System.out.print("[" + status() + "]"); _state.on(); System.out.println(" --(on)-> [" + status() + "]"); }
/** * Process off button press. */ @SuppressWarnings("nls") public void off() { System.out.print("[" + status() + "]"); _state.off(); System.out.println(" --(off)-> [" + status() + "]"); }
/** * Process panic button press. */ @SuppressWarnings("nls") public void panic() { System.out.print("[" + status() + "] --(panic)-> "); _state.panic(); System.out.println("[" + status() + "]"); }
/** * Process tick: switch light color. */ @SuppressWarnings("nls") public void tick() { System.out.print("[" + status() + "] --(tick)-> "); _state.tick(); System.out.println("[" + status() + "]"); }
/** * @return traffic light status. */ public String status() { return _state.status(); }
} </java5>
Abstract class for representing normal behavior. See also the next section (color classes).
<java5> /**
* Ticking states are those corresponding to the usual three colors. */
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())); }
} </java5>
Red light.
<java5> /**
* The red light. */
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 @SuppressWarnings("nls") public String status() { return "Red"; } } </java5>
Yellow light.
<java5> /**
* The yellow light. */
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 @SuppressWarnings("nls") public String status() { return "Yellow"; } } </java5>
Green light.
<java5> /**
* The green light. */
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 @SuppressWarnings("nls") public String status() { return "Green"; } } </java5>
<java5> /**
* Panic state. */
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 @SuppressWarnings("nls") public String status() { return "Panic"; } } </java5>
<java5> /**
* Blinking light (off). */
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 @SuppressWarnings("nls") public String status() { return "Blinking"; } } </java5>
Simple application to illustrate the traffic light's state changes.
<java5> /**
* Simple application to illustrate changes of light states. */
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(); } } </java5>
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]