Dans Generic System, il est possible de rechercher spécifiquement un Generic (recherche simple), ou bien un ensemble de Generic (recherche avancée). Quand un ensemble de résultats doit être retourné, Generic System ne renvoie pas de liste de Generic, mais un Snapshot.
Introduction
Qu’est-ce qu’un Snapshot ?
D’un point de vue fonctionnel, un Snapshot est un ensemble de résultats qui est conscient de son contexte. Le Snapshot est directement en relation avec le modèle de persistence des données, contrairement aux Collections Java qui possèdent un cache en interne contenant les informations.
D’un point de vue technique, un Snapshot est d’une part un fournisseur de Stream et d’autre part un aware Iterable. Comme nous allons le voir par la suite, un Snapshot peut être requêté directement en utilisant des filtres de Stream.
Comparaison Snapshot / Collection
Pour prendre un exemple simple, nous allons créer une instance de Vehicle puis la stocker soit dans une Collection, soit dans un Snapshot. Nous allons ensuite vérifier que notre Collection et notre Snapshot contiennent bien cette instance. Puis nous ajoutons une nouvelle instance de Vehicle, et nous vérifions que notre Collection et notre Snapshot contiennent bien les deux instances.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// (1) Engine engine = new Engine(); Generic vehicle = engine.addInstance("Vehicle"); Generic myFirstVehicle = vehicle.addInstance("myFirstVehicle"); // (2) Snapshot<Generic> instances = vehicle.getInstances(); // (3) assert instances.size() == 1; assert instances.contains(myFirstVehicle); // (4) Generic mySecondVehicle = vehicle.addInstance("mySecondVehicle"); // (5) // (6) assert instances.size() == 2; assert instances.containsAll(Arrays.asList(myFirstVehicle, mySecondVehicle)); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// (1) public static class Vehicle { } Vehicle myFirstVehicle = new Vehicle(); // (2) List<Vehicle> instances = new ArrayList<>(); instances.add(myFirstVehicle); // (3) assert instances.size() == 1; assert instances.contains(myFirstVehicle); // (4) Vehicle mySecondVehicle = new Vehicle(); // (5) instances.add(mySecondVehicle); // (6) assert instances.size() == 2; assert instances.containsAll(Arrays.asList(myFirstVehicle, mySecondVehicle)); |
Voici la synthèse des différences :
Ref | Collection | Snapshot |
---|---|---|
(1) | Crée la classe Vehicle et une instance de Vehicle. | Crée le type Vehicle et une instance de Vehicle. |
(2) | Crée une liste de Vehicle et ajoute l’instance. | Récupère les instances de Vehicle via un Snapshot. |
(3) | Vérifie que la liste de Vehicle contient l’instance myFirstVehicle. | Vérifie que le Snapshot d’instances contient l’instance myFirstVehicle. |
(4) | Crée une seconde instance de Vehicle. | Crée une seconde instance de Vehicle. |
(5) | Ajoute la seconde instance à la liste de Vehicle. | Rien à faire. |
(6) | Vérifie que la liste de Vehicle contient toutes les instances. | Vérifie que le Snapshot d’instances contient toutes les instances. |
Vous remarquez qu’il est nécessaire de mettre à jour notre Collection pour qu’elle connaisse l’état de nos instances, alors que le Snapshot est en relation directe avec le modèle de persistance, et reste informé des changements.
Recherche avec résultats multiples
Comme nous l’avons vu dans l’article sur les recherches de base, il est possible de rechercher tous les types de Generic grâce aux méthodes getGeneric. De la même façon, il existe des méthodes getGenerics (au pluriel) qui permettent de demander à Generic System de nous renvoyer un ensemble de résultats.
Afin de mieux illustrer cet article, nous allons utiliser le code suivant pour initialiser notre moteur (cliquez pour déplier) :
Rechercher des types
La recherche de types fait appel à la méthode getInstances(). Voyons cela en exemple :
1 2 |
// Get all the types from the Engine Snapshot<Generic> types = engine.getInstances(); |
Nous pouvons vérifier que notre Snapshot contient bien les types que nous avons créé :
1 2 3 4 5 6 7 |
// types should at least contain Vehicle, Color Generic vehicle = engine.getInstance("Vehicle"); Generic color = engine.getInstance("Color"); Generic car = engine.getInstance(vehicle, "Car"); Generic bike = engine.getInstance(vehicle, "Bike"); assert types.size() >= 4; assert types.containsAll(Arrays.asList(vehicle, color, car, bike)); |
Rechercher des attributs ou des propriétés
La recherche d’attributs et de propriétés fait appel à la méthode getAttributes() :
1 2 |
// Get all Vehicle attributes Snapshot<Generic> attributes = vehicle.getAttributes(); |
Nous pouvons vérifier que notre Snapshot contiennent bien Options, Wheels et Power :
1 2 3 4 5 6 |
// Vehicle contains at least Options, Wheels and Power attributes Generic options = vehicle.getAttribute("Options"); Generic wheels = vehicle.getAttribute("Wheels"); Generic power = vehicle.getAttribute("Power"); assert attributes.size() >= 3; assert attributes.containsAll(Arrays.asList(options, wheels, power)); |
Rechercher des relations ou des links
La recherche de relations ou de links fait appel respectivement aux méthodes getRelations() et getLinks() :
1 2 3 4 5 |
// Get all relations from Vehicle Snapshot<Generic> relations = vehicle.getRelations(); // Get the links from the relation betterThan for myCar Snapshot<Generic> links = myCar.getLinks(betterThan); |
Là encore, nous pouvons vérifier que les relations que nous avions créés pour l’occasion sont bien contenus dans le Snapshot :
1 2 3 4 5 |
// Vehicle has at least VehicleColor and betterThan relations Generic vehicleColor = vehicle.getRelation("VehicleColor"); Generic betterThan = vehicle.getRelation("betterThan"); assert relations.size() >= 2; assert relations.contains(Arrays.asList(vehicleColor, betterThan)); |
Comme lors d’une recherche simple, il existe une petite subtilité pour rechercher des links. Il faut en effet préciser à quelle relation ils appartiennent :
1 2 3 4 5 |
// The links should at least contain 2 links Generic myCarRocks = myCar.getLink(betterThan, "my car is better than yours"); Generic iLoveMyCar = myCar.getLink(betterThan, "my car is better than my bike"); assert links.size() >= 2; assert links.containsAll(Arrays.asList(myCarRocks, iLoveMyCar)); |
Rechercher des instances
La recherche d’instances fait logiquement appel à la méthode getInstances() :
1 2 |
// Get all Vehicle instances Snapshot<Generic> vehicles = vehicle.getInstances(); |
Nous pouvons ensuite attester qu’il existe bien au moins trois instances pour notre type Vehicle :
1 2 3 4 5 6 |
// We should have at least 3 instances of Vehicle Generic myFirstVehicle = vehicle.getInstance("myFirstVehicle"); Generic mySecondVehicle = vehicle.getInstance("mySecondVehicle"); Generic myThirdVehicle = vehicle.getInstance("myThirdVehicle"); assert vehicles.size() >= 3; assert vehicles.containsAll(Arrays.asList(myFirstVehicle, mySecondVehicle, myThirdVehicle)); |
Rechercher des sous-instances
Vous avez peut-être lu dans un article précédent qu’il était possible de créer des sous-types, qui héritent d’un type.
ll est donc possible de rechercher les instances de ces sous-types grâce à la méthode getSubInstances() :
1 2 |
// Get all Vehicle sub-instances (i.e., instances of sub-types) Snapshot<Generic> subinstances = vehicle.getSubInstances(); |
Nous pouvons vérifier que ce Snapshot contient bien les instances de Vehicle ainsi que de ces sous-types Car et Bike :
1 2 3 4 5 6 7 8 |
// We should have at least 4 sub-instances Generic myCar = car.getInstance("myCar"); Generic yourCar = car.getInstance("yourCar"); Generic myBike = bike.getInstance("myBike"); Generic yourBike = bike.getInstance("yourBike"); Generic myFirstVehicle = vehicle.getInstance("myFirstVehicle"); assert subinstances.size() >= 4; assert subinstances.containsAll(Arrays.asList(myCar, yourCar, myBike, yourBike, myFirstVehicle)); |
Rechercher des holders
La recherche de holders fait appel à la méthode getHolders. Mais comme lors de la recherche de base, il faut indiquer à Generic System sur quel attribut rechercher les holders :
1 2 |
// Get the holders from myFisrstVehicle Snapshot<Generic> holders = myFirstVehicle.getHolders(options); |
Dans ce cas, notre Snapshot contient tous les holders de l’attribut Options :
1 2 3 4 5 |
// myFirstVehicle has at least the air conditioning and ABS Generic musicPlayer = myFirstVehicle.getHolder(options, "music player"); Generic abs = myFirstVehicle.getHolder(options, "ABS"); assert holders.size() >= 2; assert holders.containsAll(Arrays.asList(musicPlayer, abs)); |
Filtrer les recherches
Quand vous effectuez une recherche qui renvoie un ensemble de résultats, vous souhaitez peut-être limiter le nombre de résultats obtenus en fonction de critères prédéfinis.
Avec un Snapshot, c’est très simple de filtrer les résultats, puisque que Snapshot est un fournisseur de Stream ! Vous bénéficiez donc de toute la puissance de l’API Stream Java 8.
Reprenons notre exemple, et imaginons que l’on souhaite récupérer toutes les instances de
Vehicle ayant l'
Options “air conditioning” :
1 2 3 4 5 6 7 8 |
// Get all instances of Vehicle that have the Options "air conditioning" Snapshot<Generic> vehicles = vehicle.getInstances() // Filter the stream of Generics .filter(generic -> generic.getHolders(options) // Get a stream on the holders "Options" .stream() // Get all holders which have the "air conditioning" .anyMatch(holder -> holder.getValue().equals("air conditioning"))); |
1 2 3 4 5 6 7 |
// This filtered search should only contain 2 instances Generic myFirstVehicle = vehicle.getInstance("myFirstVehicle"); Generic mySecondVehicle = vehicle.getInstance("mySecondVehicle"); Generic myThirdVehicle = vehicle.getInstance("myThirdVehicle"); assert vehicles.size() == 2; assert vehicles.containsAll(Arrays.asList(myFirstVehicle, myThirdVehicle)); assert !vehicles.contains(mySecondVehicle); |
1 2 3 4 5 6 7 |
// Add another instance that should appear in the results Generic myFourthVehicle = vehicle.addInstance("myFourthVehicle"); myFourthVehicle.addHolder(options, "air conditioning"); // And indeed, the snapshot has been updated and now contains the new vehicle assert vehicles.size() == 3; assert vehicles.contains(myFourthVehicle); |
En résumé
- Generic System permet d’effectuer des recherches retournant un ensemble de résultats sous la forme d’un Snapshot ;
- Un Snapshot est toujours conscient des modifications du modèle de données. Il s’agit d’un fournisseur de Stream et d’un aware Iterable.
- Enfin, il est possible de filtrer les recherches en utilisant un Stream. Les critères de sélection se font via la méthode filter.