You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
6.5 KiB

# Ebullition
Une application Java et JavaFX pour gérer des capteurs de température.
## Usage
Sur la partie gauche de l'application figure l'arborescence des capteurs.
Un nouveau capteur peut être ajouté à la liste en saisissant son nom dans le champ de texte, son type et en appuyant sur le bouton *Create*.
Il sera alors ajouté à la racine de l'arborescence et si le capteur qui était sélectionné est un capteur virtuel, il sera également ajouté comme source de ce dernier.
Une source de capteur virtuel peut être supprimée en sélectionnant le capteur virtuel puis en utilisant le menu contextuel sur la source à supprimer.
Les indicateurs liés à la génération automatique de température sont présentés en bas de l'application.
Ils permettent d'activer ou non la génération automatique de température et de choisir la fréquence d'actualisation.
## Conception
*Note : les diagrammes UML présentés ci-dessous sont générés avec [Mermaid](https://mermaidjs.github.io/), et peuvent ne pas être rendus correctement sur CodeFirst. Les flèches d'héritage n'ont notamment pas la bonne forme.*
### 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`.
### Stratégies d'actualisation automatique
```mermaid
classDiagram
class AutoUpdateStrategy {
+nextValue(s : AutoSensor)* double
+getType()* AutoUpdateStrategyFactory
}
<<interface>> AutoUpdateStrategy
class RandomUpdateStrategy {
-random : Random
-min : double
-max : double
+nextValue(s : AutoSensor) double
+getType() AutoUpdateStrategyFactory
}
class RandomVariationStrategy {
-random : Random
-maxVariation : double
+nextValue(s : AutoSensor) double
+getType() AutoUpdateStrategyFactory
}
class CpuUpdateStrategy {
+nextValue(s : AutoSensor) double
+getType() AutoUpdateStrategyFactory
}
AutoUpdateStrategy <|.. CpuUpdateStrategy
AutoUpdateStrategy <|.. RandomUpdateStrategy
AutoUpdateStrategy <|.. RandomVariationStrategy
```