Skip to content
Snippets Groups Projects
Commit d4d5c235 authored by Fabien Delecroix's avatar Fabien Delecroix
Browse files

actualisation sujet : début

parent 37683615
No related branches found
No related tags found
No related merge requests found
Showing
with 88 additions and 221 deletions
bin/
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
# TP4 - Observateur/Observé
# TP3 - Observateurs/Observable
Dans ce TP, vous allez vous familiariser avec les notions observateur/observé
notamment en implémentant les classes nécessaires puis en les utilisant pour
réaliser une horloge simple.
Dans ce TP, vous allez vous familiariser avec le patron de conception observateurs/observable.
D'abord, en implémentant sa structure et son mécanisme.
Puis, en utilisant cette couche abstraite pour réaliser un petit programme présentant des objectifs sur des saisies utilisateurs.
## Le patron Observateur / Observé
## Le patron Observateurs / Observable
La figure suivante vous présente le patron Observateur (ici « Observer ») / Observé (ici « Subject »).
L’idée est qu’un observateur peut s’inscrire auprès d’un Observé et être avertis d’évènements qui se produisent sur l’Observé.
La méthode « update() » des Observateurs est déclenchée par l’Observé chaque fois qu’il veut prévenir d’un évènement.
La figure suivante vous présente le patron Observateurs (ici « Observer ») / Observable.
L’idée est qu’un ou plusieurs observateurs peuvent s’inscrire auprès d’un Observable et être avertis d’évènements qui se produisent sur ce dernier.
La méthode « update() » des Observateurs est déclenchée par l’Observable chaque fois qu’il veut prévenir d’un évènement.
Il utilise pour ça sa propre méthode « notifyObservers() ».
```mermaid
classDiagram
direction LR
class Subject
<<Abstract>> Subject
Subject --> "*" Observer : #observers
Subject ..> Observer : notifies
Subject : +attach(Observer) void
Subject : +detach(Observer) void
Subject : #notifyObservers() void
Subject : #notifyObservers(Object) void
class Observable
<<Abstract>> Observable
Observable --> "*" Observer : #observers
Observable ..> Observer : notifies
Observable : +attach(Observer) void
Observable : +detach(Observer) void
Observable : #notifyObservers() void
Observable : #notifyObservers(Object) void
class Observer
<<interface>> Observer
Observer : +update(Subject) void
Observer : +update(Subject, Object) void
Observer : +update(Observable) void
Observer : +update(Observable, Object) void
```
**Q1.1** Compléter la classe abstraite Subject de manière à pouvoir disposer du mécanisme Observateur/Observé.
**Q1.1** Compléter la classe abstraite Observable de manière à pouvoir disposer du mécanisme Observateur/Observable.
Vérifiez la validité de votre implémentation à l'aide des tests fournis.
```java
package fr.univlille.iut.r304.tp4.q1;
public abstract class Subject {
public void attach(Observer obs)
public void detach(Observer obs)
protected void notifyObservers()
protected void notifyObservers(Object data)
public abstract class Observable {
public void attach(Observer obs){}
public void detach(Observer obs){}
protected void notifyObservers(){}
protected void notifyObservers(Object data){}
}
```
Nous utiliserons ce pattern pour implémenter un (des) chronomètre(s).
Nous utiliserons ce pattern pour implémenter un (des) analyseur(s) de textes saisis.
On vous fournit la classe suivante (*TimerThread*) qui implémente un thread simple qui produit un évènement toutes les secondes.
Ce TimerThread permettra de déclencher la mise à jour des horloges qui afficheront l’heure.
On souhaite instancier deux règles, qui se mettent à jour à chaque ligne saisie.
Ces deux règles utiliseront les mêmes saisies mais vérifieront des critères différents.
```java
public class TimerThread extends Thread {
@Override
public void run(){
while (true) {
try {
sleep(1000);
// annoncer le « tick-horloge »
} catch (InterruptedException e) {
// on ignore et on espère que ce n’est pas grave
}
}
}
}
```
Le thread s’utilise de cette façon : `new TimerThread().start();` (ce qui provoque l'appel à la méthode `void run()`) et boucle sans fin
en faisant une action (que **vous** devez définir) chaque seconde.
On souhaite instancier deux chronomètres, qui se mettent à jour toutes les secondes.
Ces deux chronomètres utiliseront le même Timer mais auront des temps écoulés différents (par simplicité, vous pouvez juste les initialiser à des valeurs différentes.
```mermaid
classDiagram
direction LR
class Subject
<<Abstract>> Subject
Subject --> "*" Observer : #observers
Subject : +attach(Observer) void
Subject : +detach(Observer) void
Subject : #notifyObservers() void
Subject : #notifyObservers(Object) void
class Observer
<<interface>> Observer
Observer : +update(Subject) void
Observer : +update(Subject, Object) void
Timer --|> Subject
Chronometer ..|> Observer
```
**Q1.2** Pour l’implémentation de Timer, on s’aperçoit d’un problème d’héritage.
Quelles sont les deux classes dont ce Timer devrait hériter ?
**Q1.3** Proposez une solution pour ce problème (c-a-d implémentez le Timer comme un Subject observable).
Implémentez aussi une classe chronomètre qui puisse être notifié par le Timer toutes les secondes et affiche le nombre de secondes écoulées.
```java
package fr.univlille.iut.r304.tp4.q1;
public class Timer
public void start()
public void stopRunning()
...
```
Note: Des tests sont fournis dans le projet pour que vous vous assuriez que vos classes fonctionnent comme attendu.
Respectez les noms des packages, classes et méthodes
**Q1.4**
**Q1.2**
Lors des épreuves de course sportive, il n'est pas rare d'afficher en parallèle le chronomètre de l'étape et celui du temps total.
Dans cette idée, écrivez un main avec deux chronomètres console qui affichent simplement leur nom et le nombre de secondes écoulées en boucle, l'un démarrant à zéro, l'autre à une valeur saisie au départ.
On doit par exemple pouvoir dérouler le scénario suivant :
......@@ -168,9 +111,9 @@ Vérifier la validité de votre implémentation en exécutant les tests associé
package fr.univlille.iut.r304.tp4.q2;
public class ConnectableProperty extends ObservableProperty
public void connectTo(ConnectableProperty other)
public void biconnectTo(ConnectableProperty other)
public void unconnectFrom(ConnectableProperty other)
public void connectTo(ConnectableProperty other){}
public void biconnectTo(ConnectableProperty other){}
public void unconnectFrom(ConnectableProperty other){}
...
```
......
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
package fr.univlille.iut.r304.tp4;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainExemple extends Application {
@Override
public void start(Stage stage) {
Label l = new Label(welcomeMessage());
Scene scene = new Scene(new StackPane(l), 640, 480);
stage.setScene(scene);
stage.show();
}
private String welcomeMessage() {
String javaVersion = System.getProperty("java.version");
String javafxVersion = System.getProperty("javafx.version");
return
"Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".\n" +
" (and powered by maven)\n";
}
public static void main(String[] args) {
launch();
}
}
package fr.univlille.iut.r304.tp4.q1;
public abstract class Subject {
public abstract class Observable {
protected void notifyObservers() {
}
......
......@@ -2,7 +2,7 @@ package fr.univlille.iut.r304.tp4.q1;
public interface Observer {
public void update(Subject subj);
public void update(Subject subj, Object data);
void update(Observable subj);
void update(Observable subj, Object data);
}
package fr.univlille.iut.r304.tp4.q1;
public class Timer {
public void start() {
}
public void stopRunning() {
}
public void attach(Observer observer) {
// methode cree pour que les tests compilent sans erreur
// n'est pas censée rester une fois que vous avez fini Q1.3
}
public void detach(Observer observer) {
// methode cree pour que les tests compilent sans erreur
// n'est pas censée rester une fois que vous avez fini Q1.3
}
}
package fr.univlille.iut.r304.tp4;
import fr.univlille.iut.r304.tp4.q1.Observer;
import fr.univlille.iut.r304.tp4.q1.Subject;
import fr.univlille.iut.r304.tp4.q1.Observable;
/** ObserverTestStub
* Can tell whether it was notified or not
......@@ -12,6 +12,7 @@ public class ObserverTestStub implements Observer {
protected boolean wasNotified;
protected int someValue;
protected static final int expectedValue = 42;
public ObserverTestStub() {
wasNotified = false;
......@@ -22,17 +23,24 @@ public class ObserverTestStub implements Observer {
return someValue;
}
public int getExpectedValue() {
return expectedValue;
}
public void setValue(int someValue) {
this.someValue = someValue;
}
public void update(Subject subj) {
public void update(Observable subj) {
wasNotified = true;
}
public void update(Subject subj, Object data) {
public void update(Observable subj, Object data) {
wasNotified = true;
someValue = (int) data;
if (someValue == expectedValue){
subj.detach(this);
}
}
public boolean wasNotified() {
......
......@@ -5,9 +5,7 @@ import org.junit.jupiter.api.Test;
import fr.univlille.iut.r304.tp4.ObserverTestStub;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
public class TestQ1 {
......@@ -15,7 +13,7 @@ public class TestQ1 {
/** A mock concrete subject
* Used to register Observers and notify them
*/
protected class MockSubject extends Subject {
protected static class MockSubject extends Observable {
public void notifyValue(int i) {
this.notifyObservers(i);
}
......@@ -84,4 +82,12 @@ public class TestQ1 {
assertEquals(5, observer.getValue());
}
@Test
public void test_detach_on_update_is_safe() {
subject.attach(observer);
subject.notifyValue(observer.getExpectedValue());
assertTrue(observer.wasNotified());
subject.notifyValue(5);
assertNotEquals(5,observer.getValue());
}
}
package fr.univlille.iut.r304.tp4.q1;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import fr.univlille.iut.r304.tp4.ObserverTestStub;
import static org.junit.jupiter.api.Assertions.*;
public class TestQ3 {
private static final int MORE_THAN_1_SECOND = 1100; // in milliseconds
/** Two objects used in the tests
*/
protected Timer timer;
protected ObserverTestStub observer;
@BeforeEach
public void setup() {
timer = new Timer();
timer.start();
observer = new ObserverTestStub();
}
@AfterEach
public void teardown() {
timer.stopRunning();
}
@Test
public void test_timer_notifies_attached_observer() {
assertFalse( observer.wasNotified());
timer.attach(observer);
try {
Thread.sleep(MORE_THAN_1_SECOND);
} catch (InterruptedException e) {
fail("Exception while waiting");
}
assertTrue( observer.wasNotified());
}
@Test
public void test_timer_does_not_notify_unattached_observer() {
assertFalse( observer.wasNotified());
try {
Thread.sleep(MORE_THAN_1_SECOND);
} catch (InterruptedException e) {
fail("Exception while waiting");
}
assertFalse( observer.wasNotified());
}
@Test
public void test_timer_does_not_notify_detached_observer() {
assertFalse( observer.wasNotified());
timer.attach(observer);
timer.detach(observer);
try {
Thread.sleep(MORE_THAN_1_SECOND);
} catch (InterruptedException e) {
fail("Exception while waiting");
}
assertFalse( observer.wasNotified());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment