Exercices Patron Builder, Singleton, Observer

WeatherService

Le but de cet exercice est de tester les contours du design pattern Singleton. Pour faciliter la correction, recopiez à chaque question vos classes dans un package différent (i.e., fr.uge.poo.weatherservice.question1, ...).

Dans cet exercice, nous allons utiliser plusieurs versions d'une même librairie très simple qui permet de récupérer la température dans une ville. Les trois versions de la librairie implémentent toutes l'interface WeatherService.java.

package com.evilcorp.weatherservice;

public interface WeatherService {
    int query(String city);
}

Dans un premier temps, on utilise la librairie WeatherService.java qui s'utilise comme suit:

    var service = new WeatherServiceTS();
    System.out.println(service.query("Paris"));

La classe WeatherServiceTS est thread-safe.

On considère l'application jouet ci-dessous:

import com.evilcorp.weatherservice.WeatherService;
import com.evilcorp.weatherservice.WeatherServiceTS;

public class Application {

    public void start() throws InterruptedException {


        System.out.println("Warming  up");
        Thread.sleep(5_000);
        System.out.println("Starting");


        Thread.ofPlatform().start(() -> {
            for(;;){
                WeatherService service = new WeatherServiceTS();
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    throw new AssertionError();
                }
                System.out.println("Paris : "+service.query("Paris"));
            }
        });

        Thread.ofPlatform().start(() -> {
            for(;;){
                WeatherService service = new WeatherServiceTS();
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    throw new AssertionError();
                }
                System.out.println("Madrid : "+service.query("Madrid"));
            }
        });
    }
    public static void main(String[] args) throws InterruptedException {
         var application = new Application();
         application.start();
    }
}

Notre but sera de centraliser les accès à ce service en utilisant le design pattern Singleton.

Modifiez l'application pour utiliser un singleton pour le WeatherServiceTS. On veut que le WeatherService soit créé au moment de sa première utilisation et pas avant.

On veut maintenant utiliser la librairie WeatherServiceNTS.java qui s'utilise comme la précédente sauf qu'elle n'est pas thread-safe (on vous demande de faire comme si elle ne l'était pas).

Modifiez l'application pour utiliser un singleton pour le WeatherServiceNTS.

On veut maintenant utiliser la librairie WeatherServiceTSFail.java qui s'utilise comme les précédentes sauf que le constructeur peut lever une exception si le service n'est pas disponible.

On veut modifier l'application pour afficher un message si le service n'est pas disponible.

Que se passe-t-il si vous utilisez cette classe avec une implémentation classique du design pattern Singleton ? Quel dogme fondamental n'est pas respecté par WeatherServiceFail ?

Modifiez la classe Application pour utiliser un singleton avec WeatherServiceFail.

Comment aurez dû être proprement codée la librairie WeatherServiceFail ?

Newsletter le retour

Pour faciliter la correction, recopiez à chaque question vos classes dans un package différent (i.e., fr.uge.poo.newsletter.question4, ...).

Dans cet exercice, on reprend la classe Newsletter du TP précédent. Votre boss vous demande de rajouter de nombreuses fonctionalités aux newsletters.

Il veut implémenter les fonctionalités suivantes:

Quel principe solide empêche de tout simplement coder ces fonctionalités dans la classe Newsletter ?

Implémenter une architecture logicielle qui permette de rajouter ces fonctionnalités tout en respectant les principes SOLID. Votre boss vous interdit formellement d'affaiblir l'encapsulation de la classe Newsletter : il accepte qu'une newsletter publie son name mais pas ses User.