Document the conception

main
Clément FRÉVILLE 2 years ago
parent 204d26a7e7
commit 564ac6759b

@ -0,0 +1,130 @@
# Ebullition
Une application Java et JavaFX pour gérer des capteurs de température.
## Conception
### Interfaces partagées
```mermaid
classDiagram
class Tickable {
+tick()*
}
<<interface>> Tickable
class Nameable {
+getName()* String
+getDisplayName() String
}
<<interface>> Nameable
class Identifiable {
+getId()* int
+setName(name : String)*
}
<<interface>> Identifiable
class ObservableIdentifiable {
+idProperty()* ReadOnlyIntProperty
+getId() int
+nameProperty()* StringProperty
+getName() String
+setName(name : String)
+displayNameExpression() StringExpression
+getDisplayName() String
}
<<interface>> ObservableIdentifiable
class SensorFactory {
+create(registry : SensorRegistry, name : String)* Sensor
}
<<interface>> SensorFactory
class AutoUpdateStrategyFactory {
+create()* AutoUpdateStrategy
}
<<interface>> AutoUpdateStrategyFactory
Nameable <|-- Identifiable
Identifiable <|-- ObservableIdentifiable
Nameable <|-- SensorFactory
Nameable <|-- AutoUpdateStrategyFactory
```
L'interface `Tickable` définit une méthode `tick` qui est appelée périodiquement par un thread.
Tous les objets héritent en Java de `java.lang.Object` et ont donc une méthode `toString` utilisée principalement pour déboguer.
Lorsqu'un objet est fait pour être affiché à l'utilisateur, ce n'est pas du débogage.
L'interface `Nameable` définit les méthodes `getName` et `getDisplayName` qui retourne les noms à afficher pour ces objets.
Un objet peut être identifié par un identifiant unique, un `UUID` ou un `int`.
L'interface `Identifiable` définit la méthode `getId` qui permet de récupérer cet identifiant sous forme d'entier.
Elle définit aussi une méthode `setName` pour changer le nom de l'objet.
Des objets qui implémentent `Nameable` ou `Identifiable` ne sont pas nécessairement observables.
C'est pourquoi l'interface `ObservableIdentifiable` hérite de ces deux interfaces et expose les propriétés observables pour l'identifiant et le nom.
Il s'agit du même nom que les méthodes `getId` et `getName` mais en exposant une propriété observable.
D'autres éléments de l'application sont nommables, comme certaines fabriques d'objets : `SensorFactory` crée des capteurs et `AutoUpdateStrategyFactory` crée des stratégies d'actualisation automatique.
Ces deux interfaces héritent de `Nameable` pour proposer un affichage de ces fabriques dans l'application.
### Capteurs
```mermaid
classDiagram
class ObservableIdentifiable {
...
}
<<interface>> ObservableIdentifiable
class Tickable {
+tick()*
}
<<interface>> Tickable
class Sensor {
-id : IntegerProperty
-name : StringProperty
-displayName : StringExpression
-temperature : DoubleProperty
+Sensor(id : int, name : String)
+idProperty() int
+nameProperty() StringProperty
+displayNameExpression() StringExpression
+temperatureProperty() ReadOnlyDoubleProperty
+getTemperature() double
}
class ManualSensor {
+temperatureProperty() DoubleProperty
}
class AutoSensor {
-updateStrategy : ObjectProperty~AutoUpdateStrategy~
+tick()
+getUpdateStrategy() AutoUpdateStrategy
+setUpdateStrategy(s : AutoUpdateStrategy)
+updateStrategyProperty() ReadOnlyObjectProperty~AutoUpdateStrategy~
}
class VirtualSensor {
-sources : ObservableList~DataSource~
-sourcesProperty : ListProperty~DataSource~
+addSource(s : Sensor, weight : double)
+removeSource(s : Sensor) bool
+sourcesProperty() ReadOnlyListProperty~DataSource~
#compute()
}
class DataSource {
-sensor : Sensor
-weight : DoubleProperty
+sensor() Sensor
+weight() double
}
Sensor <|-- ManualSensor
Sensor <|-- AutoSensor
Sensor <|-- VirtualSensor
ObservableIdentifiable <|.. Sensor
Tickable <|.. AutoSensor
DataSource "*" <-- VirtualSensor
Sensor "1" <-- DataSource
```
Un capteur est un objet observable et identifiable.
S'il peut être mis à jour périodiquement comme c'est le cas pour les capteurs automatiques `AutoSensor`, il implémente l'interface `Tickable`.
Un capteur manuel ne fait qu'autoriser publiquement la modification de la température par rapport à la classe abstraite `Sensor`.
Un capteur virtuel est composé de plusieurs sources de température.
C'est une variante du patron de conception composite : chaque capteur virtuel contient une liste de capteurs et de poids associés avec des objets `DataSource`.

