Tag: Programação avançada
Java, exercício de análise
assunto: excepções
pergunta: qual o output do seguinte:
package recursopa2; class MyException extends Exception { } class main { static void f(int n) throws MyException { try { if (n > 0) { throw new MyException(); } System.out.print("fl "); } catch (MyException e) { System.out.print("f2 "); //saida: f2 } finally { System.out.print("f3 "); //saida: f3 } System.out.print("f4 "); //saida: f4 } public static void main(String[] args) { try { f(2); System.out.print("ml "); //saida: m1 } catch (MyException e) { System.out.print("m2 "); } System.out.print("m3 "); //saida: m3 } }
assunto: classes concreta (não abstracta)
pergunta: qual o output do seguinte:
interface IMove { void move(); } interface IJump extends IMove { default void jump() { System.out.println(" jump "); } int getHeight(); } class Kanguru implements IJump { //para se tornar numa classe concreta, tem que ter todos os métodos anteriores public void jump() { } public void move() { } public int getHeight() { return 1; } }
assunto: equals, arrays, hashCode, hashSet
pergunta: qual o output do seguinte:
package recursopa2; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; class Product { private String id; private int stockQt; public Product(String id, int q) { this.id = id; this.stockQt = q; } public boolean sell(int n) { if (stockQt >= n) { stockQt -= n; return true; } return false; } @Override public boolean equals(Object ob) { if (ob == null || getClass() != ob.getClass()) { return false; } return id.equals(((Product) ob).id); } @Override public int hashCode() { return this.stockQt; } } public class main { public static void main(String[] args) { Product a = new Product("idA", 10); Set<Product> set = new HashSet<>(); set.add(a); a.sell(4); System.out.print(" Contains? " + set.contains(a)); //supostamente estas a comparar com o equals endereços de memória //saida: falso Product b = new Product("id8", 10); List<Product> list = new ArrayList<>(); list.add(b); b.sell(4); System.out.print(" Contains? " + list.contains(b)); //sendo um array.. //saida: true } }
assunto: classes derivadas, super
pergunta: qual o output do seguinte:
package recursopa2; class Bird { private String name; public Bird(String s) { name = s; } @Override public String toString() { return name; } } class Swallow extends Bird { public Swallow(String s) { //line A super(s); } public String toString() { // line B return super.toString() + "Swallow"; } } public class main { public static void main(String[] args) { Swallow objl = new Swallow(" from Africa "); Swallow obj2 = new Swallow(" from the islands "); System.out.println(objl + " " + obj2); //saida: from Africa Swallow from the islands Swallow } }
assunto: classes derivadas
pergunta: qual o output do seguinte:
package recursopa2; interface IMove { void move(); //mover } interface IFly extends IMove { void fly(); //voar } class Gaivota implements IFly { public void move() { System.out.println("move"); } public void fly() { System.out.println("fly"); } } class main { public static void main(String[] args) { IMove a = new IMove(); //linha 1 //erro: IMove, é uma interface, é abstracta IMove[] b = new IFly[4]; //linha 2 IFly c = new Gaivota(); //linha 3 IMove d = new Gaivota(); //linha 4 c.move(); //linha 5 c.fly(); //linha 6 d.fly(); //linha 7 //erro: o método fly nao faz parte de IMove d.move(); //linha 8 c = d; //linha 9 //erro: não da para coverter tipos diferentes d = c; //linha 10 } }
assunto: máquina de estados, state machine
pergunta: pretende desenvolver uma nova versão da classe MTThread sob a forma de uma máquina de estados orientada a objectos. Recorra, para o efeito, ao padrão estudado nas aulas laboratoriais e aplicado ao trabalho prático de modo a que uma thread passe a ser uma instância de uma classe que, entre outros atributos, inclua o seu estado actual e tire partido do polimorfismo ao nível dos estados.
package recursopa2; class MTThread { public static enum Const { WAII_START, WAII_TO_BE_SCHEDULED, TERMINATED, YELD_INVOKED, RUNNING, SCHEDULE_COMPLETED, UNBLOCKED, SLEEP_COMPLETED, BLOCKED, SLEEPING, SLEEP_INVOKED }; private Const situation; private Data data; // Some hidden stuff you don't have to worry about //(constructors, getters, ...J /* ... */ public Const getSituation() { return situation; } public void start() { if (situation == Const.WAII_START) { situation = Const.WAII_TO_BE_SCHEDULED; } } public void schedule() { if (situation == Const.WAII_TO_BE_SCHEDULED) { situation = Const.RUNNING; } } public void doSomething() { if (situation == Const.RUNNING) { Const result = data.doSomething(); switch (result) { case YELD_INVOKED: situation = Const.WAII_TO_BE_SCHEDULED; break; case BLOCKED: situation = Const.BLOCKED; break; case SLEEP_INVOKED: situation = Const.SLEEPING; break; case TERMINATED: situation = Const.TERMINATED; break; default: break; } } } public void scheduleCompleted() { if (situation == Const.WAII_TO_BE_SCHEDULED) { situation = Const.RUNNING; } } public void unblocked() { if (situation == Const.BLOCKED) { situation = Const.WAII_TO_BE_SCHEDULED; } } public void sleepCompleted() { if (situation == Const.SLEEPING) { situation = Const.WAII_TO_BE_SCHEDULED; } } }
resposta:
interface IStates { Const getSituation(); IStates start(); IStates schedule(); IStates doSomething(); IStates scheduleCompleted(); IStates unblocked(); IStates sleepCompleted(); }
assunto: máquina de estados, state machine
pergunta: implemente uma classe StateAdapter que implemente a interface IStates e a partir da qual derivam todos os estados da nova versão da máquina de estados MTThread
public class StateAdapter implements IStates { @Override public Const getSituation() { return this; } @Override IStates start() { return this; } @Override IStates schedule() { return this; } @Override IStates doSomething() { return this; } @Override IStates scheduleCompleted() { return this; } @Override IStates unblocked() { return this; } @Override IStates sleepCompleted() { return this; } }
assunto: máquina de estados, state machine, IStates
pergunta: implemente uma classe que representa o estado em que a thread se encontra bloqueada na nova versão da máquina de estados MTThread
class Blocked extends StateAdapter{ @Override IStates unblocked(){ return new WaitToBeScheduled(); } }
assunto: máquina de estados, state machine
pergunta: As classes Defender e Forward representam jogadores de futebol, sendo ambas derivadas da classe Player. A classe Club contém uma coleção de jogadores que podem ser do tipo Defender ou Forward. A classe Club permite acrescentar jogadores e saber o número de jogadores que contém. Escreva o código necessário para que a criação de objetos do tipo Player seja feita utilizando o padrão Fábrica de Objetos e complete a função addPlayer() da classe Club, utilizando este padrão.
package recursopa2; import java.util.ArrayList; import java.util.List; enum PlayerTypes { DEFENDER, FORWARD } abstract class Player { private String name; public Player(String name) { this.name = name; } //... } class Defender extends Player { public Defender(String name) { //... } //... } class Forward extends Player { public Forward(String name) { //... } //... } class Club { private List<Player> players = new ArrayList<>(); //... public void addPlayer(PlayerTypes type, String name) { // Fazer : usar a fabrica de objetos do tipo Player } public int getNumPlayers() { return players.size(); } }
resposta:
public void addPlayer(PlayerTypes type, String name) { switch (type) { case DEFENDER: players.add(new Defender(name)); break; case FORWARD: players.add(new Forward(name)); break; } }
assunto: PropertyChangeListener, propertyChange
pergunta: A classe ClubPanel faz parte do interface de utilizador gráfico para objetos de Club, tendo o objetivo de mostrar o número de jogadores do clube, sempre atualizado. Acrescente o necessário à classe ClubPanel de modo a cumprir este objetivo
package recursopa2; import java.beans.PropertyChangeEvent; class ClubPanel extends VBox { private ObservableClub modelObs;// ligacao ao modelObs private Label nPlayers; public ClubPanel(ObservableClub model) { this.modelObs = model; nPlayers = new Label("N. players " + modelObs.getNumPlayers()); getChildren().addAll(nPlayers); setSpacing(5); setPadding(new Insets(10, 10, 10, 10)); setAlignment(Pos.CENTER); modelObs.addPropertyChangeListener(this); } //resposta: private void updateNumberOfPlayers(){ nPlayers.setText("N. players" + modelObs.getNumPlayers()); } @Override public void propertyChange(PropertyChangeEvent ev){ updateNumberOfPlayers(); } }
assunto: máquina de estados, state machine
pergunta: Idealize um diagrama que represente a máquina de estados MTThread de forma adequada, com atribuição de nomes aos estados e às transições/métodos coincidentes com os da listagem. Deve representar todas as transições que podem ocorrer entre os estados. Descreva este diagrama de forma textual seguindo o formato usado no seguinte exemplo (estado [condição] => próximo estado):
e
package recursopa2; class MTThread { public static enum Const { WAII_START, WAII_TO_BE_SCHEDULED, TERMINATED, YELD_INVOKED, RUNNING, SCHEDULE_COMPLETED, UNBLOCKED, SLEEP_COMPLETED, BLOCKED, SLEEPING, SLEEP_INVOKED }; private Const situation; private Data data; // Some hidden stuff you don't have to worry about //(constructors, getters, ...J /* ... */ public Const getSituation() { return situation; } public void start() { if (situation == Const.WAII_START) { situation = Const.WAII_TO_BE_SCHEDULED; } } public void schedule() { if (situation == Const.WAII_TO_BE_SCHEDULED) { situation = Const.RUNNING; } } public void doSomething() { if (situation == Const.RUNNING) { Const result = data.doSomething(); switch (result) { case YELD_INVOKED: situation = Const.WAII_TO_BE_SCHEDULED; break; case BLOCKED: situation = Const.BLOCKED; break; case SLEEP_INVOKED: situation = Const.SLEEPING; break; case TERMINATED: situation = Const.TERMINATED; break; default: break; } } } public void scheduleCompleted() { if (situation == Const.WAII_TO_BE_SCHEDULED) { situation = Const.RUNNING; } } public void unblocked() { if (situation == Const.BLOCKED) { situation = Const.WAII_TO_BE_SCHEDULED; } } public void sleepCompleted() { if (situation == Const.SLEEPING) { situation = Const.WAII_TO_BE_SCHEDULED; } } }
resposta:
States: WAIT_START, WAIT_TO_BE_SCHEDULED, TERMINATED, RUNNING, BLOCKED, SLEEPING Transitions: WAIT_START start()=>WAIT_TO_BE_SCHEDULED WAIT_TO_BE_SCHEDULED schedule()=>RUNNING TERMINATED RUNNING doSomething()[result = YELD_INVOKED] => WAII_TO_BE_SCHEDULED doSomething()[result = BLOCKED] => BLOCKED doSomething()[result = SLEEP_INVOKED] => SLEEPING doSomething()[result = TERMINATED] => TERMINATED scheduleCompleted() => WAII_TO_BE_SCHEDULED BLOCKED unblocked() =>WAII_TO_BE_SCHEDULED SLEEPING sleepCompleted() =>WAII_TO_BE_SCHEDULED
Java, exercício de análise
assunto: equals, hashcode e colecções
pergunta: qual o output do seguinte:
package recursopa2; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; class Aluno{ private String nome; private int codigo; public Aluno(String nome, int codigo){ this.nome = nome; this.codigo = codigo; } public boolean equals(Object ob){ if(!(ob instanceof Aluno)) return false; //o equals só exige que tenham o mesmo nome return nome.equals(((Aluno)ob).nome);// (Aluno) é um cast importante, por ser Object } public int hashCode(){ //vai retornar o código do aluno return this.codigo; } } //o equals e o hashCode estão mal feitos/compativeis (não está bem planeado) //eles deviam ser compativeis, pois cada um pergunta por uma coisa diferente //o hashCode devia retornar os mesmo ou um sub conjunto dos membros do equals class main{ public static void main(String[] args) { Set<Aluno> conjunto = new HashSet<>(); //HashSet (se são iguais) se: //para ver se está contido, uso o equals e o hashCode //se o hashCode for diferente acabou //se o hashCode for igual vai ver se o equals diz que sim ou que não //HashSet, não deixa acrescentar elementos que ele ache que já tem //não permite/recusa assim repetições Map<Aluno,Integer> mapa = new HashMap<>(); //HashMap //não deixa que existam chaves iguais //(compara a chave do map, primeiro testa o hashcode depois o equals) //vai verificar se existe alguma chave igual, se o hashCode é o mesmo //se for só deixa entrar alterando o valor da chave que está a ser usada List<Aluno> lista = new ArrayList<>(); //ArrayList //acrescenta tudo o que lhe dado, e considera que contém //e só usa o equals para verificar, mas deixa sempre acrescentar conjunto.add(new Aluno("aaa", 2)); //fica, é o primeiro conjunto.add(new Aluno("aaa", 2)); //não fica, tem o mesmo nome, usado o equals conjunto.add(new Aluno("aaa", 4)); //fica, não existe nenhum com o mesmo hashCode conjunto.add(new Aluno("bbb", 2)); //hashCode igual, vamos ver o equals se dá igual, fica mapa.put(new Aluno("aaa", 2),1); //fica é o primeiro, mas depois saiu mapa.put(new Aluno("aaa", 2),1); //fica, é igual, mas sai o primeiro mapa.put(new Aluno("aaa", 4),1); //fica, a chave/hashCode é diferente: "aaa", 4, nem sequer usa o equals mapa.put(new Aluno("bbb", 2),1); //o hashCode é igual, mas usa o equals que é diferente, fica lista.add(new Aluno("aaa", 2)); //fica é i primeiro lista.add(new Aluno("aaa", 2)); //fica, mesmo que sejam iguais, aceita sempre lista.add(new Aluno("aaa", 4)); //fica lista.add(new Aluno("bbb", 2)); //fica System.out.print(conjunto.size() + " "); // 3 System.out.print(mapa.size() + " "); // 3 System.out.println(lista.size()); //4 Aluno a = new Aluno("bbb", 3); System.out.print(conjunto.contains(a) + " "); //perguntar se o conjunto tem o "bbb", 3 //o conjunto tem o "bbb" mas não tem o código 3 //assim o cojunto vai ver primeiro o hashCode, é diferente //logo não contem, logo a resposta dá false System.out.print((mapa.get(a) != null) + " "); //o mapa.get(a), tem lá um "bbb" com código 2 //mas o a tem código 3 //não existe nenhum hashcode 3, , resposta dá false System.out.println(lista.contains(a)); //a lista só vai ver o equals //o equals neste caso só compara o nome //, e a resposta dá true } }
Java, exercício de análise
assunto: arraylist, equals
pergunta: qual o output do seguinte:
package recursopa2; import java.util.ArrayList; import java.util.List; class Inteiro { private int i; public Inteiro(int i) { this.i = i; } public void setVal(int i) { this.i = i; } public int getVal() { return i; } public String toString() { return "" + i; } } class main { public static void main(String[] args) { List<Inteiro> listaInteiros = new ArrayList<>(); //criado um arraylist de listaInteiros Inteiro i = new Inteiro(10); Inteiro j = new Inteiro(10); System.out.println(i == j); //saida: falso //porque estão em referências diferentes System.out.println(i.equals(j)); //saida: falso //o equals faz a comparação que nos programamos lá dentro //por exemplo comparar conteudos //mas o equals não foi definido, e não dá erro porque //está a usar a do object, class Inteiro extends object //e a equals no object considera dois objetos iguais //se tiverem o mesmo endereço listaInteiros.add(i); listaInteiros.add(j); j = i; //j refere o i j.setVal(2); //o primeiro elemento do array list fica 2 System.out.println(i); //saida: 2 System.out.println(j); //saida: 2 System.out.println(listaInteiros.get(0)); //saida: 2 System.out.println(listaInteiros.get(1)); //saida: 10 } }
Java, exercício de análise
Desenvolva a classe Artista tendo em consideração os seguintes requisitos:
Assuma que a classe Artista herda as características encapsuladas pela classe Pessoa (atenção, não a desenvolva… assuma apenas que já existe);
resposta: Artista extends Pessoa
Assuma que Pessoa possui o atributo privado nomeCivil e que não existe qualquer getter correspondente;
resposta:
Assuma que Pessoa apenas pode ser instanciada fornecendo o nome civil da pessoa encapsulada;
resposta:
Assuma que Pessoa possui os métodos int hashCode(), boolean equals(Object o) e String toString() adequadamente redefinidos, sabendo que duas instâncias de Pessoa são iguais quando possuem os mesmos nomes civis (a utilização de maiúsculas e minúsculas é irrelevante).
resposta:
A classe Artista possui, além do atributo herdado de Pessoa, o atributo nomeArtistico;
resposta: No artista, o construtor tem que receber o nome, e tem que se fazer super do nomecivil
O método boolean equals(Object o) da classe Artista deve garantir que uma instância desta classe é considerada igual a outro objecto quando este último é do tipo Artista e possui o mesmo nome civil e o mesmo nome artístico (a utilização de maiúsculas e minúsculas é irrelevante);
resposta: a classe artista que deriva, sabemos que o equals da pessoa exisge um nome civil, não temos acesso ao nomecivil, não existe getter, assim tem que se construir o equals da classe derivada, return super.equals e a exisgência da igualdade do nome artistica. não esquecer do instanceof artista
A classe Artista deve possuir um método int hashCode() adequado;
resposta: super hashCode
O método String toString() da classe Artista deve retornar uma string em que o nome civil aparece entre parêntesis depois do nome artístico;
resposta: super.toString() + nomeDoArtista
As linhas de código “oo.writeObject(artista);” e “(Artista)oin.readObject();”, sabendo que oo é do tipo ObjectOuputStream, oin do tipo ObjectInputStream e artista do tipo Artista, não devem gerar qualquer tipo de exceção relacionada com a natureza de artista.
resposta: para as classes implementarem serializer, para a escrita de ficheiros não terem problemas
Java, exercício de análise
assunto: hierarquia, classes, interface, derivadas
pergunta: qual o output do seguinte:
package recursopa2; interface IPodeDeslocar { void vira(double angulo); void defineVelocidade(double v); } interface IPodeCaminhar extends IPodeDeslocar { void caminha(); } interface IPodeCorrer extends IPodeCaminhar { void corre(); } interface IPodeVoar extends IPodeDeslocar { void voa(double altitude); } class Felino implements IPodeCorrer { public void corre() { } //está mal falta mas outras três //para ser concreta e não precisar do abstract //precisa: caminha, defineVelocidade, vira } abstract class AveRapina implements IPodeVoar { public void voa(double a) { } //para ser concreta precisa do vira, defineVelocidade //mas é abstract e não precisa } class Tigre extends Felino { //se corrigir acrescentado em Felino //caminha, defineVelocidade, vira //assim em Tigre devemos implemntar todas //corre, caminha, defineVelocidade, vira //e sem restringir a visibilidade, isto é //mantendo public void corre() ... } class Avestruz implements IPodeCorrer { public void vira(double angulo) { } public void defineVelocidade(double v) { } public void caminha() { } public void corre() { } //está correcta este concretização } class Aguia extends AveRapina implements IPodeCaminhar { public void vira(double angulo) { } public void defineVelocidade(double v) { } public void caminha() { } //aguia deriva de AveRapina //tem por via do implements: //caminha, vira, defineVelocidade //tem pelo extends da sua derivada abstract //deveria ter voa, mas a AveRapina é asbtract //logo esta classe implementa tudo } class Main { public static void main(String args[]) { IPodeDeslocar d1[] = new IPodeDeslocar[10]; //não tem erro //podemos criar arrays dinâmicos para interfaces d1[0] = new AveRapina(); //erro: não se pode criar um objecto de uma classe abstracta //podem existir referências, objetos não d1[0].voa(10.5); //erro, d1 é uma referencia para IPodeDeslocar //mas o IPodeDeslocar não tem o método voa d1[1] = new Avestruz(); Avestruz av = d1[1]; //erro, uma referências para derivada não pode receber //uma referencia para o topo da hierarquia IPodeDeslocar t1 = new Tigre(); IPodeCorrer t2 = t1; //t2=t1, siginifca o mais abaixo receber o mais acima //IPodeDeslocar é o topo, IPodeCorrer está abaixo //não funciona. t1 = t2; //o de cima pode receber o debaixo //IPodeDeslocar é o topo, IPodeCorrer está abaixo Tigre t2 = new Felino(); //erro, porque Tigre deriva de Felino //uma referência para a derivada não pode receber a da base //só a referência para base é que podia receber a derivada Aguia ag = new Aguia(); AveRapina ar = ag; //aguia deriva de aveRapina //aveRapina está mais acima pode então receber //o que está mais abaixo ar.caminha(); //não faz parte das funções que desaguam.. IPodeCaminhar aguia = new Aguia(); //sim porque Ague implementa IPodeCaminhar IPodeCorrer tigre = new Tigre(); //sim IPodeCorrer está na linha acima da hierarquia tigre = aguia; //erro, porque tigre está mais abaixo na hierarquia //IPodeCaminhar está acima não pode ser dado ao mais abaixo aguia = tigre; //IPodeCorrer está acima e pode ser dado ao mais abaixo //ao contrário já dá IPodeCaminhar ag2 = (AveRapina) aguia; //não está na mesma linha IPodeCorrer t3 = (Felino) tigre; } }Tags : java, Programação avançada
Java, exercício de análise
assunto: interfaces, classes, heranças, métodos, classes concretas, classes abstractas
pergunta: qual o output do seguinte:
package recursopa2; interface IA { String getA(); } interface IB extends IA { //extends, deriva de IA int getB(); } interface IC { int getC(); } class D implements IB, IC { //implements. tem que ter todos os métodos //mas sendo abstract não precisa private String a; private int b, c; public D(String a, int b, int c) { this.a = a; this.b = b; this.c = c; } public String getA() { return a; } public int getB() { return b; } public int getC() { return c; } public void setA(String a) { this.a = a; } public void setB(int b) { this.b = b; } public void setC(int c) { this.c = c; } public boolean equals(Object o) { if (o == null || !(o instanceof D)) { //se a referência for nula ou se não for instanceof return false; } //return a.equalsIgnoreCase(o.getA()); //o o não sabe da referencia do getA() //resolução do erro: //return a.equalsIgnoreCase(((D)o).getA()); //resolução: return a.equalsIgnoreCase(((D) o).getA()); } } class E extends D { //extends, deriva de D public E(String a, int b, int c) { //1º vai ser chamado o construtor da base //mas o construtor da base não tem valores por omissão //setA(a); //setB(b); //setC(c); //resolução: super(a, b, c); } } class F extends E { //extends, deriva de E private double d; public F(String a, int b, int c, double d) { //setA(a); //setB(b); //setC(c); //resolução: super(a, b, c); this.d = d; } public double getD() { return d; } public boolean equals(Object o) { if (o == null || !(o instanceof F)) { return false; } //return a.equalsIgnoreCase(o.getA()) && b == o.getB() && c == o.getC(); //porque o é object, não conhece o getA, getB, getC, e o a é privado da base //e não temos qualquer acesso //resolução: return getA().equalsIgnoreCase(((F)o).getA()) && getB() == ((F)o).getB() && getC() == ((F)o).getC(); } } class main { public static void main(String args[]) { IB a = new E("abc", 1, 1); //classe E dreviva de D //D implementa IB e IC //assim a classe E está na linha de herança de IB //classe E está na descendencia de IB //uma referencia para o IB pode referir um objecto E D b = new F("abc", 1, 1, 2.2); //classe F deriva de E //e E deriva de B //F está na linha de descendencia de D //pode então referir um objecto de F IA c = new E("abc", 3, 3); //classe E deriva de D //D implementa IB, //IB que deriva de IA //logo E está na descendencia de IA //IB d = new IB(); //dá erro //criar um objeto de uma interface //com funções abstractas //não é possivel IC e = new F("ddd", 4, 4, 4.4); //F deriva de E //E deriva de D //D implementa IC //F está na descendencia de IC //F é uma classe concreta IA r1[] = new D[5]; //criar um array de referências new D[5]; //D é uma classe abstracta //não se pode criar objetos da classe D //mas podemos criar arrays de referências para D //mas que depois se refere a objectos de classes //derivadas de D mas que são concretas //assim, podemos criar arrays de referências para //classes abstractas //e IA está na herança da linha para cima IA r2[] = new IB[5]; //tambem se pode criar arrays para referências //de interfaces, porque se trata de arrays //de referências, e essas referências //vão ser objectos de classes concretas //e que implementam directa ou indirectamente //este interface //e IA está na linha de herança de IB //IB r3[] = new IA[5]; //dá erro //porque estamos a observar a herança ao contrário //o IA é que é a base de IB //a derivada a receber a base não IC r4[] = new IC[5]; //um array para referêncas para interfaces new IC[5] //e é uma classe concreta System.out.println(a); System.out.println(b); System.out.println(a.equals(b)); //a é um objecto da classe E //o a chama o equals, //o a é da classe E //a classe E não tem o equals //mas a classe E deriva de D que tem //vai ter a versão herdada //e também //b é um objecto da classe F //f é instanciaof de D (é derivada da derivada de D) //e na comparação interessa o getA que é a string "abc" //resultado: true System.out.println(b.equals(a)); //b é uma objecto da classe F //vai ser chamado o equals da classe F //membroA e membroB e membroC sejam iguais //o a é um objecto de E //E é instanceof D //e por esse motivo não faz mais nada //resultado: false //o (o instanceof F) //não garante uma simetria de igualdade System.out.println(c.equals(b)); //c é uma objecto da classe E //E, em um equals que exige //que o argumento seja (o instanceof D) //e D tem que getA, string, seja igual //resultado: true System.out.println(c.getA()); //resultado: abc //System.out.println(e.getA()); //tem erro //o e é uma referencia para IC //o IC só tem o método getC //quem tem o getA é o interface IA } }
Java, exercício de análise
assunto: interfaces, funções abstracta, derivadas
e funções default: não sou obrigado a redefinir, não é abstracta, tem uma implementação por omissão
e funções static
pergunta: qual o output do seguinte:
package recursopa2; interface Pagamento { void receber(); void darTroco(); } abstract class Parquimetro implements Pagamento { private String cidade; Parquimetro(String s) { cidade = s; } abstract void calcula(); void calcula2() { } } interface RegistaVisita { void registaVisita(); } //ser derivada de Parquimetro e "do tipo" RegistaVisita // "do tipo" -> impementa a interface RegistaVisita // "ser concreta", todos os métodos têm que ser concretizados //e o membro cidade ser inicializada com "Coimbra" //assim, //se forem default ou static não é preciso/não é obrigatório redefinir //se a base, for do extendes, e estiver concretizada, não preciso de a redefinir void calcula2() //os métodos das outras classes de que esta deriva ou que desagua class ParquimetroCoimbra extends Parquimetro implements RegistaVisita { public ParquimetroCoimbra() { super("Coimbra"); } void calcula() { } public void registaVisita() { } public void receber() { } public void darTroco() { } } //public class main class main { public static void main(String[] args) { } }
assunto: equals, arrays
pergunta: qual o output do seguinte:
package recursopa2; import java.util.ArrayList; import java.util.List; class A { int n; A(int nn) { n = nn; } //não tem uma redefinição do equals //tem apenas a do object } class B extends A { B(int nn) { super(nn); } public boolean equals(B obj) { return true; } //"trocar", e podem coexistir // public boolean equals(Object obj) { // return true; // } } class main { static public void main(String[] args) { A r1 = new A(10); A r2 = new A(10); A r3 = new B(10); A r4 = new B(10); System.out.println("r1.equals(r2) " + r1.equals(r2)); //a classA não tem o seu equals, herda do object //assim os objectos estão em diferentes endereços //saida: false System.out.println("r3.equals(r4) " + r3.equals(r4)); //a classeB tem um equals //r3 equals r4, r3 chama a equals através de uma referência de r3 para A //vai chamar a equals que A conhece, e A que a conhece é da object //e em A não existe uma redefinição da equals //saida: false //mas para ser true era "trocar" //r3 invoca a função equals que conhece //que é o equals da object //mas o polimorfismo como aponta para o objecto do tipo B //e assim sendo vai buscar a versão da b "trocar" List<B> list = new ArrayList<B>(); B b1 = new B(4); B b2 = new B(4); list.add(b1); list.add(b2); System.out.println("list contem new B(4)? " + list.contains(new B(4))); //o contains no array, vai pegar no objecto e vai fazer o equals //com os que já lá estão, e o array lista usa apenas a equals do object //que compara referências, e por esse motivo diz que não está lá //saida: false } }
assunto: excepções
pergunta: qual o output do seguinte:
package recursopa2; class EstaExcepcao extends Exception { } class main { static void f() throws EstaExcepcao { try { System.out.println("Ponto 1"); throw new EstaExcepcao(); //saida: ponto 1 //System.out.println("AAAAA"); //se existir dá erro //depois do lançamento da excepção dá sempre erro } catch (EstaExcepcao e) { System.out.println("Ponto 2"); //saida: ponto 2 throw e; //vai ser relançada } finally { System.out.println("Ponto 3"); //saida: ponto 3 } //System.out.println("BBBB"); //se existice //como houve erro nunca iria ser executada, por exemplo //não havendo o throw } public static void main(String[] args) { try { f(); // f() sai em erro, vai fazer o catch System.out.println("Ponto 4"); } catch (EstaExcepcao e) { System.out.println("Ponto 5"); //saida: ponto 5 } catch (Exception e) { System.out.println("Ponto 6"); } System.out.println("Ponto 7"); //saida: ponto 5 } }
Java, exercício de análise
assunto: excepções
pergunta: qual o output do seguinte:
package recursopa2; class InteiroSomaRaizesQ { static private double somaRaizesQuadradas = 0; private double n; public InteiroSomaRaizesQ(String n) throws Exception { try { try { this.n = Double.parseDouble(n); //Double.parseDouble, se for bem formado do tipo 4.0 } catch (NumberFormatException e) { //NumberFormatException, como é o caso de A.0 return; } if (this.n < 0) { throw new Exception(); } somaRaizesQuadradas += Math.sqrt(this.n); } finally { System.out.print("f1 "); //acontece sempre quer o if corra bem quer corra mal } } public static void main2(String[] args) { System.out.print("m1 "); //saida: m1 try { new InteiroSomaRaizesQ("4.0"); //somaRaizesQuadradas = 2 //saida: f1, correu bem passa ao seguinte new InteiroSomaRaizesQ("A.0"); //saida: f1, termina em paz new InteiroSomaRaizesQ("9.0"); //somaRaizesQuadradas = 2+3 //saida: f1, correu bem passa ao seguinte new InteiroSomaRaizesQ("-4.0"); //acontece throw new Exception(); //saida: f1, mas correu mal, //não faço mais nada no try new InteiroSomaRaizesQ("9"); } catch (Exception e) { System.out.print("e1 "); //saida: e1 return; } finally { System.out.print("f2: " + somaRaizesQuadradas); //saida: f2 //saida: 5 } } } //para testar public class main { public static void main(String[] args) { InteiroSomaRaizesQ.main2(args); } }
Java, exercício de análise
assunto: máquina de estados, padrão comando
ou
pergunta: qual o output do seguinte:
package recursopa2; class Semaforo { static final int TEMPO_VERDE = 4, TEMPO_VERMELHO = 4, TEMPO_AMARELO = 1; private int tempo; private String estado; private String estadoAoLigar; public Semaforo() { tempo = 0; estado = "desligado"; estadoAoLigar = "vermelho"; } public void passaTempo() { if (estado.equalsIgnoreCase("desligado")) { return; //se for igual a desligado, não faz nada } tempo--; //se for diferente a desligado if (tempo > 0) { return; //se fo tempo for positivo, não faz mais nada } //se for == 0, então.. if (estado.equalsIgnoreCase("vermelho")) { estado = "verde"; tempo = TEMPO_VERDE; } else if (estado.equalsIgnoreCase("verde")) { estado = "amarelo"; tempo = TEMPO_AMARELO; } else if (estado.equalsIgnoreCase("amarelo")) { estado = "vermelho"; tempo = TEMPO_VERMELHO; } } public void desliga(String ligarEm) { if (estado.equalsIgnoreCase("desligado")) { return; } //se estiver ligado, então.. estadoAoLigar = ligarEm; estado = "desligado"; tempo = 0; } public void liga() { if (!estado.equalsIgnoreCase("desligado")) { return; } //se estiver desligado, então.. estado = estadoAoLigar; if (estado.equalsIgnoreCase("vermelho")) { tempo = TEMPO_VERMELHO; } else if (estado.equalsIgnoreCase("verde")) { tempo = TEMPO_VERDE; } else if (estado.equalsIgnoreCase("amarelo")) { tempo = TEMPO_AMARELO; } } public String toString() { return estado + " " + tempo; } } //para testar public class main { public static void main(String[] args) { Semaforo s = new Semaforo(); s.desliga("ligado"); s.liga(); s.passaTempo(); System.out.println(s.toString()); } }
perguntas, parte I:
____ É suficiente definir três classes concretas e tipo(s) base destas classes (classe e/ou interface)
resposta: não, temos quatro estados
____ É suficiente definir quatro classes concretas sem qualquer característica em comum
resposta: não, são derivadas na mesma base
____ Conceitos como “Vermelho” ou “Verde” representam métodos
resposta: não, são classes
____ Conceitos como “PassaTempo”, “Liga” ou “Desliga” representam métodos
resposta: sim
____ Todas as classes que representam os estados dispõem de implementações (vazias ou não) de todos os métodos que representam as acções a que o semáforo tem que responder
resposta: ou seja em todos os estados temos implementações vazias ou não, de liga ou desliga, sim verdadese não temos o que interessa, temos estão o return this (o vazio)
____ Três é o número mais adequado de métodos declarados na classe abstracta de base ou na interface comum
resposta: verdade, são três
____ As implementações dos métodos definidos na classe abstracta de base ou na interface comum podem modificar os dados e/ou devolver uma referência para o objecto que representa o estado actual
resposta: é verdade. “podem modificar os dados, e não retornam o estado em que ficamos”
____ Apenas um dos métodos (representando uma transição na máquina de estados) declarados na classe abstracta de base ou na interface comum necessita de receber um argumento
resposta: é verdade, que é o String ligarEm
perguntas, parte II:
Conceitos como “PassaTempo”, “Liga” ou “Desliga” representam ____________________ (métodos/classes)
resposta: na máquina de estados eram métodos, no padrão comando são classes
arranjam-se objectos que embrulham estas acções (classes que representam comandos simples, para haver uma evolução), logo elas vão ser classes
As classes que representam os comandos concretos implementam um interface ou derivam de uma mesma classe abstracta. Indique os métodos desse tipo base abstracto ____________________________________
resposta: os métodos são o execute (executar) e o undo (refazer)
O membro “estadoAoLigar” da classe Semaforo da listagem anterior deveria ser membro de que classe da hierarquia de comandos.
resposta: no comando correspondente ao desligar
O argumento “ligaEm” da classe Semaforo da listagem E deveria ser membro da classe ____________ da hierarquia de comandos.
resposta: “ligaEm” vai ser gravado na classe desliga
quando queremos por em padrão comando um método que leva argumentos, esses argumentos também são passados ao construtor do comando e são membros do objeto comando, e ficam lá gravados dentro
“os argumentos com que as funções são chamadas, quando embrulhamos a função com um comando, esses argumentos ficam gravados na classe que representa aquela acção, que representa aquele comando”
perguntas, parte III:
a classe semáforo deve implementar a interface PropertyChangeListener
resposta: não, pois a classe semáforo é a nossa lógica/dados. Os observadores (objectos da vista) que estão do lado da vista é que implementam o PropertyChangeListener
a classe semáforo deve ser derivada de PropertyChangeSupport ou referida por uma classe derivada de PropertyChangeSupport
resposta: verdade, a classe semáforo vai ser derivada de PropertyChangeSupport
o objecto painel desenho pode ser uma instância de uma classe derivada de PropertyChangeSupport
resposta: não, o painel de desenho não tem nenhum membro de PropertyChangeSupport, ele regista-se como observador, ele tem um observador lá dentro
o objecto painelDesenho pode ser instância de uma classe que não implementa a interface PropertyChangeListener, desde que tenha definida o método propertyChange
resposta: se ele tem um método propertyChange e não tem registo como observador, então não recebe ordens de actualização
o local mais apropriado para colocar código que trata da representação gráfica do semáforo é um método designado propertyChange
resposta: sim, os objetos gráficos são actualizados no propertyChange
o objecto painelDesenho, se tiver uma referência para a classe que deriva de PropertyChangeSupport (modelo), já não precisa de se registar como listener modelo.addProppertyChangeListener(this))
resposta: falso, pode ter uma referência, mas se não tiver um registo como listener/observador, não sabe se existem actualizações, quando os dados se alterarem
a classe que deriva PropertyChangeSupport (a classe observável) deve ter métodos, como passaTempo e desliga, que permitem alterar a informação encapsulada pelo modelo. Nestes métodos, é necessário chamar o método firePropertyChange antes de fazer as alterações ao semáforo
resposta: falso, o firePropertyChange é chamado depois. primeiro mudamos os dados, depois o firePropertyChange vai mandar os observadores fazer a actualização da vista
Java, várias coisas
ArrayList
Um objecto do tipo ArrayList
A seguinte instrução cria um ArrayList vazio de elementos do tipo Produto:
List
Alguns métodos:
public boolean add(E e) acrescenta o elemento e ao fim da lista.
public E remove(int index) remove o elemento da posição index, ajustando os índices seguintes; retorna o elemento removido.
public boolean remove(Object o) remove a primeira ocorrência de o, se existir, ou seja remove o elemento com menor índice tal que (o==null ? get(i)==null : o.equals(get(i))) (se esse elemento existir); retorna true se o elemento foi encontrado e eliminado.
public void clear() remove todos os elementos da lista.
public int size() retorna o numero de elementos da lista.
public int indexOf(Object o) retorna o índica da primeira ocorrência de o na lista, ou -1 se não existir.he element, ou seja, retorna o elemento com menor índice tal que (o==null ? get(i)==null : o.equals(get(i))) ou -1 se este índice não existir.
public E get(int index) retorna o elemento da lista na posição índex.
Percorrer um ArrayList:
for( int i = 0 ; i < produtos.size(); i++){ // … produtos.get(i) } for(Produto produto: produtos){ // … produto; }
Interface Iterator
Um iterator é um objecto que lhe permite percorrer uma colecção. As colecções têm um método:
Iterator
Que retorna um iterator para a colecção que o invoca.
public interface Iterator<E> { boolean hasNext(); // retorna true se existem mais elementos E next(); // retorna o próximo elemento da colecção void remove(); }
Interface Set
Um set é uma colecção que não pode ter elementos repetidos. Uma das implementações do interface Set é HashSet.
A seguinte instrução cria um HashSet vazio de elementos do tipo Entidade:
Set< Entidade > c = new HashSet< Entidade >();
Percorrer uma colecção com iterator: Iterator
while (it.hasNext()){ // … it.next(); } }
Para verificar se um determinado objecto pertence a um HashSet, é calculado o hashCode do objecto. O objecto é comparado com equals() só com os elementos do HashSet que têm o mesmo hashCode do objecto que está a ser pesquisado.
O objecto é considerado como pertencente ao HashSet se tiver o mesmo hashCode de um elemento e se também em relação a esse elemento a comparação com equals() der verdadeira.
Os objectos que se colocam num HashSet devem dispor de funções equals() e hashCode() devidamente definidas (se x.equals(y) for true, então x.hashCode() == y.hashCode()).
Ao adicionar um elemento a um HashSet, esta operação só tem sucesso (retornando true e adicionando de facto) se o novo elemento não pertencer ainda ao HashSet.
Interface Map
Um objecto do tipo Map representa uma correspondência chave-valor. Não pode haver chaves repetidas.
public interface Map<K,V> { V put(K key, V value); // insere a correspondência de (key, value) V get(Object key); // retorna o valor associado a key V remove(Object key); // remove a associação cuja chave é key boolean containsKey(Object key); // contém uma associação com chave key boolean containsValue(Object value); // contém uma associação com valor value int size(); boolean isEmpty(); // estar vazio void clear(); // remove todas as associações public Set<K> keySet(); // conjunto das chaves public Collection<V> values(); // colecção dos valores }
Uma das implementações do interface Map é HashMap.
A seguinte instrução cria um HashMap vazio de elementos do tipo Entidade:
Map
Percorrer um map:
Set<String> chaves = map.keySet(); Iterator<String> iter = chaves.iterator(); while (iter.hasNext()) { String key = iter.next(); str += " \n" + map.get(key); }
Interfaces Comparable e Comparator
Implementando o interface Comparable a classe define uma ordem natural entre os seus elementos.
public abstract class Cartao implements Comparable<Cartao>{ protected List<Chamada> chamadas = new ArrayList<Chamada>(); private int numero; private double saldo; // … public int compareTo(Cartao o) { return numero - o.getNumero(); } // … } public class Telefonica { private String nome; private Map<Integer, Cartao> cartoes = new HashMap<Integer, Cartao>(); // … public String toStringPorNumero(){ List<Cartao> listaOrdenada = new ArrayList<Cartao>(cartoes.values()); //Faz a cópia Collections.sort(listaOrdenada); return "Operadora de telemoveis ***" + nome + "***\n" + "Lista ordenada por numero:\n" + listaOrdenada; } // … }
O interface Comparator permite ordenar a mesma colecção segundo diversos critérios.
É preciso definir um objecto do tipo Comparator, neste caso, um objecto da classe OrdenaPorSaldo que vai ser o segundo argumento da função: Collections.sort(listaOrdenada, new OrdenaPorSaldo());
public class Telefonica { private String nome; private Map<Integer, Cartao> cartoes = new HashMap<Integer, Cartao>(); // … class OrdenaPorSaldo implements Comparator<Cartao> { public int compare(Cartao o1, Cartao o2) { if (o1.getSaldo() < o2.getSaldo()) return -1; else if (o1.getSaldo() > o2.getSaldo()) return 1; else return 0; } } public String toStringPorSaldo(){ List<Cartao> listaOrdenada = new ArrayList<Cartao>(cartoes.values()); //Faz a cópia Collections.sort(listaOrdenada, new OrdenaPorSaldo()); return "Operadora de telemoveis ***" + nome + "***\n" + "Lista ordenada por saldo:\n" + listaOrdenada; } // … }
JavaFX, exercício 3.1
package recursopa; import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; import recursopa.iu.gui.PaneOrganizer; public class RecursoPA extends Application { public static void main(String[] args) { //passamos os argumentos para o subsistema gráfico os parametros launch(args); } @Override //quando começa a aplicação public void start(Stage stage) throws Exception{ PaneOrganizer po = new PaneOrganizer(); Scene scene = new Scene(po,600,400); stage.setScene(scene); //aplica a cena no stage stage.setTitle("Exercicio de programação avançada"); stage.setMinHeight(300.0); stage.setMinWidth(300.0); stage.show(); } }
package recursopa.iu.gui; import javafx.event.EventHandler; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import recursopa.logica.Desenho; import recursopa.logica.Figura; public class AreaDesenho extends Canvas { Desenho desenho; public AreaDesenho(Desenho desenho) { super(100.0, 100.0); this.desenho = desenho; } public void registaListeners() { //detectar as ações do rato this.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { desenho.iniciaFigura((int) t.getX(), (int) t.getY(), (int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256) ); atualiza(); } }); //usando lambda functions this.setOnMouseReleased((t) -> { desenho.atualizaFigura((int) t.getX(), (int) t.getY()); atualiza(); }); this.setOnMouseDragged((t) -> { desenho.finalizaFigura((int) t.getX(), (int) t.getY()); atualiza(); }); } void apagarCanvas(GraphicsContext gc) { gc.setFill(Color.rgb(233, 233, 0)); gc.fillRect(0, 0, getWidth(), getHeight()); } //para desenhar as figuras void atualiza() { //obter as ferramentas de desenho GraphicsContext gc = getGraphicsContext2D(); apagarCanvas(gc); //rir buscar todas as figuras for (Figura fig : desenho.getListaFiguras()) { //fazer as operações sobre o GraphicsContext Color cor = Color.rgb(fig.getR(), fig.getG(), fig.getB()); gc.setFill(cor); gc.fillOval(fig.getXi(), fig.getYi(), fig.getLargura(), fig.getAltura()); } //desenhar a figura actual Figura figura = desenho.getActual(); if (figura != null){ Color cor = Color.rgb(figura.getR(), figura.getG(), figura.getB()); gc.setFill(cor); gc.fillOval(figura.getXi(), figura.getYi(), figura.getLargura(), figura.getAltura()); } } public void setDim(int w, int h) { setWidth(w); setHeight(h); atualiza(); } }
package recursopa.iu.gui; import javafx.scene.layout.Pane; import recursopa.logica.Desenho; public class PaneOrganizer extends Pane { //vai extender sempre um dos containers possiveis, extends Pane Desenho desenho; //Canvas canvas; //é uma zona de desenho AreaDesenho areaDesenho; public PaneOrganizer() { desenho = new Desenho(); criaLayout(); //para criar os componentes que vão surgir no ecrã registaListeners(); // registar os comportamentos dos objectos } void criaLayout() { //adicionar o elemento ao Pane areaDesenho = new AreaDesenho(desenho); this.getChildren().add(areaDesenho); } private void registaListeners() { areaDesenho.registaListeners(); this.widthProperty().addListener((e) -> { areaDesenho.setDim((int)PaneOrganizer.this.getWidth(), (int)PaneOrganizer.this.getHeight()); }); this.heightProperty().addListener((e) -> { areaDesenho.setDim((int)PaneOrganizer.this.getWidth(), (int)PaneOrganizer.this.getHeight()); }); } }
package recursopa.logica; import java.util.ArrayList; import java.util.List; public class Desenho { //para um conjunto de figuras, que ser´auma lista de figuras List<Figura> listaDeFiguras; Figura figuraAtual; public Desenho() { listaDeFiguras = new ArrayList<>(); } public void iniciaFigura(int x, int y, int r, int g, int b) { figuraAtual = new Figura(); figuraAtual.setRGB(r, g, b); figuraAtual.setPrimeiroPonto(x, y); figuraAtual.setSegundoPonto(x, y); } public void atualizaFigura(int x, int y) { if (figuraAtual != null) { figuraAtual.setSegundoPonto(x, y); //atualizar o segundo ponto } } public void finalizaFigura(int x, int y) { //para terminar a figura if(figuraAtual != null && listaDeFiguras !=null){ listaDeFiguras.add(figuraAtual); figuraAtual = null; } } public Figura getActual(){ return figuraAtual; } public List<Figura> getListaFiguras(){ return listaDeFiguras; } }
package recursopa.logica; public class Figura { //métodos necessários para gerir a figura int xi, yi, xf, yf; //posicao e tamanho int r, g, b; //para a cor public Figura() { } public int getXi() { return xi < xf ? xi : xf; } public int getYi() { return yi < yf ? yi : yf; } public int getXf() { return xf < xi ? xf : xi; } public int getYf() { return yf < yi ? yf : yi; } public int getR() { return r; } public int getG() { return g; } public int getB() { return b; } public void setRGB(int r, int g, int b) { this.r = r; this.g = g; this.b = b; } public void setPrimeiroPonto(int x, int y) { this.xi = x; this.yi = y; } public void setSegundoPonto(int x, int y) { this.xf = x; this.yf = y; } public int getLargura() { return Math.abs(xf - xi); //não interessa a ordem dos valores } public int getAltura() { return Math.abs(yf - yi); //não interessa a ordem dos valores } }
Java, exercício de análise
assunto: arraylist, equals
pergunta: qual o output do seguinte:
package recursopa2; import java.util.ArrayList; import java.util.List; class Inteiro { private int i; public Inteiro(int i) { this.i = i; } public void setVal(int i) { this.i = i; } public int getVal() { return i; } public String toString() { return "" + i; } //extra public boolean equals(Object ob) { if (ob == null) { return false; } if (getClass() != ob.getClass()) { return false; } //se chego aqui já posso comparar o i //return (i==ob.i); //dá erro, porque ob não conhece i, então Inteiro a = (Inteiro) ob; //fazemos um cast return (i == a.i); } //e desta forma o System.out.println(i.equals(j)); //dá true } class main { public static void main(String[] args) { List<Inteiro> listaInteiros = new ArrayList<>(); //criado um arraylist de listaInteiros Inteiro i = new Inteiro(10); Inteiro j = new Inteiro(10); System.out.println(i == j); //saida: falso //porque estão em referências diferentes System.out.println(i.equals(j)); //saida: falso //o equals faz a comparação que nos programamos lá dentro //por exemplo comparar conteudos //mas o equals não foi definido, e não dá erro porque //está a usar a do object, class Inteiro extends object //e a equals no object considera dois objetos iguais //se tiverem o mesmo endereço listaInteiros.add(i); listaInteiros.add(j); j = i; //j refere o i j.setVal(2); //o primeiro elemento do array list fica 2 System.out.println(i); //saida: 2 System.out.println(j); //saida: 2 System.out.println(listaInteiros.get(0)); //saida: 2 System.out.println(listaInteiros.get(1)); //saida: 10 } }
Java, exercício análise
assunto: excepções
pergunta: qual o output do seguinte:
package recursopa2; class UmaExcepcao extends Exception { //foi definida uma excepção } class Conta { int c = 4; void f(int i) throws UmaExcepcao { if (i < c) { System.out.print(" f1"); f(++i); return; } else try { System.out.print(" f2"); if (i == c) { throw new UmaExcepcao(); } } finally { System.out.print(" f3"); } System.out.print(" f4"); } public static void main2(String[] args) { Conta c1 = new Conta(); Conta c2 = new Conta(); //não existe nenhum construtor try { c1.f(3); // saida: System.out.print(" f1"); // saida: System.out.print(" f2"); // i == c, true // lança uma excepção, throw new UmaExcepcao(); // saida: faz sempre o finally, System.out.print(" f3"); // e terminou em estado de excepção e não faz o f4, System.out.print(" m1"); c2.f(4); System.out.print(" m2"); } catch (UmaExcepcao ex1) { System.out.print(" m3"); // saida: System.out.print(" m3"); // porque apanhou uma excepção try { c1.f(5); // saida: System.out.print(" f2"); // i == c, falso // saida: System.out.print(" f3"); // saida: System.out.print(" f4"); // porque não tinha excepção } catch (UmaExcepcao ex2) { System.out.print(" m4"); } } System.out.print(" m5"); // saida: System.out.print(" m5"); // porque não tinha excepção } } //para testar public class main { public static void main(String[] args) { Conta.main2(args); } }
assunto: excepções
pergunta: qual o output do seguinte:
package recursopa2; class EstaExcepcao extends Exception { } class main { static void f() throws EstaExcepcao { try { System.out.println("Ponto 1"); throw new EstaExcepcao(); //saida: ponto 1 //System.out.println("AAAAA"); //se existir dá erro //depois do lançamento da excepção dá sempre erro } catch (EstaExcepcao e) { System.out.println("Ponto 2"); //saida: ponto 2 throw e; //vai ser relançada } finally { System.out.println("Ponto 3"); //saida: ponto 3 } //System.out.println("BBBB"); //se existice //como houve erro nunca iria ser executada, por exemplo //não havendo o throw } public static void main(String[] args) { try { f(); // f() sai em erro, vai fazer o catch System.out.println("Ponto 4"); } catch (EstaExcepcao e) { System.out.println("Ponto 5"); //saida: ponto 5 } catch (Exception e) { System.out.println("Ponto 6"); } System.out.println("Ponto 7"); //saida: ponto 5 } }
Java, exercício de análise
assunto: map, hashmap
Pergunta:
Pretende-se um programa destinado a modelizar um conjunto de pássaros, especificamente canários e periquitos. Em termos de funcionalidades requeridas, apenas se pretende inserir novas instâncias de pássaros e manter um mapeamento entre os tipos e as respectivas quantidades. Sendo assim, complete o código da Listagem C de modo a que o resultado da sua execução seja: {Piriquito=10, Canario=10}. A classe Passaro encontra-se declarada como abstracta de modo a não poder ser instanciada, não sendo necessário alterá-la. As classes Periquito e Canario requerem a redefinição dos seguintes métodos: String toString(), boolean equals(Object o) e int hashCode().
A interface Map, sendo K o tipo da chave e V o tipo do valor associado, inclui, entre outros, os métodos V put(K k, V v) e V get(Object k). Ambos devolvem o valor associado à chave k fornecida, antes de substituir o valor já existente pelo novo valor v fornecido no caso do put, ou null caso esta não seja encontrada.
package recursopa2; import java.util.HashMap; import java.util.Map; abstract class Passaro { public static String PASSARO = "Passaro"; public static String PERIQUITO = "Periquito"; public static String CANARIO = "Canario"; //fabrica de objectos public static Passaro criaPassaro(String tipoPassaro) { if (tipoPassaro.equalsIgnoreCase(PERIQUITO)) { return new Periquito(); } else if (tipoPassaro.equalsIgnoreCase(CANARIO)) { return new Canario(); } else { return null; } } } class Periquito extends Passaro { public String toString() { return "Periquito"; } public boolean equals(Object ob) { //return ob instanceof Periquito; //ou em alternativa return getClass() == ob.getClass(); } public int hashCode() { return PERIQUITO.hashCode(); } } class Canario extends Passaro { public String toString() { return "Canario"; } public boolean equals(Object ob) { return ob instanceof Canario; } public int hashCode() { return CANARIO.hashCode(); } } class MainPassaro { public static void adicionaPassaro(Passaro p, Map<Passaro, Integer> gaiola) { if (gaiola == null || p == null) { return; } Integer quantidade = gaiola.get(p); //se não tive cananrio, a quantidade vem null //se já tiver algum, a quantidade vair ser >0 if (quantidade == null) { gaiola.put(p, 1); //acrescentamos um elemento novo } else { gaiola.put(p, quantidade + 1); //adiciono um novo, com um update quantidade } } public static void main2(String args[]) { //Map</*..f..*/> gaiola = new HashMap<>(); //resolução: Map<Passaro, Integer> gaiola = new HashMap<>(); Passaro p; for (int i = 0; i < 10; i++) { adicionaPassaro(Passaro.criaPassaro(Passaro.PERIQUITO), gaiola); adicionaPassaro(Passaro.criaPassaro(Passaro.CANARIO), gaiola); } System.out.println(gaiola); } } ////para testar public class main { public static void main(String[] args) { MainPassaro.main2(args); } }Tags : java, Programação avançada
Java, exercício de análise
assunto: array
pergunta: qual o output do seguinte:
package recursopa2; class Conta { public static int sn = 0; public Conta() { ++sn; } } public class main { public static void main(String[] args) { System.out.print(Conta.sn + " "); //saida: 0 Conta[] a = new Conta[4]; //com o new Conta[4] é um array de 4 referências nulas para Conta //não existe ainda nenhum objecto, não existe nenhum construtor System.out.print(Conta.sn + " "); //saida: 0 for (int i = 0; i < a.length; i++) { a[i] = new Conta(); //aqui já estamos a criar } System.out.println(Conta.sn); //saida: 4 } }
exercício javaFx
Tópicos: máquina de estados, interface gráfica, threads,
o diagrama da máquina de estados:
o projeto:
o código:
package jfxsomajogo; import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.stage.WindowEvent; import jfxsomajogo.modelo.SomaJogoObs; import jfxsomajogo.ui.SomaUI; public class JFXSomaJogo extends Application { public static void main(String[] args) { launch(args);; } @Override public void start(Stage primaryStage){ primaryStage.setTitle("Acereta nos números"); SomaJogoObs a = new SomaJogoObs(); SomaUI ui = new SomaUI(a); Scene scene = new Scene(ui, 300,250); primaryStage.setScene(scene); primaryStage.show(); //que serve para fechar a janela primaryStage.setOnHidden((WindowEvent event) -> { a.paraRelogio(); }); } }
package jfxsomajogo.fsm; import jfxsomajogo.integracao.EstadoID; import jfxsomajogo.modelo.SomaDados; public class AguardaNomeJogador extends SomaFSMAdapter { public AguardaNomeJogador(SomaDados dados) { super(dados); } //transição @Override public ISomaFSM defineJogador(String nome) { dados.defineNomeJogador(nome); if (dados.jogadorValido()) { dados.reset(); //iniciação do jogo return new AguardaResposta(dados); //novo estado }else{ return this; } } //cada um retorna o seu próprio identicador //para evitar o uso do instanceof e o get class @Override public EstadoID obtemEstadoID() { return EstadoID.AGUARDA_NOME; } }
package jfxsomajogo.fsm; import jfxsomajogo.integracao.EstadoID; import jfxsomajogo.modelo.SomaDados; public class AguardaReinicio extends SomaFSMAdapter { public AguardaReinicio(SomaDados dados) { super(dados); } //este estado é basicamente, um "press any key to conitnue" @Override public ISomaFSM recomeca() { return new AguardaNomeJogador(dados); } @Override public EstadoID obtemEstadoID() { return EstadoID.AGUARDA_REINICIO; } }
package jfxsomajogo.fsm; import jfxsomajogo.integracao.EstadoID; import jfxsomajogo.modelo.SomaDados; public class AguardaResposta extends SomaFSMAdapter{ AguardaResposta(SomaDados dados) { super(dados); } @Override public ISomaFSM tentaResposta(int n) { dados.tentaResposta(n); if(dados.excedeuErros()){ return new AguardaReinicio(dados); //muda de estado }else{ return this; //fica no mesmo estado //return new AguardaResposta(dados); //alternativa, mostramos evolução do estado } } @Override public ISomaFSM relogioAvanca() { dados.diminuiCountDown(); if(dados.excedeuErros()){ return new AguardaReinicio(dados); }else{ return this; } } @Override public EstadoID obtemEstadoID(){ return EstadoID.AGUARDA_RESPOSTA; //para evitar o instance of } }
package jfxsomajogo.fsm; import java.io.Serializable; import jfxsomajogo.integracao.EstadoID; public interface ISomaFSM extends Serializable{ //vai servir para definir um estado, transições: default ISomaFSM defineJogador(String nome){return this;} //implementação default, pode ser no Adpater default ISomaFSM tentaResposta(int n){return this;} default ISomaFSM recomeca(){return this;} default ISomaFSM relogioAvanca(){return this;} EstadoID obtemEstadoID(); //retorna um ID //default, permite a implementação default mas devia ser no adaptar e não aqui. //mudar no final para ver como fica }
package jfxsomajogo.fsm; import jfxsomajogo.modelo.SomaDados; public abstract class SomaFSMAdapter implements ISomaFSM{ //guarda a referencia para o modelo de dados protected final SomaDados dados; //protected para os outros estados poderem aceder à informação protected SomaFSMAdapter(SomaDados dados){ this.dados = dados; } //public AdividnhaDados obtemDados(){return dados;} //usa-se protected para isto //implementações de default de cada um dos métodos de }
package jfxsomajogo.integracao; //isto é um package que vai ser usado pelo modelo de dados e pela interface import jfxsomajogo.fsm.AguardaReinicio; public enum EstadoID { //os ID dos estados AGUARDA_NOME, AGUARDA_RESPOSTA, AGUARDA_REINICIO } //este package agrupa as enumerações e constantes relacioandos com //integração entre vários módulos da aplicação //assim, a UD nao tem que improtar coisas dos packages de dados ou FSM
package jfxsomajogo.integracao; //isto é um package que vai ser usado pelo modelo de dados e pela interface public enum MsgCode { START, RIGHT, WRONG, TIMEOUT }
package jfxsomajogo.integracao; //isto é um package que vai ser usado pelo modelo de dados e pela interface public enum PropsID { //podiam ser usadas constantes //"" -> alteração gráfica PROP_ESTADO("prop_estado"), PROP_DESAFIO("prop_desafio"), PROP_RELOGIO("prop_relogio"); String valor; private PropsID(String v) { this.valor = v; } @Override public String toString() { return valor; } }
package jfxsomajogo.modelo; import java.io.Serializable; import java.util.Random; import jfxsomajogo.integracao.MsgCode; public class SomaDados implements Serializable { private static final int COUNTDOWN_TIMEOUT = 10; private static final int MAX_ERROS = 3; private static final int MIN_VALOR = 1; private static final int MAX_VALOR = 100; private String jogador = "X"; private MsgCode msg; //ver o estado actual private int pontuacao, erros; private int numA, numB; private int countdown; Random rand; SomaDados() { rand = new Random(); jogador = "X"; msg = MsgCode.START; pontuacao = erros = numA = numB = -1; countdown = -1; } public final void reset() { pontuacao = 0; erros = 0; novoDesafio(); msg = MsgCode.START; } public void defineNomeJogador(String nome) { jogador = nome; } public void novoDesafio() { numA = rand.nextInt(MAX_VALOR - MIN_VALOR + 1) + MIN_VALOR; numB = rand.nextInt(MAX_VALOR - MIN_VALOR + 1) + MIN_VALOR; resetCountDown(); } public void diminuiCountDown() { --countdown; if (countdown <= 0) { msg = MsgCode.TIMEOUT; erros++; novoDesafio(); } } public void tentaResposta(int resp) { if (resp == (numA + numB)) { pontuacao++; msg = MsgCode.RIGHT; novoDesafio(); } else { erros++; msg = MsgCode.WRONG; } } //para ver a evolução dos estados public boolean jogadorValido() { //se indicar o nome, pode ir para jogar return jogador != null && jogador.length() > 0; } public boolean excedeuErros() { return erros >= MAX_ERROS; } //obtem info para o ecrã public String obtemNomeJogador() { return jogador; } public int obtemNumA() { return numA; } public int obtemNumB() { return numB; } public int obtemPontuacao() { return pontuacao; } public int obtemErros() { return erros; } public int obtemCountDown() { return countdown; } public MsgCode obtemMsg() { return msg; } private void resetCountDown() { countdown = COUNTDOWN_TIMEOUT; } }
package jfxsomajogo.modelo; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import jfxsomajogo.fsm.AguardaNomeJogador; import jfxsomajogo.fsm.ISomaFSM; import jfxsomajogo.integracao.EstadoID; import jfxsomajogo.integracao.MsgCode; import jfxsomajogo.integracao.PropsID; //esta é a classe "contexto" da máquina de estados //tem a máquina de estados + dados //máquina de estados public class SomaJogo implements Serializable { private final SomaDados dados = new SomaDados(); //criar o modelo de dados private ISomaFSM estado = null; //define o estado incial public SomaJogo() { estado = new AguardaNomeJogador(dados); } //defineEstado recebe o próximoe stado private Set<PropsID> defineEstado(ISomaFSM prox, PropsID... eventosBase) { //isto vai ajudar no observable, vai avisar a vista Set<PropsID> eventos = new HashSet<>(Set.of(eventosBase)); ISomaFSM anterior = estado; estado = prox; if (anterior != prox) { eventos.add(PropsID.PROP_ESTADO); } return eventos; } //operação do sistema ("dispositivo") contexto da FSM //-> reencaminha para FSM //os métodos que permitem a transição de estados //ponte entre o estado, o modelo de estados e a vista public Set<PropsID> defineJogador(String nome) { //ao inves de retornar o estado pode ser um return de boolean //retornar Set<PropsID>, um conjunto de situações de jogo que ajuda na vista do jogo //para a parte gráfica return defineEstado(estado.defineJogador(nome)); } public Set<PropsID> tentaResposta(int n) { return defineEstado(estado.tentaResposta(n), PropsID.PROP_DESAFIO); //estas duas significa que podem acontecer dois eventos, e disparar o fire de uma das duas } public Set<PropsID> recomeca() { return defineEstado(estado.recomeca()); } public Set<PropsID> relogioAvanca() { return defineEstado(estado.relogioAvanca(), PropsID.PROP_RELOGIO, PropsID.PROP_DESAFIO); } public EstadoID obtemEstadoID() { return estado.obtemEstadoID(); } //obtenção de dados para uso nas UI //informação relevanta para mostrar ao utilizador //-> reencaminha para dados //isto é o mesmo que os gets apenas traudizdo para obtem //para serem mostrados no UI do utilziador public String obtemNomeJogador() { return dados.obtemNomeJogador(); } public int obtemNumA() { return dados.obtemNumA(); } public int obtemNumB() { return dados.obtemNumB(); } public int obtemPontuacao() { return dados.obtemPontuacao(); } public int obtemErros() { return dados.obtemErros(); } public MsgCode obtemMsg() { return dados.obtemMsg(); } public int obtemCountDown() { return dados.obtemCountDown(); } //não devemos retornar o modelo SomaDados todo //porque se o fizermos vamos dar hipotese a quem faz //a vista de alterar os dados }
package jfxsomajogo.modelo; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import jfxsomajogo.integracao.EstadoID; import jfxsomajogo.integracao.MsgCode; import jfxsomajogo.integracao.PropsID; //missao principal - adicionar o suporte para ligacao a vistas // = property change support //mantem a ligacao separada do contexto da FGSM e dados //permite save/load a FSM+dados sem dependencia (referencia) a vistas //adiciona save/load neste nivel e age sobre o modelo (contexto da FSM) public class SomaJogoObs { //os propertir change support SomaJogo jogo = null; //a referencia para o jogo, maquina de estados private PropertyChangeSupport props = null; private final Timer relogio; private final Temporizador segundos; public SomaJogoObs() { jogo = new SomaJogo(); props = new PropertyChangeSupport(jogo); relogio = new Timer(); segundos = new Temporizador(); relogio.schedule(segundos, 0, 1000); } //registar o interesse das vistas, quando uma determinada propriedade for alterada // public void registaPropertyChangeListener(PropsID prop, PropertyChangeListener listener) { props.addPropertyChangeListener(prop.toString(), listener); } private void disparaEventos(Set<PropsID> eventos) { for (var e : eventos) { props.firePropertyChange(e.toString(), null, null); } //alternaiva ao for //eventos.forEach((e) -> { //props.firePropertyChange(e.toString(), null, null); //}); } public void paraRelogio() { segundos.cancel(); relogio.purge(); //eliminar todas as as timer text relogio.cancel(); } // inicio: métodos que fazem a ponte entre as vistas e a maquina de estados public void relogioAvanca() { disparaEventos(jogo.relogioAvanca()); } // operação do sistema ("dispotivo") - reencaminha para jogo depois p/ FSM public void defineJogador(String nome) { disparaEventos(jogo.defineJogador(nome)); } public void tentaResposta(int n) { disparaEventos(jogo.tentaResposta(n)); //alternaiva ao udo do disparaEventos //jogo.tentaResposta(n); //props.firePropertyChange(PropsID.PROP_DESAFIO, null. null); //props.firePropertyChange(PropsID.PROP_ESTADO, null. null); } public void recomeca() { disparaEventos(jogo.recomeca()); } public EstadoID obtemEstadoID() { return jogo.obtemEstadoID(); } //fim: métodos que fazem a ponte entre as vistas e a maquina de estados //obenção de dados para uso das UI - reencaminha p/jogo (depois para dados) public String obtemNomeJogador() { return jogo.obtemNomeJogador(); } public int obtemNumA() { return jogo.obtemNumA(); } public int obtemNumB() { return jogo.obtemNumB(); } public int obtemPontuacao() { return jogo.obtemPontuacao(); } public int obtemErros() { return jogo.obtemErros(); } public MsgCode obtemMSG() { return jogo.obtemMsg(); } public int obtemCountDown() { return jogo.obtemCountDown(); } //load/save public void saveGame(String filename) { ObjectOutputStream out; try { out = new ObjectOutputStream(new FileOutputStream(filename)); out.writeObject(jogo); out.close(); } catch (IOException e) { Logger.getLogger(SomaJogoObs.class.getName()).log(Level.SEVERE, null, e); } } public void loadGame(String filename) { ObjectInputStream in; try { in = new ObjectInputStream(new FileInputStream(filename)); jogo = (SomaJogo) in.readObject(); in.close(); props.firePropertyChange(PropsID.PROP_ESTADO.toString(), null, null); } catch (IOException | ClassNotFoundException e) { Logger.getLogger(SomaJogoObs.class.getName()).log(Level.SEVERE, null, e); } } //time taks class Temporizador extends TimerTask { @Override public void run() { relogioAvanca(); } } }
package jfxsomajogo.ui; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.HashMap; import java.util.Map; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; import jfxsomajogo.integracao.EstadoID; import jfxsomajogo.integracao.MsgCode; import jfxsomajogo.integracao.PropsID; import jfxsomajogo.modelo.SomaJogoObs; //esta é uma classe genérica, que é um adpater para PropertyChangeListener //PropertyChangeListenerJFXAdapter faz com que seja implementado o PropertyChangeListener //vai implementar o propertyChange, que é o método obrigatório pelo inteface método PropertyChangeListener //e sempre que ele for chamado, e antes de correr o código pretendido ele faz um // Platform.runLater(() do método onChange(evt); // e quanto ele for corrido ele já foi corrido no contexto do .runLater(() //com o objecto qd é criado é abstracto //por exemplo propsID.PROP_ESTADO, new PropertyChangeListenerJFXAdapter() //sou obrigado a implementar o onChange(), com todo o código necessário //para as alterações que eu necessito //e assim o onChange() já foi executado na thread do javaFX //evito assim que estoire, e que acontece quanto tentamos executar código a partir de uma thread //difernte da que está responsavel por fazer a gestão dos componentes gráficos //isto por causa da utilização do timer, porque o timer está numa thread à parte abstract class PropertyChangeListenerJFXAdapter implements PropertyChangeListener{ @Override public final void propertyChange(PropertyChangeEvent evt){ Platform.runLater(()->{ onChange(evt); }); } abstract public void onChange(PropertyChangeEvent evt); } public class SomaUI extends BorderPane { SomaJogoObs adivObs; public SomaUI(SomaJogoObs a) { adivObs = a; FileChooser fileChooser = new FileChooser(); //esta funcao esta extensa. passar código para funcções auxiliares //implica passar as refs locais dos componentes para a classe //cria componentes //menu MenuBar menuBar = new MenuBar(); Menu fileMenu = new Menu("file"); MenuItem fileNew = new MenuItem("new"); MenuItem fileSave = new MenuItem("save"); MenuItem fileLoad = new MenuItem("load"); MenuItem fileExit = new MenuItem("exit"); fileMenu.getItems().addAll(fileNew, fileSave, fileLoad, fileExit); Menu aboutMenu = new Menu("about"); MenuItem aboutInfo = new MenuItem("info"); aboutMenu.getItems().addAll(aboutInfo); menuBar.getMenus().addAll(fileMenu, aboutMenu); setTop(menuBar); //eventos para os menus //file->new fileNew.setOnAction((ActionEvent e) -> { adivObs.recomeca(); }); //file-> save fileSave.setOnAction((ActionEvent e) -> { File f = fileChooser.showSaveDialog(getScene().getWindow()); if (f != null) { adivObs.saveGame(f.getAbsolutePath()); } }); //file -> load fileLoad.setOnAction((ActionEvent e) -> { File f = fileChooser.showSaveDialog(getScene().getWindow()); if (f != null) { adivObs.loadGame(f.getAbsolutePath()); } }); //file -> exit fileExit.setOnAction((ActionEvent e) -> { encerra(); ((Stage) getScene().getWindow()).close(); //Platform.exit(); //funciona apenas em windows }); //about aboutInfo.setOnAction((ActionEvent e) -> { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("acerca disto"); alert.getDialogPane().setContentText("programa de javafx"); alert.showAndWait(); }); StackPane areaUtil = new StackPane(); areaUtil.setPadding(new Insets(10)); UINome uinome = new UINome(); //é um pane UIJoga uijoga = new UIJoga(); //é um pane UIFim uifim = new UIFim(); uijoga.setVisible(false); uifim.setVisible(false); areaUtil.getChildren().addAll(uinome, uijoga, uifim); setCenter(areaUtil); } public void encerra() { adivObs.paraRelogio(); } class UINome extends VBox { private final Label lNome = new Label("escreve nome"); private final TextField tfNome = new TextField(); private final Button btnDefineNome = new Button("ok"); public UINome() { super(10); //espaçamento entre items adivObs.registaPropertyChangeListener(PropsID.PROP_ESTADO, new PropertyChangeListenerJFXAdapter() { //registaPropertyChangeListener para sermos avisados de evolução de estados @Override public void onChange(PropertyChangeEvent evt) { setVisible(adivObs.obtemEstadoID() == EstadoID.AGUARDA_NOME); } }); btnDefineNome.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent t) { adivObs.defineJogador(tfNome.getText()); } }); tfNome.setOnKeyPressed(e -> { if (e.getCode() == KeyCode.ENTER) { adivObs.defineJogador(tfNome.getText()); } }); getChildren().addAll(lNome, tfNome, btnDefineNome); } } class UIJoga extends VBox { private final Label lMsg = new Label(); private final Label lDesafio = new Label(); private final TextField tfResposta = new TextField(); private final Button btnEnviaResposta = new Button("ok"); private final Label lRelogio = new Label(); Map<MsgCode, String> mensagens = new HashMap<>(); public UIJoga() { //1,39 super(10); //espaçamento entre items mensagens.put(MsgCode.START, "vamos começar"); mensagens.put(MsgCode.RIGHT, "certo. outro desafio"); mensagens.put(MsgCode.WRONG, "errado. tenta outra vez"); mensagens.put(MsgCode.TIMEOUT, "tempo excedido. outro desafio"); btnEnviaResposta.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent t) { tentaResposta(); } }); tfResposta.setOnKeyPressed(e -> { if (e.getCode() == KeyCode.ENTER) { tentaResposta(); } }); adivObs.registaPropertyChangeListener(PropsID.PROP_ESTADO, new PropertyChangeListenerJFXAdapter() { //registaPropertyChangeListener para sermos avisados de evolução de estados @Override public void onChange(PropertyChangeEvent evt) { if (adivObs.obtemEstadoID() == EstadoID.AGUARDA_RESPOSTA) { setVisible(true); defineMensagens(); //atualziar todas as labels com o texto em causa intiTfResposta(); //por o texto a vazio (escrita do texto), quando existe mudança de estado } else { setVisible(false); } } }); adivObs.registaPropertyChangeListener(PropsID.PROP_DESAFIO, new PropertyChangeListenerJFXAdapter() { //registaPropertyChangeListener para sermos avisados de evolução de estados @Override public void onChange(PropertyChangeEvent evt) { defineMensagens(); } }); adivObs.registaPropertyChangeListener(PropsID.PROP_RELOGIO, new PropertyChangeListenerJFXAdapter() { //registaPropertyChangeListener para sermos avisados de evolução de estados @Override public void onChange(PropertyChangeEvent evt) { //para processamento futuro caso necessário } }); getChildren().addAll(lMsg, lDesafio, tfResposta, btnEnviaResposta, lRelogio); defineMensagens(); } private void defineMensagens() { lMsg.setText(mensagens.getOrDefault(adivObs.obtemMSG(), "nao compreendo..")); //adivObs.obtemMSG() com ajuda de um switch case para obter as mensagens (string) acerca do estado //em que se encontra //a alternativa foi a opção de se usar um Map<MsgCode, String> mensagens lDesafio.setText(adivObs.obtemNomeJogador() + " ,quando é " + adivObs.obtemNumA() + " + " + adivObs.obtemNumB() + "?" ); lRelogio.setText("tempo restante: " + adivObs.obtemCountDown()); } private void intiTfResposta() { //serve para apagar a resposta que é escrita //e só acontece quando existe mudança de estado tfResposta.setText(""); tfResposta.requestFocus(); } private void tentaResposta() { try { int val = Integer.parseInt(tfResposta.getText()); adivObs.tentaResposta(val); intiTfResposta(); } catch (NumberFormatException e) { } } } class UIFim extends VBox { private final Label lResultado = new Label(); private final Button btnRecomecar = new Button("Novo jogo"); public UIFim() { super(5); adivObs.registaPropertyChangeListener(PropsID.PROP_ESTADO, new PropertyChangeListenerJFXAdapter() { @Override public void onChange(PropertyChangeEvent evt) { if (adivObs.obtemEstadoID() == EstadoID.AGUARDA_REINICIO) { setVisible(true); lResultado.setText(adivObs.obtemNomeJogador() + ", o teu resultado:\n" + "pontuação: " + adivObs.obtemPontuacao() + "\n" + "Erros:" + +adivObs.obtemErros() + "(obviamente)\n\n" + "ok para jogar outra vez\n\n" ); //formatação com \n em ambiente grafico - tem tudo a ver } else { setVisible(false); } } }); btnRecomecar.setOnAction((ActionEvent e) -> { adivObs.recomeca(); } ); getChildren().addAll(lResultado, btnRecomecar); } } }
JavaFX, exercício 3
package recursopa; import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; import recursopa.iu.gui.PaneOrganizer; public class RecursoPA extends Application { public static void main(String[] args) { //passamos os argumentos para o subsistema gráfico os parametros launch(args); } @Override //quando começa a aplicação public void start(Stage stage) throws Exception{ PaneOrganizer po = new PaneOrganizer(); Scene scene = new Scene(po,600,400); stage.setScene(scene); //aplica a cena no stage stage.setTitle("Exercicio de programação avançada"); stage.setMinHeight(300.0); stage.setMinWidth(300.0); stage.show(); } }
package recursopa.iu.gui; import javafx.event.EventHandler; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Ellipse; import recursopa.logica.Figura; public class PaneOrganizer extends Pane { //vai extender sempre um dos containers possiveis, extends Pane Figura fig; Ellipse elipse; public PaneOrganizer() { fig = new Figura(); fig.setPrimeiroPonto(0, 0); fig.setSegundoPonto(100, 50); fig.setRGB(0, 50, 0); criaLayout(); //para criar os componentes que vão surgir no ecrã registaListeners(); // registar os comportamentos dos objectos atualizaElipse(); } void criaLayout() { //adicionar o elemento ao Pane elipse = new Ellipse(); this.getChildren().add(elipse); } public void registaListeners() { //detectar as ações do rato this.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { fig.setPrimeiroPonto((int) t.getX(), (int) t.getY()); fig.setSegundoPonto((int) t.getX(), (int) t.getY()); fig.setRGB((int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256)); atualizaElipse(); } }); //usando lambda functions this.setOnMouseReleased((t) -> { fig.setSegundoPonto((int) t.getX(), (int) t.getY()); atualizaElipse(); }); this.setOnMouseDragged((t) -> { fig.setSegundoPonto((int) t.getX(), (int) t.getY()); atualizaElipse(); }); } //para desenhar a elipse void atualizaElipse() { //elipse.setFill(Color.GREEN); elipse.setFill(Color.rgb(fig.getR(), fig.getG(), fig.getB())); //para ir buscar as informações à fig //elipse.setCenterX(200.0); elipse.setCenterX((fig.getXi() + fig.getXf()) / 2); //elipse.setCenterY(200.0); elipse.setCenterY((fig.getYi() + fig.getYf()) / 2); //elipse.setRadiusX(150.0); elipse.setRadiusX(fig.getLargura() / 2); //elipse.setRadiusY(100.0); elipse.setRadiusY(fig.getAltura() / 2); } }
package recursopa.logica; public class Figura { //métodos necessários para gerir a figura int xi, yi, xf, yf; //posicao e tamanho int r, g, b; //para a cor public Figura() { } public int getXi() { return xi; } public int getYi() { return yi; } public int getXf() { return xf; } public int getYf() { return yf; } public int getR() { return r; } public int getG() { return g; } public int getB() { return b; } public void setRGB(int r, int g, int b) { this.r = r; this.g = g; this.b = b; } public void setPrimeiroPonto(int x, int y) { this.xi = x; this.yi = y; } public void setSegundoPonto(int x, int y) { this.xf = x; this.yf = y; } public int getLargura() { return Math.abs(xf - xi); //não interessa a ordem dos valores } public int getAltura() { return Math.abs(yf - yi); //não interessa a ordem dos valores } }
JavaFX, exercícios
Relembrar para o netBeans correr um projeto com JavaFX e nas propriedades de um projeto:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class RecursoPA extends Application { public static void main(String[] args) { //passamos os argumentos para o subsistema gráfico os parametros launch(args); } @Override //quando começa a aplicação public void start(Stage stage) throws Exception{ BorderPane bp = new BorderPane(); Label label1 = new Label("programação avançada"); Label label2 = new Label("outra label"); bp.setBottom(label1); bp.setTop(label2); //criar a cena Scene scene = new Scene(bp,400,400); //raiz da cena, e dimensões //adicionar a cena ao palco stage.setScene(scene); stage.show(); } }
Programação avançada – capitulo 8 – maquina de estados, exemplo3 (revisitado)
Revisitar o exercício acerca do uso de maquina de estados com a implementação de um jogo de 3×3, onde existem dois jogadores.
A máquina de estados:
é um padrão de programação;
serve para abordar problemas mais complexos;
vai ajudar no fluxo na evolução das aplicações (redirecciona para o estado que vai fazer um determinado processamento);
permite identificar os momentos importantes, na evolução da aplicação/jogo;
Definição dos estados:
está relacionada com a interacção do utilizador;
existem transições entre os estados;
as transições de entrada (métodos) e podem/devem ser condicionados pelo estado do jogo;
as transições de saída (métodos) e podem/devem ser condicionados pelo estado do jogo;
existem então acções do utilizador sobre o jogo, e estas acções resultam em métodos, para haver evolução no jogo;
(identificar as etapas do jogo, que vão ser implementadas, para resolver mini problemas, sub dividir para se simplificar o código que é implementado);
Os estados, são assim:
são representados através de classes;
existe uma classe base, da qual os estados vão derivar (polimorfismo), normalmente do IEstado (através do implements);
e devem ser implementados todos os métodos abstractos que estão definidos no IEstado (usando return para o new “estado”) ou então fica nele próprio (return this).
(2)O IEstado, serve então:
é uma interface, dos estados (e não uma classe);
serve para representar/declarar o que existe, acções possíveis e comuns em todos os estados (através de métodos);
esses métodos são do tipo da interface IEstado;
mas atenção que podem existir algumas acções que podem não ser usadas/implementadas em todos os estados (fica o return this, nas bases), mas têm que ser aqui colocadas, construindo implementações default;
assim sendo os IEstado representam as evoluções (transições) do nosso modelo.
(3)O EstadoAdapter, serve então para:
é uma classe intermédia/genérica que vai implementar os comportamentos default, sem qualquer actualização de estado, para evitar a programação destas acções em estados onde não fazem sentido (normalmente ficam no mesmo estado).
só depois e em cada um dos estados é que os vamos implementar, pois só se justifica no contexto desse estado haver uma evolução na maquina de estados, e é em cada um desses estados que fica implementado
esta classe implementa o IEstado (implements)
implementa todos os métodos abstractos / default (return this), isto é, não existe evolução de estado/fica no mesmo estado.
surge aqui também os testes da evolução, assim estes estados vão ter que ter acesso aos dados do jogo (JogoDados), construtor e get e set
esta classe deve ser public abstract, para não ser instanciada,
e o JogoDados fica protected, evitando fazer uso do método getJogo, e pelas derivadas acedo a esta instância
(4)E agora construir os estados, que são classes derivadas e:
são extends EstadoAdapter
por ser protected a base, esta derivada tem que ter o construtor correspondente (super)
implementar os métodos correspondentes às acções que fazem sentido, são as setas de saída;
os outros não fazem sentido num estado, ficam com o default do EstadoAdapter
os métodos implementados em cada um dos estados fazem então um return new estado, ou this se voltar ao mesmo, sendo que é implementada também a lógica de cada um dos métodos
Surge uma classe
surge então o inicio da máquina de estados, representando numa classe que inicia o primeiro estado por onde arranca (new..), e que vai permitir aceder (get) ou alterar o estado (set)
esta classe vai ter que satisfazer as ordens do utilizador, define os métodos que permitem alterar/mudança de estado (métodos de transição)
Na iteração com o utilizador (texto ou gráfica):
recebe a maquina de estados;
obtém permanente o estado em que se encontra a máquina de estados;
faz uso de instanceof dos estados para invocar a interface que deve surgir ao utilizador.
neste exemplo:
(1)o JogoMaqEstados, gestão/ver a evolução/mudança entre os estados (no diagrama ir de um estado para outro), conhece o estado atual, é a classe de interface entre o IU do utilizador e todas as classes internas (quer aquelas que representam os estados, quer os dados, que representam o jogo (tem assim informação sobre o jogo (JogoDados), e o estado em que estamos (IEstado));
o JogoMaqEstados tem ainda a interface para todos os outros estados, onde actualiza a situação do estado;
os estados, recebem a entidade jogo, como referência;
já a grelha, onde estão as peças, o jogador, este tipo de dados ficam em JogoDados;
JogoDados, representa assim o tabuleiro do jogo, onde se fazem todas as verificações;
Jogador, representada cada um dos jogos;
Peca, as peças do tabuleiro de jogo;
IEstado;
EstadoAdapter
(10) A interface (IU) também precisa de ir buscar coisas ao jogo, mas quem trata disso é o JogoMaqEstados
package me_jogopecasr; import me_jogopecasr.iu.texto.IUtexto; import me_jogopecasr.logica.JogoMaqEstados; public class Me_jogoPecasR { public static void main(String[] args) { IUtexto iuTexto = new IUtexto(new JogoMaqEstados()); iuTexto.corre(); } }
package me_jogopecasr.iu.texto; import java.util.Scanner; import me_jogopecasr.logica.JogoMaqEstados; import me_jogopecasr.logica.estados.AguardaColocacao; import me_jogopecasr.logica.estados.AguardaDevolucao; import me_jogopecasr.logica.estados.AguardaInicio; import me_jogopecasr.logica.estados.IEstado; public class IUtexto { private JogoMaqEstados jogo; private boolean sair = false; public IUtexto(JogoMaqEstados jogo) { this.jogo = jogo; } void iuAguardaInicio() { if ((jogo.getJogador1() != null && jogo.getJogador1().isGanhou())) { System.out.println("\n" + jogo.getJogador1() + "\n" + jogo.grelhaToString()); } else if (jogo.getJogador2() != null && jogo.getJogador2().isGanhou()) { System.out.println("\n" + jogo.getJogador2() + "\n" + jogo.grelhaToString()); } System.out.println("\n=== AGUARDA INICIO ===\n" + (jogo.getJogador1() != null ? "" + jogo.getJogador1() : "") + (jogo.getJogador2() != null ? "" + jogo.getJogador2() : "")); while (true) { System.out.println("\n0 - Sair\n1 - Define nome de jogador\n2 - Comecar jogo"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '0')) { sair = true; return; } if ((c == '1')) { //1 - Define nome de jogador System.out.println("Numero (1 ou 2) e nome do jogador: "); while (!sc.hasNextInt()); int num = sc.nextInt(); System.out.println(" numero: " + num); String nome = sc.next(); jogo.defineNomeJogador(num, nome); System.out.println(" nome: " + nome); return; } if ((c == '2')) { //2 - Comecar jogo System.out.println("Comecar jogo: "); jogo.comecarJogo(); return; } } } void iuAguardaColocacao() { System.out.println("\n=== AGUARDA COLOCACAO === \n" + jogo.getJogador1() + jogo.getJogador2() + "\nJogador activo: " + jogo.getNomeJogadorActivo() + "\n" + jogo.grelhaToString()); System.out.println("\n1 - Jogar : linha coluna\n2 - Abandonar"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '1')) { System.out.print(jogo.getNomeJogadorActivo() + ">"); while (!sc.hasNextInt()); int linha = sc.nextInt(); while (!sc.hasNextInt()); int coluna = sc.nextInt(); jogo.jogar(jogo.getNumJogadorActivo(), linha, coluna); } if ((c == '2')) { jogo.abandonar(jogo.getNumJogadorActivo()); return; } } void iuAguardaDevolucao() { System.out.println("\n=== AGUARDA DEVOLUCAO === \n" + jogo.getJogador1() + jogo.getJogador2() + "\nJogador activo: " + jogo.getNomeJogadorActivo() + "\n" + jogo.grelhaToString()); // System.out.println("\nDevolver : linha coluna\nAbandonar: -1"); System.out.println("\n1 - Devolver : linha coluna\n2 - Abandonar"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '1')) { System.out.print(jogo.getNomeJogadorActivo() + ">"); while (!sc.hasNextInt()); int linha = sc.nextInt(); while (!sc.hasNextInt()); int coluna = sc.nextInt(); jogo.devolver(jogo.getNumJogadorActivo(), linha, coluna); } if ((c == '2')) { jogo.abandonar(jogo.getNumJogadorActivo()); return; } } public void corre() { while (!sair) { IEstado estado = jogo.getEstado(); if (estado instanceof AguardaInicio) { iuAguardaInicio(); } else if (estado instanceof AguardaColocacao) { iuAguardaColocacao(); } else if (estado instanceof AguardaDevolucao) { iuAguardaDevolucao(); } } } }
package me_jogopecasr.logica; public interface Constantes { int DIM = 3; }
package me_jogopecasr.logica; import java.util.ArrayList; import java.util.List; public class Jogador implements Constantes { private JogoDados jogo; private String nome; private List<Peca> mao = new ArrayList<Peca>(); private boolean ganhou; public Jogador(String nome, JogoDados j) { this.nome = nome; this.jogo = j; ganhou = false; } public void setNome(String nome) { this.nome = nome; } public String getNome() { return nome; } public boolean isGanhou() { return ganhou; } public void setGanhou(boolean ganhou) { this.ganhou = ganhou; } public void recebePecas() { mao.clear(); for (int i = 0; i < DIM; i++) { mao.add(new Peca(this)); } ganhou = false; } public void recebePeca(Peca peca) { mao.add(peca); } public boolean temPecas() { return mao.size() > 0; } public boolean jogar(int linha, int coluna) { if (mao.size() == 0) { return false; } Peca peca = mao.get(0); if (jogo.setPeca(peca, linha, coluna)) { // jogou mao.remove(0); if (jogo.ganhou(this)) { ganhou = true; } return true; } return false; } @Override public String toString() { return "Jogador " + nome + " mao=" + mao + (ganhou ? " == GANHOU ==" : "") + "\n"; } public int getNumPecas() { return mao.size(); } }
package me_jogopecasr.logica; import java.util.ArrayList; import java.util.List; public class JogoDados implements Constantes{ private List<Jogador> jogadores = new ArrayList<Jogador>(); private int numJogActivo; private Peca[][] grelha; public JogoDados() { jogadores.add(new Jogador("A", this)); jogadores.add(new Jogador("B", this)); grelha = new Peca[DIM][DIM]; } public Jogador getJogadorActivo() { return jogadores.get(numJogActivo - 1); } public String getNomeJogadorActivo() { return jogadores.get(numJogActivo - 1).getNome(); } public Jogador getJogadorNaoActivo() { if (numJogActivo == 1) { return jogadores.get(1); } else if (numJogActivo == 2) { return jogadores.get(0); } return null; } public int getNumJogadorActivo() { return numJogActivo; } public int getNumJogadorNaoActivo() { return (numJogActivo == 1? 1: 2); } public Jogador getJogador1() { return jogadores.get(0); } public Jogador getJogador2() { return jogadores.get(1); } public Peca getPeca(int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return null; } if (grelha == null) { return null; } return grelha[linha][coluna]; } public boolean setPeca(Peca peca, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (grelha[linha][coluna] != null) { return false; } grelha[linha][coluna] = peca; return true; } public boolean retiraPeca(int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (grelha[linha][coluna] == null) { return false; } grelha[linha][coluna] = null; return true; } public void jogaOutro() { numJogActivo = numJogActivo == 1 ? 2 : 1; } public boolean inicializa() { grelha = new Peca[DIM][DIM]; jogadores.get(0).recebePecas(); jogadores.get(1).recebePecas(); numJogActivo = 1; return true; } public boolean setNomeJogador(int num, String nome) { try{ jogadores.get(num-1).setNome(nome); return true; }catch(IndexOutOfBoundsException e){ return false; } } private boolean isEmDiagonalPrincipal(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (grelha[i][i] == null || grelha[i][i].getJogador() != jogador) { return false; } } return true; } private boolean isEmDiagonalSecundaria(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (grelha[i][DIM - 1 - i] == null || grelha[i][DIM - 1 - i].getJogador() != jogador) { return false; } } return true; } private boolean isEmDiagonal(Jogador jogador) { return isEmDiagonalPrincipal(jogador) || isEmDiagonalSecundaria(jogador); } private boolean isEmHorizontal(Jogador jogador, int linha) { for (Peca peca : grelha[linha]) { if (peca == null || peca.getJogador() != jogador) { return false; } } return true; } private boolean isEmVertical(Jogador jogador, int coluna) { for (int i = 0; i < grelha[coluna].length; i++) { Peca peca = grelha[i][coluna]; if (peca == null || peca.getJogador() != jogador) { return false; } } return true; } private boolean isEmHorizontal(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (isEmHorizontal(jogador, i)) { return true; } } return false; } private boolean isEmVertical(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (isEmVertical(jogador, i)) { return true; } } return false; } public boolean ganhou(Jogador jogador) { return isEmHorizontal(jogador) || isEmDiagonal(jogador) || isEmVertical(jogador); } public boolean jogar(int numeroJogador, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if(numJogActivo != numeroJogador){ return false; } Jogador j = getJogadorActivo(); if(!j.jogar(linha, coluna)){ return false; } return true; } public boolean devolver(int numeroJogador, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if(numJogActivo != numeroJogador){ return false; } Peca peca = getPeca(linha, coluna); Jogador j = getJogadorActivo(); if (peca == null || peca.getJogador() != j) { return false; } if(!retiraPeca(linha, coluna)){ return false; } j.recebePeca(peca); return true; } public String grelhaToString() { String s = ""; for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { String casa; if (grelha[i][j] != null) { casa = "" + grelha[i][j].getJogador().getNome().charAt(0); } else { casa = " "; } s += "|\t" + casa + "\t"; } s += "|\n"; } return s; } public boolean acabou() { return ganhou(jogadores.get(0)) || ganhou(jogadores.get(1)); } }
package me_jogopecasr.logica; import me_jogopecasr.logica.estados.AguardaInicio; import me_jogopecasr.logica.estados.IEstado; public class JogoMaqEstados { JogoDados jogo; IEstado estado; public JogoMaqEstados() { //1) this.jogo = new JogoDados(); //7 this.estado = new AguardaInicio(jogo); } public JogoDados getJogo() { return jogo; } public void setJogo(JogoDados jogo) { this.jogo = jogo; } public IEstado getEstado() { return estado; } public void setEstado(IEstado estado) { this.estado = estado; } //8 redirecionar, agulhar, as acções para os estados, o interface para todas as outras classes public void defineNomeJogador(int numeroJogador, String nome) { //8.1 a evolução do estado, retorna o estado seguinte estado = estado.defineNomeJogador(numeroJogador, nome); //ou usar o setEstado } public void comecarJogo() { //no infitivo estado = estado.comecaJogo(); } public void jogar(int numeroJogador, int linha, int coluna) { estado = estado.joga(numeroJogador, linha, coluna); } public void devolver(int numeroJogador, int linha, int coluna) { estado = estado.devolve(numeroJogador, linha, coluna); } public void abandonar(int numeroJogador) { estado = estado.abandona(numeroJogador); } //9 redirencuionar para o modelo de dados public Jogador getJogador1() { return jogo.getJogador1(); } public Jogador getJogador2() { return jogo.getJogador2(); } //11 redirencuionar para o modelo de dados public String getNomeJogadorActivo() { return jogo.getNomeJogadorActivo(); } public String grelhaToString() { return jogo.grelhaToString(); } public int getNumJogadorActivo() { return jogo.getNumJogadorActivo(); } }
package me_jogopecasr.logica; public class Peca { private Jogador jogador; public Peca(Jogador jogador) { this.jogador = jogador; } public Jogador getJogador() { return jogador; } public String toString(){ return "" + jogador.getNome().charAt(0); } }
package me_jogopecasr.logica.estados; import me_jogopecasr.logica.JogoDados; //5 public class AguardaColocacao extends EstadoAdapter{ //6.2.3 ver se ele não colocou no mesmo local int l, c; //5.1 public AguardaColocacao(JogoDados jogo) { super(jogo); //6.2.5 l = c-1; } //6.2.4 public AguardaColocacao(JogoDados jogo, int l, int c) { super(jogo); this.l = l; this.c = c; } //5.2 @Override public IEstado abandona(int numeroJogador) { //poderia ver qual é o jogador e atribuir a vitória ao outro return new AguardaInicio(jogo); } //5.3 @Override public IEstado joga(int numeroJogador, int linha, int coluna) { //6.2.6, testar se é a mesma jogada if(linha == l && coluna == c){ return this; } //5.3.1, vamos realizar o jogar if(!jogo.jogar(numeroJogador, linha, coluna)){ return this; } //5.3.2, ver se ele ganhou if(jogo.getJogadorActivo().isGanhou()){ return new AguardaInicio(jogo); } //5.3.3, mudar de jogador jogo.jogaOutro(); //5.3.4, ver se tem peças if(jogo.getJogadorActivo().isGanhou()){ return new AguardaColocacao(jogo); //ou return this, fica no mesmo estado, e com l e c a -1 } //5.3.5, return new AguardaDevolucao(jogo); } }
package me_jogopecasr.logica.estados; import me_jogopecasr.logica.JogoDados; //6 public class AguardaDevolucao extends EstadoAdapter { public AguardaDevolucao(JogoDados jogo) { super(jogo); } //6.1 @Override public IEstado abandona(int numeroJogador) { return new AguardaInicio(jogo); } //6.2 @Override public IEstado devolve(int numeroJogador, int linha, int coluna) { //6.2.1 adcionar a devolção if(jogo.devolver(numeroJogador, linha, coluna)){ //o devolver já verifica return new AguardaColocacao(jogo, linha, coluna); //6.2.7 } //6.2.2 fica no mesmo estado return this; } }
package me_jogopecasr.logica.estados; import me_jogopecasr.logica.JogoDados; public class AguardaInicio extends EstadoAdapter{ //4) por ser protected a base, esta derivada tem que ter um construtor correspondente public AguardaInicio(JogoDados jogo) { super(jogo); } //4.2) implementar os métodos correspondentes às acções que fazem sentido, são as setas de saída @Override public IEstado defineNomeJogador(int numeroJogador, String nome) { //4.4 jogo.setNomeJogador(numeroJogador, nome); //4.3 return this; } @Override public IEstado comecaJogo() { //4.4 testes para começar um jogo if(jogo.getJogador1()== null || jogo.getJogador2() ==null){ //fico no mesmo estado return this; } //12 jogo.inicializa(); return new AguardaColocacao(jogo); } }
package me_jogopecasr.logica.estados; //3) existem acções que não fazem sent import me_jogopecasr.logica.JogoDados; public abstract class EstadoAdapter implements IEstado{ //3.2) acesso aos jogos de dados //3.3) protected, evitando fazer uso do método getJogo, e pelas derivadas acedo a esta instancia protected JogoDados jogo; public EstadoAdapter(JogoDados jogo) { this.jogo = jogo; } public JogoDados getJogo() { return jogo; } public void setJogo(JogoDados jogo) { this.jogo = jogo; } //3.1) @Override public IEstado defineNomeJogador(int numeroJogador, String nome) { return this; } @Override public IEstado comecaJogo() { return this; } @Override public IEstado joga(int numeroJogador, int linha, int coluna) { return this; } @Override public IEstado devolve(int numeroJogador, int linha, int coluna) { return this; } @Override public IEstado abandona(int numeroJogador) { return this; } }
package me_jogopecasr.logica.estados; //2) definir todos os estados public interface IEstado { IEstado defineNomeJogador(int numeroJogador, String nome); IEstado comecaJogo(); IEstado joga(int numeroJogador, int linha, int coluna); IEstado devolve(int numeroJogador, int linha, int coluna); IEstado abandona(int numeroJogador); }
JavaFX, exercício 2
package javafx03; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import javafx03.iu.gui.PaneOrganizer; public class Javafx03 extends Application { public static void main(String[] args) { //redirecionar a execução para o método launch launch(args); } @Override public void init() throws Exception { //inicar qualquer coisa antes do start System.out.println("init"); super.init(); } //méotod obrigatório abstract do Application @Override public void start(Stage stage) throws Exception { System.out.println("start"); //no palco vão ocorrer cenas PaneOrganizer po = new PaneOrganizer(); Scene cena = new Scene(po, 600, 400); stage.setScene(cena); stage.setTitle("programação avançada!"); stage.setMinWidth(300); stage.setMinHeight(200); stage.show(); } @Override public void stop() throws Exception { System.out.println("stop"); super.stop(); } }package javafx03.iu.gui; import javafx.event.EventHandler; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Ellipse; import javafx03.logica.Figura; //pane, usa o espaço todo disponivel public class PaneOrganizer extends Pane { //criar a figura Figura figura; Ellipse elipse; public PaneOrganizer() { this.figura = new Figura(); figura.setPrimeiroPonto(0, 0); figura.setSegundoPonto(100, 50); figura.setRGB(0, 255, 0); criarLayout(); registaListeners(); atualizaFigura(); } private void criarLayout() { //criar uma nova elipse /* elipse.setCenterX(200); elipse.setCenterY(100); elipse.setFill(Color.GREEN); elipse.setRadiusX(200); elipse.setRadiusY(100); */ //adicionar a elipse ao pane elipse = new Ellipse(); this.getChildren().add(elipse); } private void registaListeners() { //podia ser feito numa classe à parte this.setOnMousePressed(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent t) { figura.setPrimeiroPonto((int) t.getX(), (int) t.getY()); figura.setSegundoPonto((int) t.getX(), (int) t.getY()); figura.setRGB((int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256)); atualizaFigura(); } }); //com lambda this.setOnMouseDragged((t) -> { figura.setSegundoPonto((int) t.getX(), (int) t.getY()); atualizaFigura(); }); // this.setOnMouseReleased((t) -> { // figura.setSegundoPonto((int) t.getX(), (int) t.getY()); // atualizaFigura(); // }); } private void atualizaFigura() { elipse.setFill(Color.rgb(figura.getR(), figura.getG(), figura.getB())); elipse.setCenterX((figura.getXi() + figura.getXf()) / 2); elipse.setCenterY((figura.getYi() + figura.getYf()) / 2); elipse.setRadiusX(figura.getAltura() / 2); elipse.setRadiusY(figura.getLargura() / 2); } }package javafx03.logica; public class Figura { int xi, xf; int yi, yf; int r, g, b; public Figura() { } public int getXi() { return xi; } public int getXf() { return xf; } public int getYi() { return yi; } public int getYf() { return yf; } public int getR() { return r; } public int getG() { return g; } public int getB() { return b; } public void setRGB(int r, int g, int b) { this.r = r; this.g = g; this.b = b; } public void setPrimeiroPonto(int x, int y) { this.xi = x; this.yi = y; } public void setSegundoPonto(int x, int y) { this.xf = x; this.yf = y; } public int getLargura() { return Math.abs(xf - xi); } public int getAltura() { return Math.abs(xf - xi); } }Tags : javafx, Programação avançada
Programação avançada – capitulo 8 – maquina de estados, exemplo3
Exemplo de uma maquina de estado, usando como referência a implementação de um jogo de 3×3, onde existem dois jogadores.
O diagrama da maquina de estados dado:
Outra versão do diagrama da maquina de estados:
package me_jogopecas; import me_jogopecas.iu.texto.IUTexto; import me_jogopecas.logica.estados.JogoMaquinaEstados; public class Me_jogoPecas { public static void main(String[] args) { IUTexto iuTexto = new IUTexto(new JogoMaquinaEstados()); iuTexto.corre(); } }
package me_jogopecas.iu.texto; import java.util.Scanner; import me_jogopecas.logica.estados.*; public class IUTexto { private JogoMaquinaEstados jogo; private boolean sair = false; public IUTexto(JogoMaquinaEstados jogo) { this.jogo = jogo; } void iuAguardaInicio() { if ((jogo.getJogador1() != null && jogo.getJogador1().isGanhou())) { System.out.println("\n" + jogo.getJogador1() + "\n" + jogo.grelhaToString()); } else if (jogo.getJogador2() != null && jogo.getJogador2().isGanhou()) { System.out.println("\n" + jogo.getJogador2() + "\n" + jogo.grelhaToString()); } System.out.println("\n=== AGUARDA INICIO ===\n" + (jogo.getJogador1() != null ? "" + jogo.getJogador1() : "") + (jogo.getJogador2() != null ? "" + jogo.getJogador2() : "")); while (true) { System.out.println("\n0 - Sair\n1 - Define nome de jogador\n2 - Comecar jogo\n3 - Ler jogo"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '0')) { sair = true; return; } if ((c == '1')) { //1 - Define nome de jogador System.out.println("Numero (1 ou 2) e nome do jogador: "); while (!sc.hasNextInt()); int num = sc.nextInt(); System.out.println(" numero: " + num); String nome = sc.next(); jogo.defineNomeJogador(num, nome); System.out.println(" nome: " + nome); return; } if ((c == '2')) { //2 - Comecar jogo System.out.println("Comecar jogo: "); jogo.comecarJogo(); return; } if ((c == '3')) { //3 - Ler o jogo System.out.println("Ler o jogo: "); String ficheiroLer = sc.next(); // jogo.ler(ficheiroLer); return; } } } void iuAguardaColocacao() { System.out.println("\n=== AGUARDA COLOCACAO === \n" + jogo.getJogador1() + jogo.getJogador2() + "\nJogador activo: " + jogo.getNomeJogadorActivo() + "\n" + jogo.grelhaToString()); System.out.println("\n1 - Jogar : linha coluna\n2 - Abandonar"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '1')) { System.out.print(jogo.getNomeJogadorActivo() + ">"); while (!sc.hasNextInt()); int linha = sc.nextInt(); while (!sc.hasNextInt()); int coluna = sc.nextInt(); jogo.jogar(jogo.getNumJogadorActivo(), linha, coluna); } if ((c == '2')) { System.out.println("Guardar o jogo: "); String ficheiroGuardar = sc.next(); // jogo.grava(ficheiroGuardar); jogo.abandonar(jogo.getNumJogadorActivo()); return; } } void iuAguardaDevolucao() { System.out.println("\n=== AGUARDA DEVOLUCAO === \n" + jogo.getJogador1() + jogo.getJogador2() + "\nJogador activo: " + jogo.getNomeJogadorActivo() + "\n" + jogo.grelhaToString()); // System.out.println("\nDevolver : linha coluna\nAbandonar: -1"); System.out.println("\n1 - Devolver : linha coluna\n2 - Abandonar"); char c = ' '; Scanner sc = new Scanner(System.in); c = sc.next().charAt(0); if ((c == '1')) { System.out.print(jogo.getNomeJogadorActivo() + ">"); while (!sc.hasNextInt()); int linha = sc.nextInt(); while (!sc.hasNextInt()); int coluna = sc.nextInt(); jogo.devolver(jogo.getNumJogadorActivo(), linha, coluna); } if ((c == '2')) { jogo.abandonar(jogo.getNumJogadorActivo()); return; } } public void corre() { while (!sair) { IEstado estado = jogo.getEstado(); if (estado instanceof AguardaInicio) { iuAguardaInicio(); } else if (estado instanceof AguardaColocacao) { iuAguardaColocacao(); } else if (estado instanceof AguardaDevolucao) { iuAguardaDevolucao(); } } } }
package me_jogopecas.logica; public interface Constantes { int DIM =3; }
package me_jogopecas.logica; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import static me_jogopecas.logica.Constantes.*; public class Jogador implements Constantes, Serializable{ private String nome; private JogoDados jogo; //lista de peças no inicio private List<Peca> mao = new ArrayList<Peca>(); private boolean ganhou; public Jogador(String nome, JogoDados j) { this.nome = nome; this.jogo = j; ganhou = false; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public JogoDados getJogo() { return jogo; } public void setJogo(JogoDados jogo) { this.jogo = jogo; } public List<Peca> getMao() { return mao; } public void setMao(List<Peca> mao) { this.mao = mao; } public boolean isGanhou() { return ganhou; } public void setGanhou(boolean ganhou) { this.ganhou = ganhou; } //quando começar o jogo! public void recebePecas() { mao.clear(); for (int i = 0; i < DIM; i++) { mao.add(new Peca(this)); } ganhou = false; } public int getNumPecas(){ return mao.size(); } //quando a peça é devolvida public void recebePeca(Peca peca) { mao.add(new Peca(this)); } public boolean temPecas() { return mao.size() > 0; } public boolean jogar(int linha, int coluna){ if(mao.size()==0){ return false; } //as peças são todas iguais Peca peca = mao.get(0); if(jogo.setPeca(peca, linha, coluna)){ //jogou mao.remove(0); if(jogo.ganhou(this)){ ganhou = true; } return true; } return false; } @Override public String toString() { return "Jogador " + nome + " mao=" + mao + (ganhou ? " == GANHOU ==" : "") + "\n" ; } }
package me_jogopecas.logica; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class JogoDados implements Constantes, Serializable { private List<Jogador> jogadores = new ArrayList<Jogador>(); private int numJoActivo; private Peca[][] grelha; public JogoDados() { jogadores.add(new Jogador("A", this)); jogadores.add(new Jogador("B", this)); grelha = new Peca[DIM][DIM]; } public Jogador getJogadorActivo() { //considera-se que o jogador activo é 1 ou 2, daí o -1 return jogadores.get(numJoActivo - 1); } public String getNomeJogadorActivo() { return jogadores.get(numJoActivo - 1).getNome(); } public Jogador getJogadorNaoActivo() { if (numJoActivo == 1) { return jogadores.get(1); } else if (numJoActivo == 2) { return jogadores.get(0); } return null; } public int getNumJogadorActivo() { return numJoActivo; } public int getNumJogadorNaoActivo() { return (numJoActivo == 1 ? 1 : 2); } public Jogador getJogador1() { return jogadores.get(0); } public Jogador getJogador2() { return jogadores.get(1); } public Peca getPeca(int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return null; } if (grelha == null) { return null; } return grelha[linha][coluna]; } public boolean setPeca(Peca peca, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (grelha[linha][coluna] != null) { return false; } grelha[linha][coluna] = peca; return true; } public boolean retiraPeca(int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (grelha[linha][coluna] == null) { return false; } grelha[linha][coluna] = null; return true; } public void jogaOutro() { numJoActivo = numJoActivo == 1 ? 2 : 1; } public boolean inicializa() { grelha = new Peca[DIM][DIM]; jogadores.get(0).recebePecas(); jogadores.get(1).recebePecas(); numJoActivo = 1; return true; } public boolean setNomeJogador(int num, String nome) { //falta validar se o num é válido try { //tento aceder a um elemento do array que nao existe jogadores.get(num - 1).setNome(nome); return true; } catch (IndexOutOfBoundsException e) { return false; } } private boolean isEmDiagonalPrincipal(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (grelha[i][i] == null || grelha[i][i].getJogador() != jogador) { return false; } } return true; } private boolean isEmDiagonalSecundaria(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (grelha[i][DIM - 1 - i] == null || grelha[i][DIM - 1 - i].getJogador() != jogador) { return false; } } return true; } private boolean isEmDiagonal(Jogador jogador) { return isEmDiagonalPrincipal(jogador) || isEmDiagonalSecundaria(jogador); } private boolean isEmHorizontal(Jogador jogador, int linha) { for (Peca peca : grelha[linha]) { if (peca == null || peca.getJogador() != jogador) { return false; } } return true; } private boolean isEmVertical(Jogador jogador, int coluna) { for (int i = 0; i < grelha[coluna].length; i++) { Peca peca = grelha[i][coluna]; if (peca == null || peca.getJogador() != jogador) { return false; } } return true; } private boolean isEmHorizontal(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (isEmHorizontal(jogador, i)) { return true; } } return false; } private boolean isEmVertical(Jogador jogador) { for (int i = 0; i < DIM; i++) { if (isEmVertical(jogador, i)) { return true; } } return false; } public boolean ganhou(Jogador jogador) { return isEmHorizontal(jogador) || isEmDiagonal(jogador) || isEmVertical(jogador); } public boolean jogar(int numeroJogador, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (numJoActivo != numeroJogador) { return false; } Jogador j = getJogadorActivo(); if (!j.jogar(linha, coluna)) { return false; } return true; } public boolean devolver(int numeroJogador, int linha, int coluna) { if (linha < 0 || linha >= DIM || coluna < 0 || coluna >= DIM) { return false; } if (numJoActivo != numeroJogador) { return false; } Peca peca = getPeca(linha, coluna); Jogador j = getJogadorActivo(); if (peca == null || peca.getJogador() != j) { return false; } if (!retiraPeca(linha, coluna)) { return false; } j.recebePeca(peca); return true; } public String grelhaToString() { String s = ""; for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { String casa; if (grelha[i][j] != null) { casa = "" + grelha[i][j].getJogador().getNome().charAt(0); } else { casa = " "; } s += "|\t" + casa + "\t"; } s += "|\n"; } return s; } public boolean acabou() { return ganhou(jogadores.get(0)) || ganhou(jogadores.get(1)); } }
package me_jogopecas.logica; import java.io.Serializable; public class Peca implements Serializable { private Jogador jogador; public Peca(Jogador jgd) { this.jogador = jgd; } public Jogador getJogador() { return jogador; } public void setJogador(Jogador jogador) { this.jogador = jogador; } @Override public String toString() { return "" + jogador.getNome().charAt(0); } }
package me_jogopecas.logica.estados; import me_jogopecas.logica.JogoDados; public class AguardaColocacao extends EstadoAdapter { //para informação adicional int l, c; public AguardaColocacao(JogoDados jogodados) { super(jogodados); //para informação adicional l = c = -1; //se vier return this } //para informação adicional public AguardaColocacao(JogoDados jogo, int l, int c) { super(jogo); this.l = l; this.c = c; } //setas de saida @Override public IEstado abandona(int numeroJogador) { //podiamos atribuir a vitoria a um jogador, olhando para numeroJogador //voltamos ao inicio return new AguardaInicio(jogodados); } @Override public IEstado joga(int numeroJogador, int linha, int coluna) { //informação adicional if (linha == l && coluna == c) { return this; } //jogar normal, o jogar faz o teste se pode ou nao jogar jogodados.jogar(numeroJogador, linha, coluna); //verificar se o jogador activo if (jogodados.getJogadorActivo().isGanhou()) { return new AguardaInicio(jogodados); } jogodados.jogaOutro(); //jogar a um jogador que não tem peças //jogar que nao tem pecas if (jogodados.getJogadorActivo().temPecas()) { //return this; //tb funciona //para informação adicional return new AguardaColocacao(jogodados); } return new AguardaDevolucao(jogodados); } }
package me_jogopecas.logica.estados; import me_jogopecas.logica.JogoDados; public class AguardaDevolucao extends EstadoAdapter { public AguardaDevolucao(JogoDados jogodados) { super(jogodados); } @Override public IEstado abandona(int numeroJogador) { return new AguardaInicio(jogodados); } @Override public IEstado devolve(int numeroJogador, int linha, int coluna) { if (jogodados.devolver(numeroJogador, linha, coluna)) { //return new AguardaColocacao(jogodados); //informação adicional return new AguardaColocacao(jogodados, linha, coluna); } return this; } }
package me_jogopecas.logica.estados; import me_jogopecas.logica.JogoDados; public class AguardaInicio extends EstadoAdapter { //construtor que redireciona para a classe base public AguardaInicio(JogoDados jogodados) { super(jogodados); } //setas de saida, os outros não fazem sentido @Override public IEstado defineNomeJogador(int numeroJogador, String nome) { //qual o novo estado depois de defineNomeJogador //agora vou atuar sobre o jogo jogodados.setNomeJogador(numeroJogador, nome); return this; //fico no mesmo estado } @Override public IEstado comecaJogo() { //testes para verificar se já tinhamos os dois jogadores if(jogodados.getJogador1()==null || jogodados.getJogador2()==null){ return this; } jogodados.inicializa(); return new AguardaColocacao(jogodados); } }
package me_jogopecas.logica.estados; import java.io.Serializable; import me_jogopecas.logica.JogoDados; //abstract para nao ser instanciada public abstract class EstadoAdapter implements IEstado, Serializable{ JogoDados jogodados;//tem que ter acesso aos dados de jogo //podemos colocar como protected, para ser usado apenas nas classes derivadas public EstadoAdapter(JogoDados jogod) { this.jogodados = jogod; } public JogoDados getJogodados() { return jogodados; } public void setJogodados(JogoDados jogodados) { this.jogodados = jogodados; } @Override public IEstado defineNomeJogador(int numeroJogador, String nome) { return this; } @Override public IEstado comecaJogo() { return this; } @Override public IEstado joga(int numeroJogador, int linha, int coluna) { return this; } @Override public IEstado devolve(int numeroJogador, int linha, int coluna) { return this; } @Override public IEstado abandona(int numeroJogador) { return this; } //o interface precisa de ir buscar coisas para as mostrar }
package me_jogopecas.logica.estados; public interface IEstado { //definir todas as acções o jogo IEstado defineNomeJogador(int numeroJogador, String nome); IEstado comecaJogo(); IEstado joga(int numeroJogador, int linha, int coluna); IEstado devolve(int numeroJogador, int linha, int coluna); IEstado abandona(int numeroJogador); }
package me_jogopecas.logica.estados; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import me_jogopecas.logica.Jogador; import me_jogopecas.logica.JogoDados; public class JogoMaquinaEstados implements Serializable { //se JogoMaquinaEstados é Serializable as classes de base tb têm que ser JogoDados jogodados; IEstado estado; public JogoMaquinaEstados() { //criar o meu jogo this.jogodados = new JogoDados(); //desenvolver, evoluir, programação dos estados (do diagrama) this.estado = new AguardaInicio(jogodados); } public IEstado getEstado() { return estado; } public void setEstado(IEstado estado) { this.estado = estado; } //implementar todos os estados, através desta maquina de estados //interface de todas as classes public void defineNomeJogador(int numeroJogador, String nome) { //estado seguinte vai ser do retornar.. estado = estado.defineNomeJogador(numeroJogador, nome); } public void comecarJogo() { estado = estado.comecaJogo(); } public void jogar(int numeroJogador, int linha, int coluna) { estado = estado.joga(numeroJogador, linha, coluna); } public void devolver(int numeroJogador, int linha, int coluna) { estado = estado.devolve(numeroJogador, linha, coluna); } public void abandonar(int numeroJogador) { estado = estado.abandona(numeroJogador); } //os métodos que surgem no IUTexto public Jogador getJogador1() { return jogodados.getJogador1(); } public Jogador getJogador2() { return jogodados.getJogador2(); } public String getNomeJogadorActivo() { return jogodados.getNomeJogadorActivo(); } public int getNumJogadorActivo() { return jogodados.getNumJogadorActivo(); } public String grelhaToString() { return jogodados.grelhaToString(); } //ou em alternativa dava acesso ao jogodados public JogoDados getJogo() { return jogodados; } //gravação dos ficheiros public void grava(String filename) throws IOException { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream(filename)); oos.writeObject(this); } finally { if(oos != null) { oos.close(); } } } public static JogoMaquinaEstados ler(String filename) throws IOException, ClassNotFoundException { ObjectInputStream oos = null; try { oos = new ObjectInputStream(new FileInputStream(filename)); return (JogoMaquinaEstados) oos.readObject(); } finally { if(oos != null) { oos.close(); } } } }
Programação avançada – capitulo 8 – maquina de estados, exemplo2
Exemplo de uma maquina de estado, simples, usando as referências a um mecanismo de um elevador com dois estados extra: erro e chaveManutencao
Em que ficou:
Com:
package me_me_elevador; import me_me_elevador.IU.Texto.UsaElevador; import me_me_elevador.logica.Elevador; public class Me_ME_elevador { public static void main(String[] args) { Elevador e = new Elevador(); UsaElevador usaE = new UsaElevador(e); //interface com o utilizador usaE.corre(); } }
package me_me_elevador.IU.Texto; import me_me_elevador.logica.*; import me_me_elevador.util.IUUtil; public class UsaElevador { //o interface com o utilizador, com o nosso elevador. private Elevador elevador; private boolean sair = false; public UsaElevador(Elevador elevador) { this.elevador = elevador; } public void corre() { while (!sair) { //saber em que estado estou IEstado estado = elevador.getEstado(); if (estado instanceof RC) { iuRC(); } else if (estado instanceof Andar1) { iuAndar1(); } else if (estado instanceof Andar2) { iuAndar2(); } else if (estado instanceof Andar3) { iuAndar3(); }else if (estado instanceof Manutencao) { iuManutencao(); } } } private void iuManutencao() { int opcao = IUUtil.getOpcao("Em modo de manutenção", "Usar a chave", "Sair do elevador"); switch (opcao) { case 0: elevador.chaveManutencao(); case 1: sair = true; break; } } private void iuRC() { //opcoa 1 //pedir ao utilizador: sair ou subir int opcao = IUUtil.getOpcao("Piso R/C", "Sair do prédio", "Subir", "Erro"); switch (opcao) { case 0: sair = true; break; case 1: //fazer evoluir a maquina de estados elevador.sobe(); break; case 2: elevador.erro(); break; } } private void iuAndar1() { int opcao = IUUtil.getOpcao("Piso 1 andar", "Descer", "Subir", "Erro"); switch (opcao) { case 0: //fazer evoluir a maquina de estados elevador.desce(); break; case 1: //fazer evoluir a maquina de estados elevador.sobe(); break; case 2: elevador.erro(); break; } } private void iuAndar2() { int opcao = IUUtil.getOpcao("Piso 2 andar", "Descer", "Subir", "Erro"); switch (opcao) { case 0: //fazer evoluir a maquina de estados elevador.desce(); break; case 1: //fazer evoluir a maquina de estados elevador.sobe(); break; case 2: elevador.erro(); break; } } private void iuAndar3() { int opcao = IUUtil.getOpcao("Piso 3 andar", "Descer", "Erro"); switch (opcao) { case 0: //fazer evoluir a maquina de estados elevador.desce(); break; case 1: elevador.erro(); break; } } }
package me_me_elevador.logica; public class Andar1 extends Piso { @Override public IEstado sobe() { //altero de estado return new Andar2(); } @Override public IEstado desce() { //altero de estado return new RC(); } //se fossem todos iguais podia ser implementado no Piso // com return this; @Override public IEstado erro() { return new Manutencao(this); } }
package me_me_elevador.logica; public class Andar2 extends Piso{ @Override public IEstado sobe() { return new Andar3(); } @Override public IEstado desce() { return new Andar1(); } @Override public IEstado erro() { return new Manutencao(this); } }
package me_me_elevador.logica; public class Andar3 extends Piso{ @Override public IEstado sobe() { //fico no mesmo estado return this; } @Override public IEstado desce() { //altero de estado return new Andar2(); } @Override public IEstado erro() { return new Manutencao(this); } }
package me_me_elevador.logica; public class Elevador { IEstado estado; public Elevador() { estado = new RC(); } public IEstado getEstado() { return estado; } public void setEstado(IEstado estado) { this.estado = estado; } public void sobe() { setEstado(estado.sobe()); } public void desce() { setEstado(estado.desce()); } public void erro(){ setEstado(estado.erro()); } public void chaveManutencao(){ setEstado(estado.chaveManutencao()); } }
package me_me_elevador.logica; public interface IEstado { IEstado sobe(); IEstado desce(); IEstado erro(); IEstado chaveManutencao(); }
package me_me_elevador.logica; public class Manutencao extends Piso{ //vai recordar qual era o estado antes private IEstado anterior; public Manutencao(IEstado ant) { this.anterior = ant; } @Override public IEstado chaveManutencao() { return anterior; } }
package me_me_elevador.logica; public abstract class Piso implements IEstado { @Override public IEstado sobe() { return this; } @Override public IEstado desce() { return this; } @Override public IEstado chaveManutencao() { return this; } @Override public IEstado erro() { return this; } }
package me_me_elevador.logica; public class RC extends Piso { @Override public IEstado sobe() { //altero de estado return new Andar1(); } @Override public IEstado desce() { //fico no mesmo estado return this; } @Override public IEstado erro() { return new Manutencao(this); } }
package me_me_elevador.util; import java.util.Scanner; public class IUUtil { public static int getOpcao(String question, String... options) { System.out.println(question); char[] ops = new char[options.length]; for (int i = 0; i < options.length; i++) { char o = '\0'; int c = 0; while (c < options[i].length()) { o = Character.toUpperCase(options[i].charAt(c)); for (int j = 0; j < i; j++) { if (ops[j] == o) { o = '\0'; break; } } if (o != '\0') { break; } c++; } if (c >= options[i].length()) { return -1; } ops[i] = o; if (i > 0) { System.out.print(", "); } if (c > 0) { System.out.print(options[i].substring(0, c)); } System.out.print("(" + ops[i] + ")" + options[i].substring(c + 1)); } System.out.println(); Scanner sc = new Scanner(System.in); while (true) { System.out.print("Option: "); char o = Character.toUpperCase(sc.nextLine().charAt(0)); for (int i = 0; i < ops.length; i++) { if (o == ops[i]) { return i; } } } } }
O erro e a chaveEmergencia são acções, sendo que o evento que surge é a Manutenção.
Programação avançada – capitulo 8 – maquina de estados, exemplo1
Exemplo de uma maquina de estado, simples, usando as referências a um mecanismo de um elevador
Em que ficou:
Com:
package me_me_elevador; import me_me_elevador.IU.Texto.UsaElevador; import me_me_elevador.logica.Elevador; public class Me_ME_elevador { public static void main(String[] args) { Elevador e = new Elevador(); UsaElevador usaE = new UsaElevador(e); //interface com o utilizador usaE.corre(); } }
package me_me_elevador.IU.Texto; import me_me_elevador.logica.*; import me_me_elevador.util.IUUtil; public class UsaElevador { //o interface com o utilizador, com o nosso elevador. private Elevador elevador; private boolean sair = false; public UsaElevador(Elevador elevador) { this.elevador = elevador; } public void corre() { while (!sair) { //saber em que estado estou IEstado estado = elevador.getEstado(); if (estado instanceof RC) { iuRC(); } else if (estado instanceof Andar1) { iuAndar1(); } else if (estado instanceof Andar2) { iuAndar2(); } else if (estado instanceof Andar3) { iuAndar3(); } } } private void iuRC() { //opcoa 1 //pedir ao utilizador: sair ou subir int opcao = IUUtil.getOpcao("Piso R/C", "Ir embora", "Subir"); switch (opcao) { case 0: sair = true; break; case 1: //fazer evoluir a maquina de estados elevador.sobe(); break; } } private void iuAndar1() { int opcao = IUUtil.getOpcao("Piso 1 andar","Descer", "Subir"); switch (opcao) { case 0: //fazer evoluir a maquina de estados elevador.desce(); break; case 1: //fazer evoluir a maquina de estados elevador.sobe(); break; } } private void iuAndar2() { int opcao = IUUtil.getOpcao("Piso 2 andar","Descer", "Subir"); switch (opcao) { case 0: //fazer evoluir a maquina de estados elevador.desce(); break; case 1: //fazer evoluir a maquina de estados elevador.sobe(); break; } } private void iuAndar3() { int opcao = IUUtil.getOpcao("Piso 3 andar","Descer"); switch (opcao) { case 0: //fazer evoluir a maquina de estados elevador.desce(); break; } } }
package me_me_elevador.logica; public class Andar1 extends Piso{ @Override public IEstado sobe() { //altero de estado return new Andar2(); } @Override public IEstado desce() { //altero de estado return new RC(); } }
package me_me_elevador.logica; public class Andar2 extends Piso{ @Override public IEstado sobe() { return new Andar3(); } @Override public IEstado desce() { return new Andar1(); } }
package me_me_elevador.logica; public class Andar3 extends Piso{ @Override public IEstado sobe() { //fico no mesmo estado return this; } @Override public IEstado desce() { //altero de estado return new Andar2(); } }
package me_me_elevador.logica; public class Elevador { //é a maquina de estados, que faz alterar os estados IEstado estado; public Elevador() { //o estado incial//arranque é então: estado = new RC(); } public IEstado getEstado() { return estado; } public void setEstado(IEstado estado) { this.estado = estado; } //podia ter outras informações, como o numero de pessoas //as luzes que estão ou não ligadas.. //métodos que dão origem à mudança de estado public void sobe() { setEstado(estado.sobe()); //versão1 //this.estado = estado.sobe(); //versão2 } public void desce() { setEstado(estado.desce()); //versão1 //this.estado = estado.desce(); //versão2 } }
package me_me_elevador.logica; public interface IEstado { //acções comuns a cada uma dos estados:RC,andar1,andar2... //interface geral IEstado sobe(); IEstado desce(); }
package me_me_elevador.logica; public abstract class Piso implements IEstado { //classe para implementação default, sem alterar o estado //serve para simplifcar todas as outras @Override public IEstado sobe() { return this; } @Override public IEstado desce() { return this; } }
package me_me_elevador.logica; public class RC extends Piso{ @Override public IEstado sobe() { //altero de estado return new Andar1(); } @Override public IEstado desce() { //fico no mesmo estado return this; } }
package me_me_elevador.util; import java.util.Scanner; public class IUUtil { // v1 public static int getOpcao(String question, String... options) { System.out.println(question); char[] ops = new char[options.length]; for (int i = 0; i < options.length; i++) { char o = '\0'; int c = 0; while (c < options[i].length()) { o = Character.toUpperCase(options[i].charAt(c)); for (int j = 0; j < i; j++) { if (ops[j] == o) { o = '\0'; break; } } if (o != '\0') { break; } c++; } if (c >= options[i].length()) { return -1; } ops[i] = o; if (i > 0) { System.out.print(", "); } if (c > 0) { System.out.print(options[i].substring(0, c)); } System.out.print("(" + ops[i] + ")" + options[i].substring(c + 1)); } System.out.println(); Scanner sc = new Scanner(System.in); while (true) { System.out.print("Option: "); char o = Character.toUpperCase(sc.nextLine().charAt(0)); for (int i = 0; i < ops.length; i++) { if (o == ops[i]) { return i; } } } } }
No interface IEstado, são colocados todas as ações dos estados, mesmo que não façam sentido em alguns dos estados.
A class Piso, faz a implementação default de alguns dos estados para que não tenhamos que estar a repetir código nos diferentes estados.
Programação avançada – capitulo 8
Num máquina de estados existem os seguintes conceitos:
estados (por exemplo: “sem moedas”, “com moedas”, “em manutenção”, ..),
acções (por exemplo: “insere moeda”, “retira moeda”, “roda manípulo”, “roda manipulo”,…),
tem reacções (de ignorar, ou de alterar o seu estado e executar acções (que por sua vez podem ou não gerar outras acções)).
Assim uma aplicação tem:
contexto ou entidade (entidade cujo contexto depende do seu estado),
eventos (podem acontecer acções que fazem desencadear eventos),
e estados (é a situação que é assumida aquando de eventos e traduz o resultado do comportamento da entidade).
A máquina de estados orientada a objectos
A entidade maquina de estados, tem funções que correspondem ao processamento dos eventos a que reage. O processamento dos eventos depende do estado em que a entidade se encontra. Quando se pretende que o código das funções da entidade que correspondem ao processamento de eventos não envolva instruções if ou switch dependentes do estado:
- define-se uma hierarquia de classes que representa os estados possíveis e contém o conhecimento acerca do processamento de eventos em cada estado (incluindo mudanças de estado)
- a entidade, em cada momento, tem uma referência para um objecto que representa o estado concreto em que se encontra
- as funções da entidade que correspondem a processamento de eventos que dependem do estado, delegam para o objecto que representa o estado corrente, o processamento dos eventos.
O contexto tem uma referência para um objecto que representa o estado (concreto) em que se encontra. Os possíveis estados concretos fazem parte de uma hierarquia que tem por base um tipo abstracto, IEstado.
O comportamento da entidade (o seu contexto) é delegado nesse objecto (estado concreto):
reacção aos eventos
acções a executar
mudanças de estado
Assim surge a entidade ou contexto, o estado e os estados concretos, e que se podem resumir da seguinte forma:
A entidade ou contexto:
define o interface necessário de acordo com as suas responsabilidades
mantém um membro que representa o estado concreto em que se encontra
tem uma referencia para o IEstado (tipo da base da hierarquia que representa os estados possíveis) que refere o objecto que representa o estado concreto em que se encontra
tem métodos que representam o processamento de eventos. A entidade delega o processamento de eventos (que pode variar conforme o seu estado) no objecto que representa o estado corrente
O estado (IEstado):
define o interface para encapsular o comportamento da entidade que pode variar conforme o seu estado concreto
Os Estados concretos, que são classes derivadas da classe EstadoAdapter (que implementa o interface IEstado):
cada classe derivada, representando um estado concreto, implementa o comportamento que lhe e associado.
1 |