Kurs JavaScript i TypeScript · Moduł 9: Wzorce projektowe i architektura
Projekt końcowy: System zarządzania Parkiem Jurajskim
W tej lekcji8
Witaj w laboratorium genetycznym Parku Jurajskiego! Po długiej podróży przez świat JavaScript, czas na wyzwanie wieńczące ten moduł. Dr Henry Wu, główny genetyk parku, powierza Ci stworzenie kompleksowego systemu zarządzania, który będzie nadzorować wszystkie aspekty działania parku - od monitorowania dinozaurów po zarządzanie bezpieczeństwem odwiedzających.
Cel projektu
Twoim zadaniem jest stworzenie zaawansowanej aplikacji JavaScript, która zintegruje wszystkie poznane przez Ciebie technologie w jeden spójny system. To będzie Twój magnum opus - dowód na to, że opanowałeś sztukę programowania w JavaScript.
Wymagania funkcjonalne systemu
1. System zarządzania dinozaurami
Twój system musi umożliwiać:
1// Przykład struktury danych dinozaura
2const dinosaurSpecies = {
3 id: 'trex-001',
4 name: 'Tyrannosaurus Rex',
5 species: 'T-Rex',
6 genome: {
7 dnaSequence: '4A7B...9F2E', // Sekwencja DNA
8 modifications: ['enhanced-strength', 'reduced-aggression'],
9 purity: 0.92, // 92% oryginalne DNA
10 gapsFilled: ['amphibian-dna', 'bird-dna']
11 },
12 physicalTraits: {
13 height: 5.6, // metry
14 weight: 8500, // kg
15 length: 12.8, // metry
16 age: 4, // lata
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. System monitorowania bezpieczeństwa
1// Struktura systemu bezpieczeństwa
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 // napięcie ogrodzenia w woltach
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(), // ID karty -> poziom dostępu
29 restrictedAreas: ['genetic-lab', 'control-room', 'medical-bay'],
30 emergencyOverride: false
31 }
32};3. System zarządzania odwiedzającymi
1// System zarządzania odwiedzającymi
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. System laboratorium genetycznego
1// System laboratorium genetycznego
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}Wymagania techniczne
1. Architektura aplikacji
Twoja aplikacja musi wykorzystywać:
- Module Pattern lub ES6 Modules do organizacji kodu
- Observer Pattern do komunikacji między komponentami
- Factory Pattern do tworzenia obiektów dinozaurów i odwiedzających
- Singleton Pattern dla systemów krytycznych (bezpieczeństwo, główna baza danych)
1// Przykład architektury modularnej
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 // Komunikacja między systemami przez 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. Zarządzanie danymi
1// System zarządzania danymi z localStorage i 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 // Zapisz do cache
12 this.cache.set(dinosaur.id, dinosaur);
13
14 // Zapisz do localStorage jako backup
15 localStorage.setItem(`dino_${dinosaur.id}`, JSON.stringify(dinosaur));
16
17 // Zapisz do IndexedDB dla większych danych
18 await this.localDB.store('dinosaurs', dinosaur);
19
20 // Dodaj do kolejki synchronizacji z serwerem
21 this.queueForSync('dinosaurs', dinosaur.id, 'update');
22
23 } catch (error) {
24 console.error('Błąd zapisywania danych dinozaura:', error);
25 throw new DataError('Nie udało się zapisać danych dinozaura');
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('Błąd ładowania stanu parku:', error);
44 return this.getEmergencyFallbackState();
45 }
46 }
47}3. Interfejs użytkownika
Twój system musi posiadać:
- Dashboard główny z przeglądem wszystkich systemów
- Panel dinozaurów z listą, szczegółami i możliwością zarządzania
- Monitor bezpieczeństwa z alertami i statusem systemów
- Panel odwiedzających z listą aktywnych wycieczek
- Laboratorium genetyczne z narzędziami do analizy DNA
- System raportowania z wykresami i statystykami
1// Przykład interfejsu użytkownika
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>Zarządzanie dinozaurami</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>Wiek:</label>
52 <span>${dino.physicalTraits.age} lat</span>
53 </div>
54 <div class="stat">
55 <label>Zdrowie:</label>
56 <span>${dino.physicalTraits.healthStatus}</span>
57 </div>
58 <div class="stat">
59 <label>Lokalizacja:</label>
60 <span>${dino.habitat.enclosureId}</span>
61 </div>
62 </div>
63
64 <div class="dino-actions">
65 <button data-action="feed">Nakarm</button>
66 <button data-action="checkup">Kontrola</button>
67 <button data-action="relocate">Przenieś</button>
68 </div>
69 </div>
70 `).join('')}
71 </div>
72
73 <button class="add-dinosaur-btn" data-action="add-dinosaur">
74 + Dodaj nowego dinozaura
75 </button>
76 </div>
77 `;
78 }
79
80 bindEvents() {
81 // Jeden listener na kontenerze (delegacja zdarzeń): w atrybucie onclick "this" wskazywałby przycisk, a nie 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. Obsługa sytuacji kryzysowych
1// System zarządzania kryzysowego
2class EmergencyResponseSystem {
3 constructor(parkCore) {
4 this.park = parkCore;
5 this.emergencyLevel = 0; // 0-5, gdzie 5 to najwyższy
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 // Automatyczne procedury w zależności od typu i wagi zagrożenia
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. Natychmiastowe zamknięcie dotkniętego sektora
46 this.park.systems.security.lockdownSector(location);
47
48 // 2. Aktywacja protokołu ewakuacji dla odwiedzających w zagrożonej strefie
49 const dangerZone = this.calculateDangerZone(location, data.dinosaurType);
50 this.park.systems.visitors.evacuateZone(dangerZone);
51
52 // 3. Wysłanie zespołu ratunkowego
53 this.deployResponseTeam('containment', location, data);
54
55 // 4. Informowanie wszystkich systemów
56 this.park.eventBus.publish('emergency.containment-breach', {
57 location,
58 dangerZone,
59 estimatedContainmentTime: this.estimateContainmentTime(data.dinosaurType)
60 });
61
62 // 5. Automatyczne protokoły bezpieczeństwa
63 this.activateEmergencyProtocol('Code Red - Containment Breach');
64 }
65}Funkcje zaawansowane
1. Symulacja czasu rzeczywistego
1// System symulacji czasu i cykli życiowych
2class TimeSimulation {
3 constructor() {
4 this.gameTime = new Date();
5 this.timeMultiplier = 1; // 1 = czas rzeczywisty, 60 = 1 minuta = 1 godzina
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 // Aktualizuj czas symulacji
19 this.gameTime = new Date(this.gameTime.getTime() + (1000 * this.timeMultiplier));
20
21 // Sprawdź zaplanowane wydarzenia
22 this.processScheduledEvents();
23
24 // Symuluj naturalne procesy
25 this.simulateNaturalProcesses();
26
27 // Następna iteracja za sekundę
28 setTimeout(() => this.simulationLoop(), 1000);
29 }
30
31 simulateNaturalProcesses() {
32 // Starzenie się dinozaurów
33 this.ageDinosaurs();
34
35 // Zmiany pogody
36 this.updateWeather();
37
38 // Zużycie zasobów (energia, pożywienie)
39 this.consumeResources();
40
41 // Naturalne zachowania dinozaurów
42 this.simulateDinosaurBehavior();
43 }
44}2. System AI dla dinozaurów
1// Sztuczna inteligencja dinozaurów
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}Kryteria oceny projektu
Twój projekt będzie oceniany według następujących kryteriów:
1. Funkcjonalność (30%)
- Wszystkie wymagane systemy działają poprawnie
- Obsługa błędów i sytuacji wyjątkowych
- Intuicyjny interfejs użytkownika
- Responsywność aplikacji
2. Kod i architektura (25%)
- Czytelny, dobrze skomentowany kod
- Prawidłowe użycie wzorców projektowych
- Modularna struktura aplikacji
- Przestrzeganie dobrych praktyk JavaScript
3. Funkcje zaawansowane (20%)
- Implementacja systemu czasu rzeczywistego
- AI dla dinozaurów
- Zaawansowane zarządzanie danymi
- System raportowania i analityki
4. Kreatywność i innowacyjność (15%)
- Unikalne funkcje i rozwiązania
- Interaktywne elementy UI/UX
- Ciekawe rozszerzenia tematu dinozaurów
- Implementacja dodatkowych systemów
5. Testowanie i dokumentacja (10%)
- Testy jednostkowe kluczowych funkcji
- Dokumentacja API i architektury
- Instrukcja obsługi dla użytkowników
- Komentarze w kodzie
Dodatkowe wyzwania (punkty bonusowe)
1. System genetyczny z prawdziwą logiką DNA
Zaimplementuj rzeczywisty system analizy sekwencji DNA z:
- Algorytmami mutacji genetycznych
- Systemem krzyżowania DNA różnych gatunków
- Przewidywaniem cech fizycznych na podstawie genotypu
- Symulacją dziedziczenia cech przez pokolenia
2. Multiplayer i komunikacja w czasie rzeczywistym
Dodaj funkcjonalność wieloużytkownikową:
- WebSocket dla komunikacji w czasie rzeczywistym
- Wspólne zarządzanie parkiem przez wielu użytkowników
- Chat między zarządzającymi parkiem
- Synchronizacja stanów między klientami
3. Zaawansowane API i integracje
Połącz z zewnętrznymi serwisami:
- Prawdziwe dane pogodowe
- Geolokalizacja użytkowników
- System płatności dla biletów
- Integracja z kalendarzem rezerwacji
4. Machine Learning i predykcja
Dodaj elementy uczenia maszynowego:
- Przewidywanie zachowań dinozaurów
- Optymalizacja harmonogramów karmienia
- Analiza wzorców odwiedzających
- Predykcja awarii systemów
Rozpoczęcie projektu
Krok 1: Planowanie
- Narysuj diagram architektury systemu
- Określ główne moduły i ich odpowiedzialności
- Zaplanuj strukturę danych
- Stwórz listę funkcjonalności MVP (Minimum Viable Product)
Krok 2: Implementacja MVP
- Stwórz podstawową strukturę aplikacji
- Zaimplementuj główne klasy (ParkCore, DataManager)
- Dodaj podstawowy interfejs użytkownika
- Połącz moduły przez event bus
Krok 3: Rozszerzanie funkcjonalności
- Dodaj każdy system pojedynczo
- Testuj integrację między systemami
- Implementuj zaawansowane funkcje
- Optymalizuj wydajność
Krok 4: Finalizacja
- Dodaj obsługę błędów
- Napisz testy
- Stwórz dokumentację
- Przeprowadź testy końcowe
Wskazówki techniczne
Struktura plików
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.jsPrzykład inicjalizacji aplikacji
1// app.js - główny plik aplikacji
2document.addEventListener('DOMContentLoaded', async () => {
3 try {
4 // Inicjalizacja systemu
5 const park = new ParkCore();
6 await park.initialize();
7
8 // Ładowanie danych
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 // Inicjalizacja interfejsu
19 const ui = new ParkInterface(park);
20 ui.render();
21
22 // Start symulacji
23 const simulation = new TimeSimulation(park);
24 simulation.start();
25
26 console.log('Jurassic Park Management System uruchomiony pomyślnie!');
27
28 } catch (error) {
29 console.error('Błąd inicjalizacji systemu:', error);
30 showErrorPage('Nie udało się uruchomić systemu zarządzania parkiem');
31 }
32});To jest Twoje wielkie wyzwanie na koniec modułu, młody programisto! Czas pokazać, czego się nauczyłeś, i stworzyć coś naprawdę wyjątkowego. Dr Wu i całe laboratorium genetyczne liczą na Ciebie!
Powodzenia w budowie przyszłości Parku Jurajskiego!
Kod do tej lekcji: index.js
1// System AI Dinozaurów
2// Ćwiczenie: Zaimplementuj system potrzeb i zachowań
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 // Zaimplementuj metody:
13 // updateNeeds() - zaktualizuj potrzeby (losowe zmiany)
14 // decideBehavior() - podejmij decyzję o zachowaniu na podstawie potrzeb
15 // getStatus() - zwróć status dinozaura
16
17 updateNeeds() {
18 // Twój kod tutaj
19 }
20
21 decideBehavior() {
22 // Twój kod tutaj
23 }
24
25 getStatus() {
26 // Twój kod tutaj
27 }
28}
29
30const rex = new DinosaurAI("Blue", "Velociraptor");
31console.log("AI dinozaura:", rex.name, "Status:", rex.behavior);Widzisz błąd w tej lekcji?