@ -16,12 +16,12 @@ import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
import fr.uca.iut.clfreville2.model.sensor.VirtualSensor;
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.AutoUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.StandardUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.provider.AutoSensorProvider;
import fr.uca.iut.clfreville2.model.sensor.provider.ManualSensorProvider;
import fr.uca.iut.clfreville2.model.sensor.provider.SensorProvider;
import fr.uca.iut.clfreville2.model.sensor.provider.VirtualSensorProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.AutoUpdateStrategyFactory;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.StandardUpdateStrategyFactory;
import fr.uca.iut.clfreville2.model.sensor.factory.AutoSensorFactory;
import fr.uca.iut.clfreville2.model.sensor.factory.ManualSensorFactory;
import fr.uca.iut.clfreville2.model.sensor.factory.SensorFactory;
import fr.uca.iut.clfreville2.model.sensor.factory.VirtualSensorFactory;
import fr.uca.iut.clfreville2.persistence.StubSensorRegistryLoader;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
@ -64,7 +64,7 @@ public class MainWindows {
private Button changeBtn;
@FXML
private ChoiceBox<AutoUpdateStrategyProvider> autoType;
private ChoiceBox<AutoUpdateStrategyFactory> autoType;
private final ChangeListener<AutoUpdateStrategy> autoUpdateChangeHandler = this::changedUpdateStrategy;
@FXML
@ -86,7 +86,7 @@ public class MainWindows {
private TextField newName;
@FXML
private ChoiceBox<SensorProvider> createType;
private ChoiceBox<SensorFactory> createType;
@FXML
private Button createButton;
@ -216,7 +216,7 @@ public class MainWindows {
@FXML
private void bindProvidable() {
autoType.getItems().addAll(StandardUpdateStrategyProvider.values());
autoType.getItems().addAll(StandardUpdateStrategyFactory.values());
autoType.setConverter(new NameableStringConverter<>(autoType.getItems()));
autoType.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
Sensor selected = getSelectedSensor();
@ -227,9 +227,9 @@ public class MainWindows {
});
createType.getItems().addAll(
new ManualSensorProvider(),
new AutoSensorProvider(),
new VirtualSensorProvider()
new ManualSensorFactory(),
new AutoSensorFactory(),
new VirtualSensorFactory()
);
createType.setConverter(new NameableStringConverter<>(createType.getItems()));
}

@ -4,6 +4,7 @@ import fr.uca.iut.clfreville2.model.shared.TemperatureHolder;
import fr.uca.iut.clfreville2.model.shared.ObservableIdentifiable;
import javafx.beans.binding.DoubleExpression;
import javafx.beans.binding.StringExpression;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
@ -38,21 +39,6 @@ public abstract class Sensor implements ObservableIdentifiable, TemperatureHolde
return temperatureProperty().get();
}
@Override
public int getId() {
return id.get();
}
@Override
public void setName(String name) {
this.name.set(requireNonNull(name, "name"));
}
@Override
public String getName() {
return name.get();
}
@Override
public ReadOnlyIntegerProperty idProperty() {
return id;

@ -1,7 +1,7 @@
package fr.uca.iut.clfreville2.model.sensor.auto;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.AutoUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.AutoUpdateStrategyFactory;
public interface AutoUpdateStrategy {
@ -18,5 +18,5 @@ public interface AutoUpdateStrategy {
*
* @return The type of this strategy.
*/
AutoUpdateStrategyProvider getType();
AutoUpdateStrategyFactory getType();
}

@ -1,8 +1,8 @@
package fr.uca.iut.clfreville2.model.sensor.auto;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.AutoUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.StandardUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.AutoUpdateStrategyFactory;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.StandardUpdateStrategyFactory;
import java.io.IOException;
import java.nio.file.Files;
@ -21,7 +21,7 @@ public class CpuUpdateStrategy implements AutoUpdateStrategy {
}
@Override
public AutoUpdateStrategyProvider getType() {
return StandardUpdateStrategyProvider.CPU;
public AutoUpdateStrategyFactory getType() {
return StandardUpdateStrategyFactory.CPU;
}
}

@ -1,8 +1,8 @@
package fr.uca.iut.clfreville2.model.sensor.auto;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.AutoUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.StandardUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.AutoUpdateStrategyFactory;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.StandardUpdateStrategyFactory;
import java.util.Random;
@ -28,7 +28,7 @@ public class RandomUpdateStrategy implements AutoUpdateStrategy {
}
@Override
public AutoUpdateStrategyProvider getType() {
return StandardUpdateStrategyProvider.RANDOM_UPDATE;
public AutoUpdateStrategyFactory getType() {
return StandardUpdateStrategyFactory.RANDOM_UPDATE;
}
}

@ -1,8 +1,8 @@
package fr.uca.iut.clfreville2.model.sensor.auto;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.AutoUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.provider.StandardUpdateStrategyProvider;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.AutoUpdateStrategyFactory;
import fr.uca.iut.clfreville2.model.sensor.auto.factory.StandardUpdateStrategyFactory;
import java.util.Random;
@ -26,7 +26,7 @@ public class RandomVariationStrategy implements AutoUpdateStrategy {
}
@Override
public AutoUpdateStrategyProvider getType() {
return StandardUpdateStrategyProvider.RANDOM_VARIATION;
public AutoUpdateStrategyFactory getType() {
return StandardUpdateStrategyFactory.RANDOM_VARIATION;
}
}

@ -1,9 +1,9 @@
package fr.uca.iut.clfreville2.model.sensor.auto.provider;
package fr.uca.iut.clfreville2.model.sensor.auto.factory;
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
import fr.uca.iut.clfreville2.model.shared.Nameable;
public interface AutoUpdateStrategyProvider extends Nameable {
public interface AutoUpdateStrategyFactory extends Nameable {
AutoUpdateStrategy create();
}

@ -1,4 +1,4 @@
package fr.uca.iut.clfreville2.model.sensor.auto.provider;
package fr.uca.iut.clfreville2.model.sensor.auto.factory;
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
import fr.uca.iut.clfreville2.model.sensor.auto.CpuUpdateStrategy;
@ -10,7 +10,7 @@ import fr.uca.iut.clfreville2.model.sensor.auto.RandomVariationStrategy;
* <p>
* This enum ensures that the same strategy is always returned with the same identity.
*/
public enum StandardUpdateStrategyProvider implements AutoUpdateStrategyProvider {
public enum StandardUpdateStrategyFactory implements AutoUpdateStrategyFactory {
RANDOM_UPDATE {
@Override
public AutoUpdateStrategy create() {

@ -1,10 +1,10 @@
package fr.uca.iut.clfreville2.model.sensor.provider;
package fr.uca.iut.clfreville2.model.sensor.factory;
import fr.uca.iut.clfreville2.model.SensorRegistry;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
import fr.uca.iut.clfreville2.model.sensor.auto.RandomVariationStrategy;
public class AutoSensorProvider implements SensorProvider {
public class AutoSensorFactory implements SensorFactory {
@Override
public Sensor create(SensorRegistry registry, String name) {

@ -1,9 +1,9 @@
package fr.uca.iut.clfreville2.model.sensor.provider;
package fr.uca.iut.clfreville2.model.sensor.factory;
import fr.uca.iut.clfreville2.model.SensorRegistry;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
public class ManualSensorProvider implements SensorProvider {
public class ManualSensorFactory implements SensorFactory {
@Override
public Sensor create(SensorRegistry registry, String name) {

@ -1,10 +1,10 @@
package fr.uca.iut.clfreville2.model.sensor.provider;
package fr.uca.iut.clfreville2.model.sensor.factory;
import fr.uca.iut.clfreville2.model.SensorRegistry;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
import fr.uca.iut.clfreville2.model.shared.Nameable;
public interface SensorProvider extends Nameable {
public interface SensorFactory extends Nameable {
Sensor create(SensorRegistry registry, String name);
}

@ -1,9 +1,9 @@
package fr.uca.iut.clfreville2.model.sensor.provider;
package fr.uca.iut.clfreville2.model.sensor.factory;
import fr.uca.iut.clfreville2.model.SensorRegistry;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
public class VirtualSensorProvider implements SensorProvider {
public class VirtualSensorFactory implements SensorFactory {
@Override
public Sensor create(SensorRegistry registry, String name) {

@ -17,6 +17,11 @@ public interface ObservableIdentifiable extends Identifiable {
*/
ReadOnlyIntegerProperty idProperty();
@Override
default int getId() {
return idProperty().get();
}
/**
* Get the name property of this object.
*
@ -25,6 +30,16 @@ public interface ObservableIdentifiable extends Identifiable {
*/
StringProperty nameProperty();
@Override
default String getName() {
return nameProperty().get();
}
@Override
default void setName(String name) {
nameProperty().set(name);
}
/**
* Get the display name of this object.
*

Loading…
Cancel
Save