Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mokira3d48/suko
Super Kalculator implemented in Java with JFX.
https://github.com/mokira3d48/suko
calculator interpreter-pattern javafx javafx-fxml pipeline-pattern
Last synced: 21 days ago
JSON representation
Super Kalculator implemented in Java with JFX.
- Host: GitHub
- URL: https://github.com/mokira3d48/suko
- Owner: mokira3d48
- License: mit
- Created: 2023-12-30T05:54:11.000Z (about 1 year ago)
- Default Branch: master
- Last Pushed: 2024-01-18T15:54:03.000Z (12 months ago)
- Last Synced: 2024-10-30T01:55:24.647Z (2 months ago)
- Topics: calculator, interpreter-pattern, javafx, javafx-fxml, pipeline-pattern
- Language: Java
- Homepage:
- Size: 793 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
-------------------------------------------------------------------------------
![](https://img.shields.io/badge/pattern-MVC-blue)
![](https://img.shields.io/badge/build-success-success)
![](https://img.shields.io/badge/IDE-Netbeans-green)
![](https://img.shields.io/badge/contact-dr.mokira%40gmail.com-blueviolet)
Une calculatrice simple avec interface graphique développée en **JavaFX** et **FXML + CSS**.
Comme spécifié ci-dessous, elle ne gère pas les nombres à virgule, ni les parenthèses ni
autres fonctions mathématiques complexes à part l'addition, la soustration, la multiplication
et la division.Vous pouvez utiliser les boutons présents sur l'interface utilisateur
ou utiliser le pavé numérique de votre clavier pour interagir avec le logiciel.- Le projet de l'application avec interface graphique se trouve dans le dossier `Suko`.
- Le projet de l'application avec interface console se trouve dans le dossier `SukoConsole`.
![](./images/suko_screenshot.png)
- Appuyez sur `[ENTER]` de votre clavier ou *=* de la calculatrice pour avoir le résultat;
- Appuyez sur `[C]` de votre clavier ou le bouton **C** de la calculatrice
pour reinitialiser la calculatrice;
- Appuyez sur `[DELETE]` de votre clavier ou le bouton **CE** de la calculatrice pour effacer
le champs de saisi inférieur.
- Appuyez sur `[BACK SPACE]` de votre clavier ou le bouton **DEL** de la calculatrice pour
effacer chiffre par chiffre le nombre saisi sur la champs de saisi inférieur.
- Vous avez la possibilité de changer l'opérateur précédement saisi en appuyant sur une des
touche des opérateurs ( + - * /), ceci même si vous aviez déjà saisi un nombre dans champs
de saisi inférieur.## Spécifications
Développez une calculatrice dotée d’une interface qui reçoit les informations entrées par l’utilisateur. Ces informations permettront de calculer le résultat des opérations.- **Etape 0** : La calculatrice attend la saisie du premier terme.
- **Etape 1** : D’abord le premier terme est entré par la fourniture successive du (ou des) chiffre(s) le composant.
- **Etape 2** : Ensuite, un symbole est fourni par l’entrée d’un des signes des opérations acceptés par la calculatrice (+ - DIV *).
- **Etape 3** : Et enfin le deuxième terme qui sera composé de 1 ou plusieurs chiffres aussi sera entré.
- **Etape 4** : Apres cette étape, l’utilisateur devra taper le signe = et le résultat définitif de l’opération lui sera affiché et la calculatrice reviendra à l’**étape 1**.
A l’entrée de « C », l’opération est remise à zéro, et on revient à l’**étape 0**.> **NOTE** : l’application pourra ne gérer que les nombres entiers dans un premier temps. Ensuite, elle ne devra gérer que les cas normaux de fonctionnement. Ainsi, les cas exceptionnels d’erreur (cas anormaux) ne seront pas pris en compte (Exemple : appui sur = après saisie de la première opérande)
## Conception
Dans une expression, nous avons des opérations et des termes. Les différentes opérations possibles
que nous pouvons avoir sont des additions, multiplications, soustrations et divisions. Les termes
ne sont uniquement que des nombres entiers. Donc, il n'y aura aucune implémentation pour gérer
des nombres réels. Vooici un exemple d'expression :$$
97 \times 985 + 109 - 229
$$### Interpreteur
L'expression à calculer sera représentée sous forme arborescente, dans un premier temps. C'est ce
arbre de calcul qui sera évalué pour obtenir le résultat final. Dans l'exemple
suivant, les noeuds en forme de carré représentent les termes et les noeuds en forme circulaire
représentent les opérations ($+, -, \times \div$).
*Figure 01* : Exemple d'un arbre de calcul.
- Les noeuds en forme de carré représentent les noeuds terminaux.
- Les noeuds en forme circulaire représentent les noeuds non-terminaux.Pour parvenir à obtenir ce modèle d'arbre, nous allons utiliser le design pattern **interpreter**.
Voici donc le diagramme des classes modélisant cet arbre :
*Figure 02* : Diagramme des classes du modèle interpreter.
- Les noeuds terminaux seront représentés par les instances de la classe `TerminalNode`;
- Les noeuds non-terminaux sont représentés par les instances de la classe `NonTerminalNode`;
- Le contexte `Context` encapsule la liste des variables de l'équation mappées leurs valeurs
respectives;Le modèle interpreter permet de définir une équation en fonction des variables qu'on peut
renseigner avec leurs valeurs respectives. Ces variables sont représentées par des noeuds
terminaux.Par contre, ce modèle ne permet pas d'implémenter l'analyseur qui permettra de construire
l'arbre de calcul. Ce qui fera l'objet de la sous-section suivante.### Analyseur
Dans cette étape de conception, nous allons mettre en place l'analyseur qui va nous permettre
de construire l'arbre du modèle interpreter à partir de l'équation reçue sous forme chaine de
caractères.L'équation reçue étant sous forme de chaine de caractères, on aura besoin de faire une chaine
de traitement à effectuer sur ce dernier celle-ci afin d'obtenir l'arbre de calcul résultant.
C'est cette chaine de traitement qui constitue l'analyseur. Voici la chaine de traitement
proposée :
*Figure 03* : Pipeline de l'analyse et construction de l'arbre de calcul.
Il y a juste deux étapes de traitement.
Pour élaborer cette chaine de traitement, nous allons utiliser le design pattern **Pipeline**.
Ce modèle de conception permet de définir une chaine de responsabilité (processus)
destinée à s'exécuter de façon séquentielle : l'une après l'autre. Voici donc le diagramme
des classes modélisant cette chaine de traitement :
*Figure 04* : Diagramme des classes de l'analyseur.
Après l'implémentation, on pourra écrire le code suivant pour initialiser l'analyseur.
```java
Pipeline analyser = null;
analyser = new Pipeline<>(new Preprocess(...)).addHandler(new TreeBuilder(...));```
- `Preprocess` a besoin de la liste de tous les opérateurs mappés avec leur niveau de
riorité (de 1 à $+\infty$).```
{"+": 1};
{"-": 1};
{"/": 2};
{"*": 2};```
Plus ce nombre augment pour un opérateur plus ce opérateur a plus de priorié.
- `TreeBuilder` a besoin de la liste des opérateurs mappés avec leur instance de noeud
non-terminal respectives.```
{"+": (l, r) -> new AddNode(l, r)}
{"-": (l, r) -> new SubtractNode(l, r)};
{"*": (l, r) -> new MultiplyNode(l, r)};
{"/": (l, r) -> new DivisionNode(l, r)};
```Et pour une équation bien définit sous forme chaine de caractères, on pourra faire comme suit :
```java
Node treeRoot = analyser.execute("a * b + c - d");```
`treeRoot` sera donc le noeud racine de l'arbre de calcul résultant de l'équation `a * b + c - d`
.### Instance de calculatrice
Ici, il s'agira de "builder" une instance de la calculatrice (`Calculator`) muni de son analyseur.
Pour cela nous allons utiliser le pattern **Builder** pour élaboler le programme qui va nous
permettre de construire une instance de notre calculatrice. Voici le diagramme des classes
de l'analyseur :
*Figure 04* : Diagramme des classes du buildeur d'un objet `Calculator`.
## Implémentation
Je ne vais pas détailler l'implémentation de toutes les classes énoncées dans la partie,
mais je peux vous montrer le résultat d'implémentation sur un exemple d'équation. Je ferai
la démonstraction sur exemple suivant :$$
\alpha + x_2 \times x_3 - x_4 \times x_4 + x_4 \times (x_1 + \alpha) + \frac{x_5}{x_3 \times x_2}
$$### Construction d'une calculatrice
Dans une première étape, on doit construire une instance de la calculatrice `Calculator`.```java
Builder b = new CalculatorBuilder();
Director director = new Director(b);
director.makeBuild();
Calculator calc = b.getResult();
```### Définition du contexte
On définit une instance d'un context qui encapsulera toutes les variables de l'équation
associées à leur valeur.```java
// instantiate the context
Context ctx = new Context();ctx.assign("alpha", 8);
ctx.assign("x1", 0);
ctx.assign("x2", 12);
ctx.assign("x3", 10);
ctx.assign("x4", 65);
ctx.assign("x5", 32);
ctx.assign("x6", 10);```
### Équation à évaluer
On définit ensuite l'équation en fonction de ces variables définies précédement.```java
calc.setEquation("alpha + x2 * x3 - x4 * x4 + x4 * (x1 + alpha) + x5 / (x3 * x2)");
calc.setContext(ctx);System.out.println(ctx);
System.out.println("Equation = " + calc.getEquation());
```![](./images/output01.png)
### Evaluation de l'équation
Maintenant, on peut évaluer l'équation en appelant la fonction `evaluate()` de l'objet `calc`.```java
try {
Double result = calc.evaluate();
// On convertie le resultat en entier avant de l'afficher.
System.out.println("Result = " + result.intValue());
} catch (SemanticError e) {
System.out.println("SemanticError: \t" + e);
} catch (Exception e) {
e.printStackTrace();
}```
![](./images/output02.png)
Le programme a tout simplement remplacé les valeurs du contexte par leur variable dans l'équation
avant d'éffectuer le calcul.