(→Solução) |
|||
(4 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 14: | Line 14: | ||
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. | 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. */ | |
− | + | 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(); | |
− | + | } | |
− | |||
− | |||
} | } | ||
− | </ | + | </source> |
+ | }} | ||
− | |||
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). | ||
Line 124: | Line 111: | ||
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 | |
− | + | */ | |
− | + | 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())); | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
− | + | }} | |
− | |||
Red light. | Red light. | ||
− | < | + | {{CollapsedCode|Ficheiro '''Red.java'''| |
+ | <source lang="java"> | ||
public class Red extends Ticking { | 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"; | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
+ | }} | ||
Yellow light. | Yellow light. | ||
− | < | + | {{CollapsedCode|Ficheiro '''Yellow.java'''| |
+ | <source lang="java"> | ||
public class Yellow extends Ticking { | 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"; | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
+ | }} | ||
Green light. | Green light. | ||
− | < | + | {{CollapsedCode|Ficheiro '''Green.java'''| |
+ | <source lang="java"> | ||
public class Green extends Ticking { | 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"; | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
− | + | }} | |
− | |||
Panic state. | Panic state. | ||
− | < | + | {{CollapsedCode|Ficheiro '''Panic.java'''| |
+ | <source lang="java"> | ||
public class Panic extends TrafficLight.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 | |
− | + | public String status() { | |
− | + | return "Panic"; | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
− | + | }} | |
− | |||
Blinking light (off). | Blinking light (off). | ||
− | < | + | {{CollapsedCode|Ficheiro '''Blinking.java'''| |
+ | <source lang="java"> | ||
public class Blinking extends TrafficLight.State { | 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"; | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
− | + | }} | |
− | |||
Simple application to illustrate the traffic light's state changes. | Simple application to illustrate the traffic light's state changes. | ||
− | < | + | {{CollapsedCode|Ficheiro '''App.java'''| |
+ | <source lang="java"> | ||
public class App { | 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(); | |
− | + | } | |
} | } | ||
− | </ | + | </source> |
+ | }} | ||
= Compiling and Running = | = Compiling and Running = |
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.
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();
}
}
|
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]