Cours JavaScript et TypeScript · Module 9: Design patterns et architecture
Projet final : système de gestion de Jurassic Park
Dans cette leçon8
Bienvenue au laboratoire génétique de Jurassic Park ! Après un long voyage à travers le monde du JavaScript, l'heure est venue de relever le défi qui clôt ce module. Le Dr Henry Wu, généticien en chef du parc, te confie la création d'un système de gestion complet qui supervisera tous les aspects du fonctionnement du parc - de la surveillance des dinosaures à la sécurité des visiteurs.
Objectif du projet
Ta mission est de créer une application JavaScript avancée qui intègre toutes les technologies apprises en un seul système cohérent. Ce sera ton chef-d'œuvre - la preuve que tu maîtrises l'art de la programmation JavaScript.
Exigences fonctionnelles du système
1. Système de gestion des dinosaures
Ton système doit permettre de :
1// Example dinosaur data structure
2const dinosaurSpecies = {
3 id: 'trex-001',
4 name: 'Tyrannosaurus Rex',
5 species: 'T-Rex',
6 genome: {
7 dnaSequence: '4A7B...9F2E', // DNA sequence
8 modifications: ['enhanced-strength', 'reduced-aggression'],
9 purity: 0.92, // 92% original DNA
10 gapsFilled: ['amphibian-dna', 'bird-dna']
11 },
12 physicalTraits: {
13 height: 5.6, // meters
14 weight: 8500, // kg
15 length: 12.8, // meters
16 age: 4, // years
17 healthStatus: 'excellent'
18 },
19 behavior: {
20 aggressionLevel: 7, // 1-10
21 intelligence: 8,
22 socialBehavior: 'territorial',
23 huntingPattern: 'ambush-predator'
24 },
25 habitat: {
26 enclosureId: 'sector-7',
27 temperature: { min: 18, max: 28, current: 24 },
28 humidity: { min: 60, max: 80, current: 72 },
29 terrainType: 'forest-plains'
30 },
31 status: 'active' // active, sedated, medical-care, quarantine
32};2. Système de surveillance de la sécurité
1// Security system structure
2const securitySystem = {
3 alerts: {
4 breach: false,
5 evacuation: false,
6 containmentFailure: false,
7 emergencyProtocol: false
8 },
9 sensors: [
10 {
11 id: 'fence-sensor-001',
12 type: 'perimeter',
13 location: 'sector-7-north',
14 status: 'operational',
15 lastReading: Date.now(),
16 voltage: 10000 // fence voltage in volts
17 },
18 {
19 id: 'motion-detector-034',
20 type: 'motion',
21 location: 'visitor-center',
22 status: 'operational',
23 sensitivity: 'high',
24 detectedMovement: false
25 }
26 ],
27 accessControl: {
28 keyCards: new Map(), // Card ID -> access level
29 restrictedAreas: ['genetic-lab', 'control-room', 'medical-bay'],
30 emergencyOverride: false
31 }
32};3. Système de gestion des visiteurs
1// Visitor management system
2class VisitorManagementSystem {
3 constructor() {
4 this.visitors = new Map();
5 this.tours = new Map();
6 this.emergencyContactList = [];
7 this.evacuationProcedures = [];
8 }
9
10 registerVisitor(visitorData) {
11 const visitor = {
12 id: this.generateVisitorId(),
13 personalData: {
14 name: visitorData.name,
15 age: visitorData.age,
16 emergencyContact: visitorData.emergencyContact,
17 medicalConditions: visitorData.medicalConditions || [],
18 insurancePolicy: visitorData.insurancePolicy
19 },
20 visit: {
21 arrivalTime: new Date(),
22 departureTime: null,
23 tourType: visitorData.tourType, // 'standard', 'vip', 'research'
24 groupId: visitorData.groupId,
25 currentLocation: 'entrance',
26 visitedAreas: ['entrance']
27 },
28 safety: {
29 waiverSigned: false,
30 briefingCompleted: false,
31 emergencyProtocolsExplained: false,
32 trackingDevice: null
33 }
34 };
35
36 this.visitors.set(visitor.id, visitor);
37 return visitor.id;
38 }
39
40 trackVisitorLocation(visitorId, newLocation) {
41 const visitor = this.visitors.get(visitorId);
42 if (visitor) {
43 visitor.visit.currentLocation = newLocation;
44 visitor.visit.visitedAreas.push(newLocation);
45 this.validateSafetyProtocols(visitor);
46 }
47 }
48}4. Système du laboratoire génétique
1// Genetic laboratory system
2class GeneticLaboratory {
3 constructor() {
4 this.dnaLibrary = new Map();
5 this.activeExperiments = [];
6 this.incubators = [];
7 this.sequencingMachines = [];
8 }
9
10 analyzeDNA(sampleId, dnaSequence) {
11 const analysis = {
12 sampleId,
13 sequenceLength: dnaSequence.length,
14 gcContent: this.calculateGCContent(dnaSequence),
15 mutations: this.detectMutations(dnaSequence),
16 viability: this.assessViability(dnaSequence),
17 recommendedModifications: [],
18 timestamp: new Date()
19 };
20
21 return analysis;
22 }
23
24 createNewSpecimen(parentDNA, modifications = []) {
25 const baseGenome = this.reconstructGenome(parentDNA);
26 const modifiedGenome = this.applyModifications(baseGenome, modifications);
27
28 const specimen = {
29 id: this.generateSpecimenId(),
30 genome: modifiedGenome,
31 generation: this.getParentGeneration(parentDNA) + 1,
32 created: new Date(),
33 status: 'developing',
34 expectedHatchTime: this.calculateHatchTime(modifiedGenome),
35 parentSpecimens: [parentDNA.id]
36 };
37
38 return this.initiateIncubation(specimen);
39 }
40}Exigences techniques
1. Architecture de l'application
Ton application doit utiliser :
- le Module Pattern ou les modules ES6 pour organiser le code
- l'Observer Pattern pour la communication entre composants
- le Factory Pattern pour créer les objets dinosaure et visiteur
- le Singleton Pattern pour les systèmes critiques (sécurité, base de données principale)
1// Example of modular architecture
2// modules/ParkCore.js
3class ParkCore {
4 constructor() {
5 if (ParkCore.instance) {
6 return ParkCore.instance;
7 }
8
9 this.systems = {
10 security: new SecuritySystem(),
11 genetic: new GeneticLaboratory(),
12 visitors: new VisitorManagementSystem(),
13 dinosaurs: new DinosaurRegistry(),
14 weather: new WeatherMonitoring(),
15 power: new PowerGrid()
16 };
17
18 this.eventBus = new EventBus();
19 this.setupSystemCommunication();
20
21 ParkCore.instance = this;
22 }
23
24 setupSystemCommunication() {
25 // Communication between systems via event bus
26 this.eventBus.subscribe('security.breach', (data) => {
27 this.systems.visitors.initiateEvacuation(data.location);
28 this.systems.dinosaurs.activateContainmentProtocol();
29 });
30
31 this.eventBus.subscribe('dinosaur.escaped', (data) => {
32 this.systems.security.raiseAlert('containment-failure', data);
33 this.systems.visitors.redirectToSafeZones(data.dangerRadius);
34 });
35 }
36}2. Gestion des données
1// Data management system with localStorage and IndexedDB
2class DataManager {
3 constructor() {
4 this.localDB = new LocalDatabase('park-data');
5 this.cache = new Map();
6 this.syncQueue = [];
7 }
8
9 async saveDinosaurData(dinosaur) {
10 try {
11 // Save to cache
12 this.cache.set(dinosaur.id, dinosaur);
13
14 // Save to localStorage as backup
15 localStorage.setItem(`dino_${dinosaur.id}`, JSON.stringify(dinosaur));
16
17 // Save to IndexedDB for larger data
18 await this.localDB.store('dinosaurs', dinosaur);
19
20 // Add to synchronization queue with server
21 this.queueForSync('dinosaurs', dinosaur.id, 'update');
22
23 } catch (error) {
24 console.error('Error saving dinosaur data:', error);
25 throw new DataError('Failed to save dinosaur data');
26 }
27 }
28
29 async loadParkState() {
30 try {
31 const [dinosaurs, visitors, security] = await Promise.all([
32 this.localDB.getAll('dinosaurs'),
33 this.localDB.getAll('visitors'),
34 this.localDB.get('security', 'current-state')
35 ]);
36
37 return {
38 dinosaurs: dinosaurs || [],
39 visitors: visitors || [],
40 security: security || this.getDefaultSecurityState()
41 };
42 } catch (error) {
43 console.error('Error loading park state:', error);
44 return this.getEmergencyFallbackState();
45 }
46 }
47}3. Interface utilisateur
Ton système doit inclure :
- un tableau de bord principal offrant une vue d'ensemble de tous les systèmes
- un panneau des dinosaures avec liste, détails et fonctions de gestion
- un moniteur de sécurité avec alertes et état du système
- un panneau des visiteurs avec la liste des visites en cours
- un laboratoire génétique avec des outils d'analyse de l'ADN
- un système de reporting avec graphiques et statistiques
1// User interface example
2class ParkInterface {
3 constructor(parkCore) {
4 this.park = parkCore;
5 this.currentView = 'dashboard';
6 this.refreshInterval = null;
7 this.setupEventListeners();
8 }
9
10 render() {
11 const app = document.getElementById('park-app');
12 app.innerHTML = `
13 <header class="park-header">
14 <h1>Jurassic Park Management System</h1>
15 <div class="system-status">${this.renderSystemStatus()}</div>
16 </header>
17
18 <nav class="park-navigation">
19 ${this.renderNavigation()}
20 </nav>
21
22 <main class="park-content">
23 ${this.renderCurrentView()}
24 </main>
25
26 <aside class="alerts-panel">
27 ${this.renderAlerts()}
28 </aside>
29 `;
30
31 this.bindEvents();
32 }
33
34 renderDinosaurPanel() {
35 const dinosaurs = this.park.systems.dinosaurs.getAll();
36
37 return `
38 <div class="dinosaur-panel">
39 <h2>Dinosaur Management</h2>
40
41 <div class="dinosaur-grid">
42 ${dinosaurs.map(dino => `
43 <div class="dinosaur-card" data-id="${dino.id}">
44 <div class="dino-header">
45 <h3>${dino.name}</h3>
46 <span class="status ${dino.status}">${dino.status}</span>
47 </div>
48
49 <div class="dino-stats">
50 <div class="stat">
51 <label>Age:</label>
52 <span>${dino.physicalTraits.age} years</span>
53 </div>
54 <div class="stat">
55 <label>Health:</label>
56 <span>${dino.physicalTraits.healthStatus}</span>
57 </div>
58 <div class="stat">
59 <label>Location:</label>
60 <span>${dino.habitat.enclosureId}</span>
61 </div>
62 </div>
63
64 <div class="dino-actions">
65 <button data-action="feed">Feed</button>
66 <button data-action="checkup">Checkup</button>
67 <button data-action="relocate">Relocate</button>
68 </div>
69 </div>
70 `).join('')}
71 </div>
72
73 <button class="add-dinosaur-btn" data-action="add-dinosaur">
74 + Add new dinosaur
75 </button>
76 </div>
77 `;
78 }
79
80 bindEvents() {
81 // One listener on the container (event delegation): in an onclick attribute "this" would be the button, not ParkInterface
82 document.getElementById('park-app').onclick = (event) => {
83 const button = event.target.closest('[data-action]');
84 if (!button) return;
85 const id = button.closest('.dinosaur-card')?.dataset.id;
86 const actions = {
87 feed: () => this.feedDinosaur(id),
88 checkup: () => this.medicateCheckup(id),
89 relocate: () => this.relocateDinosaur(id),
90 'add-dinosaur': () => this.showAddDinosaurForm()
91 };
92 actions[button.dataset.action]?.();
93 };
94 }
95}4. Gestion des situations d'urgence
1// Emergency response system
2class EmergencyResponseSystem {
3 constructor(parkCore) {
4 this.park = parkCore;
5 this.emergencyLevel = 0; // 0-5, where 5 is the highest
6 this.activeProtocols = [];
7 this.evacuationRoutes = this.loadEvacuationRoutes();
8 }
9
10 handleEmergency(type, severity, location, additionalData = {}) {
11 const emergency = {
12 id: this.generateEmergencyId(),
13 type, // 'containment-breach', 'power-failure', 'weather-emergency', 'medical'
14 severity, // 1-5
15 location,
16 timestamp: new Date(),
17 status: 'active',
18 data: additionalData
19 };
20
21 // Automatic procedures depending on type and severity
22 switch (type) {
23 case 'containment-breach':
24 this.handleContainmentBreach(emergency);
25 break;
26 case 'power-failure':
27 this.handlePowerFailure(emergency);
28 break;
29 case 'weather-emergency':
30 this.handleWeatherEmergency(emergency);
31 break;
32 case 'medical':
33 this.handleMedicalEmergency(emergency);
34 break;
35 default:
36 this.handleGenericEmergency(emergency);
37 }
38
39 return emergency.id;
40 }
41
42 handleContainmentBreach(emergency) {
43 const { location, data } = emergency;
44
45 // 1. Immediate lockdown of affected sector
46 this.park.systems.security.lockdownSector(location);
47
48 // 2. Activate evacuation protocol for visitors in the danger zone
49 const dangerZone = this.calculateDangerZone(location, data.dinosaurType);
50 this.park.systems.visitors.evacuateZone(dangerZone);
51
52 // 3. Deploy response team
53 this.deployResponseTeam('containment', location, data);
54
55 // 4. Notify all systems
56 this.park.eventBus.publish('emergency.containment-breach', {
57 location,
58 dangerZone,
59 estimatedContainmentTime: this.estimateContainmentTime(data.dinosaurType)
60 });
61
62 // 5. Automatic safety protocols
63 this.activateEmergencyProtocol('Code Red - Containment Breach');
64 }
65}Fonctionnalités avancées
1. Simulation en temps réel
1// Time simulation and life cycle system
2class TimeSimulation {
3 constructor() {
4 this.gameTime = new Date();
5 this.timeMultiplier = 1; // 1 = real time, 60 = 1 minute = 1 hour
6 this.isRunning = false;
7 this.events = [];
8 }
9
10 start() {
11 this.isRunning = true;
12 this.simulationLoop();
13 }
14
15 simulationLoop() {
16 if (!this.isRunning) return;
17
18 // Update simulation time
19 this.gameTime = new Date(this.gameTime.getTime() + (1000 * this.timeMultiplier));
20
21 // Check scheduled events
22 this.processScheduledEvents();
23
24 // Simulate natural processes
25 this.simulateNaturalProcesses();
26
27 // Next iteration in one second
28 setTimeout(() => this.simulationLoop(), 1000);
29 }
30
31 simulateNaturalProcesses() {
32 // Dinosaur aging
33 this.ageDinosaurs();
34
35 // Weather changes
36 this.updateWeather();
37
38 // Resource consumption (energy, food)
39 this.consumeResources();
40
41 // Natural dinosaur behaviors
42 this.simulateDinosaurBehavior();
43 }
44}2. Système d'IA pour les dinosaures
1// Dinosaur artificial intelligence
2class DinosaurAI {
3 constructor(dinosaur) {
4 this.dinosaur = dinosaur;
5 this.currentState = 'idle';
6 this.needs = {
7 hunger: 50,
8 thirst: 30,
9 social: 70,
10 territory: 80,
11 reproduction: 20
12 };
13 this.decisionTree = this.buildDecisionTree();
14 }
15
16 makeDecision() {
17 const context = this.gatherEnvironmentalData();
18 const urgentNeed = this.findMostUrgentNeed();
19
20 const decision = this.decisionTree.evaluate(urgentNeed, context);
21
22 return this.executeDecision(decision);
23 }
24
25 buildDecisionTree() {
26 return {
27 evaluate: (need, context) => {
28 if (need === 'hunger' && this.needs.hunger > 80) {
29 return this.findFood(context);
30 }
31
32 if (need === 'social' && this.dinosaur.behavior.socialBehavior === 'pack') {
33 return this.seekPackMembers(context);
34 }
35
36 if (need === 'territory' && context.intruders.length > 0) {
37 return this.defendTerritory(context.intruders);
38 }
39
40 return { action: 'wander', target: this.chooseRandomLocation() };
41 }
42 };
43 }
44}Critères d'évaluation
Ton projet sera évalué selon les critères suivants :
1. Fonctionnalité (30 %)
- Tous les systèmes requis fonctionnent correctement
- Gestion des erreurs et des cas limites
- Interface utilisateur intuitive
- Réactivité de l'application
2. Code et architecture (25 %)
- Code lisible et bien commenté
- Bon usage des patterns de conception
- Structure d'application modulaire
- Respect des bonnes pratiques JavaScript
3. Fonctionnalités avancées (20 %)
- Implémentation d'un système temps réel
- IA pour les dinosaures
- Gestion avancée des données
- Système de reporting et d'analyse
4. Créativité et innovation (15 %)
- Fonctionnalités et solutions originales
- Éléments UI/UX interactifs
- Extensions intéressantes du thème des dinosaures
- Implémentation de systèmes supplémentaires
5. Tests et documentation (10 %)
- Tests unitaires pour les fonctions clés
- Documentation de l'API et de l'architecture
- Manuel d'utilisation
- Commentaires dans le code
Défis bonus (points supplémentaires)
1. Système génétique avec une vraie logique d'ADN
Implémente un véritable système d'analyse de séquences d'ADN avec :
- des algorithmes de mutation génétique
- un système de croisement d'ADN entre espèces
- la prédiction des traits physiques à partir du génotype
- la simulation de l'hérédité des traits au fil des générations
2. Multijoueur et communication en temps réel
Ajoute des fonctionnalités multi-utilisateurs :
- WebSocket pour la communication en temps réel
- gestion partagée du parc par plusieurs utilisateurs
- chat entre gestionnaires du parc
- synchronisation de l'état entre les clients
3. API avancées et intégrations
Connecte-toi à des services externes :
- données météo réelles
- géolocalisation de l'utilisateur
- système de paiement pour les billets
- intégration de réservations dans un calendrier
4. Machine Learning et prédiction
Ajoute des éléments de machine learning :
- prédire le comportement des dinosaures
- optimiser les horaires de nourrissage
- analyser les habitudes des visiteurs
- prédire les pannes du système
Pour commencer
Étape 1 : Planification
- Dessine un schéma d'architecture du système
- Définis les principaux modules et leurs responsabilités
- Planifie la structure des données
- Établis la liste des fonctionnalités du MVP (Minimum Viable Product)
Étape 2 : Implémentation du MVP
- Crée la structure de base de l'application
- Implémente les classes principales (ParkCore, DataManager)
- Ajoute l'interface utilisateur de base
- Relie les modules via un bus d'événements
Étape 3 : Extension des fonctionnalités
- Ajoute chaque système l'un après l'autre
- Teste l'intégration entre les systèmes
- Implémente les fonctionnalités avancées
- Optimise les performances
Étape 4 : Finalisation
- Ajoute la gestion des erreurs
- Écris des tests
- Rédige la documentation
- Réalise les tests finaux
Conseils techniques
Structure des fichiers
1jurassic-park-system/
2├── index.html
3├── css/
4│ ├── main.css
5│ ├── dashboard.css
6│ └── components.css
7├── js/
8│ ├── core/
9│ │ ├── ParkCore.js
10│ │ ├── EventBus.js
11│ │ └── DataManager.js
12│ ├── systems/
13│ │ ├── SecuritySystem.js
14│ │ ├── DinosaurRegistry.js
15│ │ ├── VisitorManager.js
16│ │ └── GeneticLab.js
17│ ├── ui/
18│ │ ├── Dashboard.js
19│ │ ├── DinosaurPanel.js
20│ │ └── SecurityMonitor.js
21│ ├── utils/
22│ │ ├── helpers.js
23│ │ └── validators.js
24│ └── app.js
25├── data/
26│ ├── dinosaurs.json
27│ ├── species-data.json
28│ └── default-config.json
29└── tests/
30 ├── core.test.js
31 ├── systems.test.js
32 └── integration.test.jsExemple d'initialisation de l'application
1// app.js - main application file
2document.addEventListener('DOMContentLoaded', async () => {
3 try {
4 // Initialize system
5 const park = new ParkCore();
6 await park.initialize();
7
8 // Load data
9 const dataManager = new DataManager();
10 const savedState = await dataManager.loadParkState();
11
12 if (savedState) {
13 await park.loadState(savedState);
14 } else {
15 await park.initializeDefaultState();
16 }
17
18 // Initialize interface
19 const ui = new ParkInterface(park);
20 ui.render();
21
22 // Start simulation
23 const simulation = new TimeSimulation(park);
24 simulation.start();
25
26 console.log('Jurassic Park Management System started successfully!');
27
28 } catch (error) {
29 console.error('System initialization error:', error);
30 showErrorPage('Failed to start the park management system');
31 }
32});C'est ton grand défi de fin de module, jeune programmeur ! Il est temps de montrer ce que tu as appris et de créer quelque chose de vraiment exceptionnel. Le Dr Wu et tout le laboratoire génétique comptent sur toi !
Bonne chance pour bâtir l'avenir de Jurassic Park !
Code de cette leçon : index.js
1// Système d’IA des dinosaures
2// Exercice : implémente un système de besoins et de comportements
3
4class DinosaurAI {
5 constructor(name, species) {
6 this.name = name;
7 this.species = species;
8 this.needs = { hunger: 50, energy: 80, social: 60 };
9 this.behavior = "idle";
10 }
11
12 // Implémente les méthodes :
13 // updateNeeds() - met à jour les besoins (changements aléatoires)
14 // decideBehavior() - décide du comportement en fonction des besoins
15 // getStatus() - retourne l'état du dinosaure
16
17 updateNeeds() {
18 // Ton code ici
19 }
20
21 decideBehavior() {
22 // Ton code ici
23 }
24
25 getStatus() {
26 // Ton code ici
27 }
28}
29
30const rex = new DinosaurAI("Blue", "Velociraptor");
31console.log("IA du dinosaure :", rex.name, "Statut :", rex.behavior);Tu as repéré une erreur dans cette leçon ?