Cours JavaScript et TypeScript · Module 9: Design patterns et architecture

Projet final : système de gestion de Jurassic Park

11 min de lecture
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

  1. Dessine un schéma d'architecture du système
  2. Définis les principaux modules et leurs responsabilités
  3. Planifie la structure des données
  4. Établis la liste des fonctionnalités du MVP (Minimum Viable Product)

Étape 2 : Implémentation du MVP

  1. Crée la structure de base de l'application
  2. Implémente les classes principales (ParkCore, DataManager)
  3. Ajoute l'interface utilisateur de base
  4. Relie les modules via un bus d'événements

Étape 3 : Extension des fonctionnalités

  1. Ajoute chaque système l'un après l'autre
  2. Teste l'intégration entre les systèmes
  3. Implémente les fonctionnalités avancées
  4. Optimise les performances

Étape 4 : Finalisation

  1. Ajoute la gestion des erreurs
  2. Écris des tests
  3. Rédige la documentation
  4. 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.js

Exemple 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 ?

Articles utiles