"W Parku Jurajskim wszystko musi działać według ścisłych protokołów," wyjaśnia Claire Dearing, dyrektor operacyjna. "Każdy pracownik ma jasno określony zakres obowiązków, a każdy system musi spełniać określone wymagania. Nie interesuje nas, jak dokładnie ochroniarz pilnuje wybiegu z raptorami - ważne, że wykonuje swoją pracę zgodnie z procedurami bezpieczeństwa."
W świecie TypeScript, interfejsy pełnią podobną rolę - definiują "kontrakt", który klasy muszą spełnić, bez określania, jak dokładnie mają to zrobić. W tym ćwiczeniu dowiesz się, jak projektować i implementować interfejsy, tworząc zaawansowany system zarządzania Parkiem Jurajskim.
Interfejs w TypeScript to struktura, która definiuje kształt obiektu - jakie właściwości i metody powinien posiadać, bez określania ich implementacji. Możesz myśleć o interfejsie jak o kontrakcie lub protokole, który klasa musi przestrzegać.
Przyjrzyjmy się podstawowej składni interfejsu:
1// Definicja interfejsu
2interface PracownikParku {
3 // Właściwości
4 id: string;
5 imię: string;
6 nazwisko: string;
7 poziomDostępu: number;
8
9 // Metody
10 zaloguj(): void;
11 wyloguj(): void;
12 sprawdźUprawnienia(wymaganyPoziom: number): boolean;
13}
14
15// Klasa implementująca interfejs
16class OchroniarzParku implements PracownikParku {
17 // Implementacja wszystkich wymaganych właściwości
18 id: string;
19 imię: string;
20 nazwisko: string;
21 poziomDostępu: number;
22 private aktywnyStatus: boolean = false;
23
24 constructor(id: string, imię: string, nazwisko: string) {
25 this.id = id;
26 this.imię = imię;
27 this.nazwisko = nazwisko;
28 this.poziomDostępu = 2; // Standardowy poziom dla ochroniarzy
29 }
30
31 // Implementacja wszystkich wymaganych metod
32 zaloguj(): void {
33 console.log(`Ochroniarz ${this.imię} ${this.nazwisko} zalogował się do systemu.`);
34 this.aktywnyStatus = true;
35 }
36
37 wyloguj(): void {
38 console.log(`Ochroniarz ${this.imię} ${this.nazwisko} wylogował się z systemu.`);
39 this.aktywnyStatus = false;
40 }
41
42 sprawdźUprawnienia(wymaganyPoziom: number): boolean {
43 return this.poziomDostępu >= wymaganyPoziom;
44 }
45
46 // Dodatkowe metody specyficzne dla ochroniarza
47 patrolujSektor(sektorId: string): void {
48 if (!this.aktywnyStatus) {
49 console.log("Błąd: Ochroniarz musi być zalogowany, aby patrolować sektor.");
50 return;
51 }
52
53 console.log(`Ochroniarz ${this.imię} ${this.nazwisko} patroluje sektor ${sektorId}.`);
54 }
55}
56
57// Inna klasa implementująca ten sam interfejs
58class NaukowiecParku implements PracownikParku {
59 id: string;
60 imię: string;
61 nazwisko: string;
62 poziomDostępu: number;
63 private specjalizacja: string;
64
65 constructor(id: string, imię: string, nazwisko: string, specjalizacja: string) {
66 this.id = id;
67 this.imię = imię;
68 this.nazwisko = nazwisko;
69 this.poziomDostępu = 4; // Wyższy poziom dostępu dla naukowców
70 this.specjalizacja = specjalizacja;
71 }
72
73 zaloguj(): void {
74 console.log(`Dr ${this.imię} ${this.nazwisko} zalogował się do systemu laboratorium.`);
75 }
76
77 wyloguj(): void {
78 console.log(`Dr ${this.imię} ${this.nazwisko} wylogował się z systemu laboratorium.`);
79 }
80
81 sprawdźUprawnienia(wymaganyPoziom: number): boolean {
82 // Naukowcy mają specjalne uprawnienia w laboratoriach
83 if (wymaganyPoziom === 3 && this.specjalizacja === "genetyka") {
84 return true;
85 }
86 return this.poziomDostępu >= wymaganyPoziom;
87 }
88
89 // Metoda specyficzna dla naukowca
90 przeprowadźBadanie(obiektBadań: string): void {
91 console.log(`Dr ${this.imię} ${this.nazwisko} prowadzi badania nad: ${obiektBadań}.`);
92 }
93}
94
95// Użycie klas implementujących interfejs
96const ochroniarz = new OchroniarzParku("SEC-001", "John", "Smith");
97const naukowiec = new NaukowiecParku("SCI-042", "Henry", "Wu", "genetyka");
98
99// Obie klasy implementują ten sam interfejs, więc możemy użyć tych samych metod
100ochroniarz.zaloguj();
101naukowiec.zaloguj();
102
103// Sprawdzenie uprawnień
104console.log(`Ochroniarz ma dostęp do strefy 2: ${ochroniarz.sprawdźUprawnienia(2)}`);
105console.log(`Naukowiec ma dostęp do strefy 3: ${naukowiec.sprawdźUprawnienia(3)}`);
106
107// Wywołanie metod specyficznych dla konkretnych klas
108ochroniarz.patrolujSektor("B-5");
109naukowiec.przeprowadźBadanie("DNA Velociraptora");W powyższym przykładzie:
PracownikParku określający, jakie właściwości i metody musi mieć każdy pracownikInterfejsy TypeScript pozwalają na bardziej zaawansowane definiowanie właściwości:
1interface SystemBezpieczeństwa {
2 // Wymagana właściwość
3 id: string;
4
5 // Właściwość tylko do odczytu - nie można jej modyfikować po inicjalizacji
6 readonly typSystemu: "monitoring" | "ogrodzenie" | "czujnikRuchu" | "alarm";
7
8 // Właściwość opcjonalna - może istnieć lub nie
9 opcjeZaawansowane?: Record<string, any>;
10
11 // Metody
12 aktywuj(): void;
13 deaktywuj(): void;
14 sprawdźStatus(): string;
15}
16
17class SystemOgrodzenia implements SystemBezpieczeństwa {
18 id: string;
19 readonly typSystemu: "monitoring" | "ogrodzenie" | "czujnikRuchu" | "alarm" = "ogrodzenie";
20 opcjeZaawansowane?: Record<string, any>; // Opcjonalna właściwość
21
22 private napięcie: number = 0;
23 private aktywny: boolean = false;
24
25 constructor(id: string, opcjeZaawansowane?: Record<string, any>) {
26 this.id = id;
27 if (opcjeZaawansowane) {
28 this.opcjeZaawansowane = opcjeZaawansowane;
29 }
30 }
31
32 aktywuj(): void {
33 this.aktywny = true;
34 this.napięcie = this.opcjeZaawansowane?.napięcieStartowe || 10000; // Użycie opcjonalnej właściwości
35 console.log(`System ogrodzenia ${this.id} aktywowany. Napięcie: ${this.napięcie}V`);
36 }
37
38 deaktywuj(): void {
39 this.aktywny = false;
40 this.napięcie = 0;
41 console.log(`System ogrodzenia ${this.id} deaktywowany.`);
42 }
43
44 sprawdźStatus(): string {
45 return `System ogrodzenia ${this.id}: ${this.aktywny ? "AKTYWNY" : "NIEAKTYWNY"}, Napięcie: ${this.napięcie}V`;
46 }
47
48 // Własna metoda, niewymagana przez interfejs
49 zwiększNapięcie(przyrost: number): void {
50 if (!this.aktywny) {
51 console.log("Nie można zmienić napięcia - system nieaktywny.");
52 return;
53 }
54
55 this.napięcie += przyrost;
56 console.log(`Zwiększono napięcie do ${this.napięcie}V.`);
57 }
58}
59
60// Użycie z opcjonalnymi właściwościami
61const ogrodzenieTRex = new SystemOgrodzenia("FNC-TR1", {
62 napięcieStartowe: 20000,
63 automatyczneRestarty: true
64});
65
66const ogrodzenieStandardowe = new SystemOgrodzenia("FNC-ST1");
67
68ogrodzenieTRex.aktywuj(); // Używa niestandardowego napięcia startowego
69ogrodzenieStandardowe.aktywuj(); // Używa domyślnego napięcia startowego
70
71// Error: Nie można przypisać do 'typSystemu' ponieważ jest to właściwość tylko do odczytu
72// ogrodzenieTRex.typSystemu = "alarm";W tym przykładzie:
readonly, której nie można modyfikować po inicjalizacjiopcjeZaawansowane (oznaczoną przez ?)Interfejsy, podobnie jak klasy, mogą rozszerzać inne interfejsy, dziedzicząc ich właściwości i metody:
1// Podstawowy interfejs dla wszystkich zwierząt
2interface Zwierzę {
3 id: string;
4 gatunek: string;
5 waga: number;
6 karma(): void;
7 monitoruj(): string;
8}
9
10// Rozszerzony interfejs specyficzny dla dinozaurów
11interface Dinozaur extends Zwierzę {
12 poziomNiebezpieczeństwa: number;
13 eraDinozaura: "trias" | "jura" | "kreda";
14 podajSpecjalnąDietę(): string;
15}
16
17// Jeszcze bardziej wyspecjalizowany interfejs
18interface DrapieżnyDinozaur extends Dinozaur {
19 siłaUgryzienia: number;
20 prędkość: number;
21 poluj(): void;
22}
23
24// Implementacja
25class TyranozaurRex implements DrapieżnyDinozaur {
26 // Właściwości z interfejsu Zwierzę
27 id: string;
28 gatunek: string = "Tyrannosaurus Rex";
29 waga: number;
30
31 // Właściwości z interfejsu Dinozaur
32 poziomNiebezpieczeństwa: number = 10;
33 eraDinozaura: "trias" | "jura" | "kreda" = "kreda";
34
35 // Właściwości z interfejsu DrapieżnyDinozaur
36 siłaUgryzienia: number;
37 prędkość: number;
38
39 // Własne właściwości
40 private wiek: number;
41 private ostatnieKarmienie: Date | null = null;
42
43 constructor(id: string, waga: number, wiek: number, siłaUgryzienia: number, prędkość: number) {
44 this.id = id;
45 this.waga = waga;
46 this.wiek = wiek;
47 this.siłaUgryzienia = siłaUgryzienia;
48 this.prędkość = prędkość;
49 }
50
51 // Implementacja metod z interfejsu Zwierzę
52 karma(): void {
53 this.ostatnieKarmienie = new Date();
54 console.log(`T-Rex ${this.id} został nakarmiony.`);
55 }
56
57 monitoruj(): string {
58 const statusKarmienia = this.ostatnieKarmienie
59 ? `Ostatnie karmienie: ${this.ostatnieKarmienie.toLocaleString()}`
60 : "Brak informacji o karmieniu";
61
62 return `T-Rex ${this.id}: Waga: ${this.waga}kg, Wiek: ${this.wiek} lat. ${statusKarmienia}`;
63 }
64
65 // Implementacja metody z interfejsu Dinozaur
66 podajSpecjalnąDietę(): string {
67 return "Świeże mięso ssaków, preferowana wołowina, 250kg dziennie.";
68 }
69
70 // Implementacja metody z interfejsu DrapieżnyDinozaur
71 poluj(): void {
72 console.log(`T-Rex ${this.id} poluje z prędkością ${this.prędkość} km/h i siłą ugryzienia ${this.siłaUgryzienia} PSI!`);
73 }
74}
75
76// Użycie
77const rex = new TyranozaurRex("TREX-01", 8000, 12, 12800, 30);
78rex.karma();
79console.log(rex.monitoruj());
80console.log(`Specjalna dieta: ${rex.podajSpecjalnąDietę()}`);
81rex.poluj();W tym przykładzie stworzyliśmy hierarchię interfejsów:
Zwierzę - podstawowy interfejs dla wszystkich zwierzątDinozaur - rozszerza Zwierzę o właściwości specyficzne dla dinozaurówDrapieżnyDinozaur - rozszerza Dinozaur o właściwości specyficzne dla drapieżnikówKlasa
TyranozaurRex implementuje najbardziej wyspecjalizowany interfejs DrapieżnyDinozaur, co oznacza, że musi dostarczyć wszystkie właściwości i metody ze wszystkich trzech interfejsów.TypeScript oferuje również aliasy typów (
type), które mają podobne możliwości co interfejsy, ale istnieją między nimi pewne różnice:1// Interfejs
2interface PomiarWybieg {
3 szerokość: number;
4 długość: number;
5 obliczPowierzchnię(): number;
6}
7
8// Typ (Type alias)
9type PomiarKlatka = {
10 szerokość: number;
11 wysokość: number;
12 głębokość: number;
13 obliczObjętość(): number;
14};
15
16// Rozszerzanie interfejsu
17interface PomiarWybiegZOgrodzeniem extends PomiarWybieg {
18 wysokośćOgrodzenia: number;
19 materiałOgrodzenia: string;
20}
21
22// "Rozszerzanie" typu poprzez przecięcie (intersection)
23type PomiarKlatkaWzmocniona = PomiarKlatka & {
24 materiałWzmocnienia: string;
25 maksymalneObciążenie: number;
26};
27
28// Implementacja interfejsu
29class WybiegRaptorów implements PomiarWybiegZOgrodzeniem {
30 szerokość: number;
31 długość: number;
32 wysokośćOgrodzenia: number;
33 materiałOgrodzenia: string;
34
35 constructor(szerokość: number, długość: number, wysokośćOgrodzenia: number) {
36 this.szerokość = szerokość;
37 this.długość = długość;
38 this.wysokośćOgrodzenia = wysokośćOgrodzenia;
39 this.materiałOgrodzenia = "Stal wzmocniona";
40 }
41
42 obliczPowierzchnię(): number {
43 return this.szerokość * this.długość;
44 }
45}
46
47// Implementacja typu (działa tak samo jak interfejs)
48class KlatkaTransportowa implements PomiarKlatkaWzmocniona {
49 szerokość: number;
50 wysokość: number;
51 głębokość: number;
52 materiałWzmocnienia: string;
53 maksymalneObciążenie: number;
54
55 constructor(
56 szerokość: number,
57 wysokość: number,
58 głębokość: number,
59 maksymalneObciążenie: number
60 ) {
61 this.szerokość = szerokość;
62 this.wysokość = wysokość;
63 this.głębokość = głębokość;
64 this.materiałWzmocnienia = "Kompozyt węglowy";
65 this.maksymalneObciążenie = maksymalneObciążenie;
66 }
67
68 obliczObjętość(): number {
69 return this.szerokość * this.wysokość * this.głębokość;
70 }
71}Główne różnice między interfejsami a typami:
Rozszerzalność:
1// Interfejs można rozszerzyć dodatkowymi deklaracjami
2interface DiagnozaDinozaura {
3 wynikBadania: string;
4}
5
6// Dodawanie nowych właściwości do istniejącego interfejsu
7interface DiagnozaDinozaura {
8 dataWykonania: Date;
9}
10
11// Teraz DiagnozaDinozaura ma obie właściwości!
12
13// Dla typów to nie zadziała:
14type OpisWybieg = {
15 id: string;
16};
17
18// Error: Duplicate identifier 'OpisWybieg'
19// type OpisWybieg = {
20// nazwa: string;
21// };Łączenie:
extends&Zaawansowane konstrukcje:
1// Zaawansowane typy, których nie można wyrazić interfejsami
2type StatusDinozaura = "zdrowy" | "chory" | "w trakcie leczenia" | "poddany kwarantannie";
3
4type IDDinozaura = string | number;
5
6type ZwierzęLubRoślina = Zwierzę | { rodzaj: string, wysokość: number };
7
8// Mapowane typy
9type Opcjonalny<T> = {
10 [P in keyof T]?: T[P];
11};
12
13// Użycie mapowanego typu z interfejsem
14type OpcjonalnyDinozaur = Opcjonalny<Dinozaur>;Interfejsy mogą również definiować kształt funkcji i konstrukcji klas:
1// Interfejs dla funkcji
2interface ProcesowanieZdjęcia {
3 (ścieżka: string, opcje?: { rozdzielczość?: number, filtr?: string }): Promise<string>;
4}
5
6// Implementacja funkcji zgodnej z interfejsem
7const procesorZdjęćDinozaurów: ProcesowanieZdjęcia = async (ścieżka, opcje) => {
8 console.log(`Przetwarzanie zdjęcia: ${ścieżka}`);
9 console.log(`Opcje: ${JSON.stringify(opcje || {})}`);
10
11 // Symulacja przetwarzania
12 await new Promise(resolve => setTimeout(resolve, 1000));
13
14 return `zoptymalizowane_${ścieżka}`;
15};
16
17// Wywołanie funkcji
18procesorZdjęćDinozaurów("trex.jpg", { rozdzielczość: 1200 })
19 .then(wynik => console.log(`Przetworzono: ${wynik}`));
20
21// Interfejs dla konstruktora klasy
22interface KonstruktorDinozaura {
23 new (id: string, gatunek: string, wiek: number): Zwierzę;
24}
25
26// Funkcja używająca konstruktora
27function utworzDinozaura(Konstruktor: KonstruktorDinozaura, id: string, gatunek: string, wiek: number): Zwierzę {
28 return new Konstruktor(id, gatunek, wiek);
29}
30
31// Klasa zgodna z interfejsem konstruktora
32class PrototypDinozaura implements Zwierzę {
33 id: string;
34 gatunek: string;
35 waga: number = 0;
36 private _wiek: number;
37
38 constructor(id: string, gatunek: string, wiek: number) {
39 this.id = id;
40 this.gatunek = gatunek;
41 this._wiek = wiek;
42
43 // Kalkulacja wagi na podstawie wieku
44 this.waga = wiek * 100; // Uproszczona kalkulacja
45 }
46
47 karma(): void {
48 console.log(`Karmienie prototypu ${this.gatunek}.`);
49 }
50
51 monitoruj(): string {
52 return `Monitoring prototypu ${this.gatunek} (ID: ${this.id}).`;
53 }
54}
55
56// Użycie funkcji fabrycznej
57const nowyDinozaur = utworzDinozaura(PrototypDinozaura, "PROTO-1", "Testosaurus", 5);
58console.log(nowyDinozaur.monitoruj());Interfejsy mogą również definiować typy indeksowane, które pozwalają na dynamiczny dostęp do właściwości:
1// Interfejs z indeksami
2interface BazaDanychZwierząt {
3 // Indeks typu string, wartości typu Zwierzę
4 [id: string]: Zwierzę;
5
6 // Możemy również dodać konkretne właściwości
7 liczbaZwierząt: number;
8 ostatniaAktualizacja: Date;
9}
10
11// Implementacja
12class RepositoryZwierząt implements BazaDanychZwierząt {
13 // Implementacja indeksu
14 [id: string]: Zwierzę | number | Date | Function;
15
16 liczbaZwierząt: number = 0;
17 ostatniaAktualizacja: Date = new Date();
18
19 // Musimy obsłużyć metody, ponieważ również są właściwościami
20 dodajZwierzę(zwierzę: Zwierzę): void {
21 this[zwierzę.id] = zwierzę;
22 this.liczbaZwierząt++;
23 this.ostatniaAktualizacja = new Date();
24 }
25
26 pobierzZwierzę(id: string): Zwierzę | undefined {
27 const zwierzę = this[id];
28 if (zwierzę && typeof zwierzę !== 'number' && !(zwierzę instanceof Date) && typeof zwierzę !== 'function') {
29 return zwierzę;
30 }
31 return undefined;
32 }
33}
34
35// Użycie
36const repoZwierząt = new RepositoryZwierząt();
37
38// Dodanie kilku zwierząt
39const triceratops = {
40 id: "TRIC-01",
41 gatunek: "Triceratops",
42 waga: 6000,
43 karma(): void { console.log("Karmienie Triceratopsa"); },
44 monitoruj(): string { return "Monitoring Triceratopsa"; }
45};
46
47const stegozaur = {
48 id: "STEG-01",
49 gatunek: "Stegosaurus",
50 waga: 5000,
51 karma(): void { console.log("Karmienie Stegozaura"); },
52 monitoruj(): string { return "Monitoring Stegozaura"; }
53};
54
55repoZwierząt.dodajZwierzę(triceratops);
56repoZwierząt.dodajZwierzę(stegozaur);
57
58// Dostęp przez indeksy
59const zwierzę = repoZwierząt.pobierzZwierzę("TRIC-01");
60if (zwierzę) {
61 console.log(`Znaleziono: ${zwierzę.gatunek}`);
62 zwierzę.karma();
63}
64
65console.log(`Liczba zwierząt w repozytorium: ${repoZwierząt.liczbaZwierząt}`);
66console.log(`Ostatnia aktualizacja: ${repoZwierząt.ostatniaAktualizacja.toLocaleString()}`);Klasa może implementować wiele interfejsów jednocześnie:
1// Interfejs dla możliwości monitorowania
2interface Monitorowalny {
3 rozpocznijMonitoring(): void;
4 zakończMonitoring(): void;
5 pobierzStatusMonitoringu(): string;
6}
7
8// Interfejs dla systemów alarmowych
9interface SystemAlarmowy {
10 uruchomAlarm(): void;
11 wyłączAlarm(): void;
12 czyAlarmAktywny: boolean;
13}
14
15// Interfejs dla systemów kontroli dostępu
16interface KontrolaDostępu {
17 sprawdźDostęp(poziomUprawnień: number): boolean;
18 zablokujDostęp(): void;
19 odblokujDostęp(): void;
20}
21
22// Klasa implementująca wszystkie trzy interfejsy
23class ZaawansowanySystemBezpieczeństwa implements Monitorowalny, SystemAlarmowy, KontrolaDostępu {
24 private id: string;
25 private aktywnyMonitoring: boolean = false;
26 czyAlarmAktywny: boolean = false;
27 private dostępZablokowany: boolean = false;
28 private minimalnyPoziomUprawnień: number;
29
30 constructor(id: string, minimalnyPoziomUprawnień: number = 3) {
31 this.id = id;
32 this.minimalnyPoziomUprawnień = minimalnyPoziomUprawnień;
33 }
34
35 // Implementacja Monitorowalny
36 rozpocznijMonitoring(): void {
37 this.aktywnyMonitoring = true;
38 console.log(`System ${this.id}: Rozpoczęto monitoring.`);
39 }
40
41 zakończMonitoring(): void {
42 this.aktywnyMonitoring = false;
43 console.log(`System ${this.id}: Zakończono monitoring.`);
44 }
45
46 pobierzStatusMonitoringu(): string {
47 return `System ${this.id}: Monitoring ${this.aktywnyMonitoring ? "aktywny" : "nieaktywny"}`;
48 }
49
50 // Implementacja SystemAlarmowy
51 uruchomAlarm(): void {
52 this.czyAlarmAktywny = true;
53 this.zablokujDostęp(); // Automatyczna blokada dostępu
54 console.log(`System ${this.id}: !!! ALARM URUCHOMIONY !!!`);
55 }
56
57 wyłączAlarm(): void {
58 this.czyAlarmAktywny = false;
59 console.log(`System ${this.id}: Alarm wyłączony.`);
60 }
61
62 // Implementacja KontrolaDostępu
63 sprawdźDostęp(poziomUprawnień: number): boolean {
64 if (this.dostępZablokowany) {
65 console.log(`System ${this.id}: Dostęp zablokowany dla wszystkich poziomów uprawnień.`);
66 return false;
67 }
68
69 const dostępPrzyznany = poziomUprawnień >= this.minimalnyPoziomUprawnień;
70 console.log(`System ${this.id}: Sprawdzanie dostępu dla poziomu ${poziomUprawnień}: ${dostępPrzyznany ? "PRZYZNANY" : "ODMOWA"}`);
71 return dostępPrzyznany;
72 }
73
74 zablokujDostęp(): void {
75 this.dostępZablokowany = true;
76 console.log(`System ${this.id}: Dostęp zablokowany.`);
77 }
78
79 odblokujDostęp(): void {
80 if (this.czyAlarmAktywny) {
81 console.log(`System ${this.id}: Nie można odblokować dostępu - alarm aktywny!`);
82 return;
83 }
84
85 this.dostępZablokowany = false;
86 console.log(`System ${this.id}: Dostęp odblokowany.`);
87 }
88
89 // Własna metoda łącząca funkcjonalności z różnych interfejsów
90 reagujNaWłamanie(): void {
91 console.log(`System ${this.id}: Wykryto próbę włamania!`);
92 this.rozpocznijMonitoring();
93 this.uruchomAlarm();
94 // Dostęp jest już zablokowany przez uruchomAlarm()
95 }
96}
97
98// Użycie klasy implementującej wiele interfejsów
99const systemZabezpieczeńLab = new ZaawansowanySystemBezpieczeństwa("SEC-LAB-01", 4);
100
101// Możemy użyć metod z różnych interfejsów
102systemZabezpieczeńLab.rozpocznijMonitoring();
103console.log(systemZabezpieczeńLab.pobierzStatusMonitoringu());
104
105// Sprawdzenie dostępu
106console.log(systemZabezpieczeńLab.sprawdźDostęp(3)); // Odmowa - wymagany poziom 4
107console.log(systemZabezpieczeńLab.sprawdźDostęp(5)); // Dostęp przyznany
108
109// Reakcja na włamanie
110systemZabezpieczeńLab.reagujNaWłamanie();
111
112// Próba odblokowania dostępu podczas alarmu
113systemZabezpieczeńLab.odblokujDostęp(); // Nie pozwoli odblokować
114
115// Wyłączenie alarmu i odblokowanie
116systemZabezpieczeńLab.wyłączAlarm();
117systemZabezpieczeńLab.odblokujDostęp();Co się stanie, gdy implementujemy dwa interfejsy z właściwościami o tych samych nazwach?
1// Dwa interfejsy z właściwościami o tej samej nazwie
2interface SystemA {
3 id: string;
4 status: string;
5 aktywuj(): void;
6}
7
8interface SystemB {
9 id: number; // Konflikt typu - string vs number
10 status: string; // Taki sam typ, brak konfliktu
11 aktywuj(kod: string): boolean; // Konflikt sygnatury
12}
13
14// Próba implementacji obu interfejsów
15// Ta implementacja spowoduje błąd kompilacji
16/*
17class ProblemowaSytuacja implements SystemA, SystemB {
18 id: string; // Nie może być jednocześnie string i number
19 status: string; // OK, ten sam typ w obu interfejsach
20
21 // Próba implementacji obu sygnatur aktywuj
22 aktywuj(kod?: string): boolean | void {
23 if (kod) {
24 console.log(`Aktywacja z kodem: ${kod}`);
25 return true;
26 } else {
27 console.log("Aktywacja bez kodu");
28 }
29 }
30}
31*/
32
33// Poprawna implementacja:
34// Musimy stworzyć typ, który jest kompatybilny z oboma interfejsami
35interface SystemKombinowany extends SystemA, SystemB {
36 // Rozwiązanie konfliktu id
37 id: string & number; // Musi być zarówno string jak i number (niemożliwe w praktyce)
38
39 // Status bez konfliktu
40 status: string;
41
42 // Rozwiązanie konfliktu metody
43 aktywuj(kod?: string): boolean | void;
44}
45
46// W praktyce, często niemożliwe jest zaimplementowanie obu interfejsów jednocześnie
47// W takim przypadku lepiej zmodyfikować jeden z interfejsów lub
48// stworzyć adapter, który przekierowuje wywołaniaJak rozwiązać problem niekompatybilnych interfejsów:
1// Lepsze podejście: Używanie kompozycji zamiast dziedziczenia
2class SystemDostępu {
3 private systemA: SystemAImplementacja;
4 private systemB: SystemBImplementacja;
5
6 constructor() {
7 this.systemA = new SystemAImplementacja("SYS-A");
8 this.systemB = new SystemBImplementacja(1001);
9 }
10
11 // Metody delegujące do odpowiednich implementacji
12 aktywujA(): void {
13 this.systemA.aktywuj();
14 }
15
16 aktywujB(kod: string): boolean {
17 return this.systemB.aktywuj(kod);
18 }
19
20 pobierzStatusA(): string {
21 return this.systemA.status;
22 }
23
24 pobierzStatusB(): string {
25 return this.systemB.status;
26 }
27}
28
29// Implementacje pojedynczych interfejsów
30class SystemAImplementacja implements SystemA {
31 id: string;
32 status: string = "nieaktywny";
33
34 constructor(id: string) {
35 this.id = id;
36 }
37
38 aktywuj(): void {
39 this.status = "aktywny";
40 console.log(`System A (${this.id}) aktywowany`);
41 }
42}
43
44class SystemBImplementacja implements SystemB {
45 id: number;
46 status: string = "offline";
47
48 constructor(id: number) {
49 this.id = id;
50 }
51
52 aktywuj(kod: string): boolean {
53 if (kod === "tajne-hasło") {
54 this.status = "online";
55 console.log(`System B (${this.id}) aktywowany z kodem`);
56 return true;
57 }
58 console.log(`System B (${this.id}) - błędny kod aktywacji`);
59 return false;
60 }
61}Poniżej znajduje się kompleksowy przykład wykorzystujący interfejsy do stworzenia systemu zarządzania dla Parku Jurajskiego:
1// Interfejs dla podstawowego bytu zarządzalnego
2interface PozycjaInwentarza {
3 readonly id: string;
4 nazwa: string;
5 kategoria: string;
6 dataDodania: Date;
7 ostatniaAktualizacja: Date;
8 status: "aktywny" | "nieaktywny" | "w naprawie" | "wycofany";
9
10 aktualizujStatus(nowyStatus: "aktywny" | "nieaktywny" | "w naprawie" | "wycofany"): void;
11 pobierzInformacje(): Record<string, any>;
12}
13
14// Interfejs dla obiektów, które mogą być śledzone
15interface Śledzone {
16 lokalizacjaBieżąca: { x: number, y: number } | null;
17 historiaLokalizacji: Array<{ czas: Date, x: number, y: number }>;
18
19 aktualizujLokalizację(x: number, y: number): void;
20 pobierzOstatniaLokalizację(): { czas: Date, x: number, y: number } | null;
21 pobierzTraséRuchu(odCzas: Date, doCzas?: Date): Array<{ czas: Date, x: number, y: number }>;
22}
23
24// Interfejs dla obiektów, które mogą być monitorowane
25interface Monitorowane {
26 parametryMonitorowane: Map<string, number | string | boolean>;
27 historiaPomiarów: Array<{ czas: Date, parametr: string, wartość: number | string | boolean }>;
28 statusMonitoringu: "włączony" | "wyłączony" | "ograniczony";
29
30 rozpocznijMonitoring(): void;
31 zakończMonitoring(): void;
32 dodajPomiar(parametr: string, wartość: number | string | boolean): void;
33 pobierzOstatniePomiary(liczba?: number): Array<{ czas: Date, parametr: string, wartość: number | string | boolean }>;
34}
35
36// Interfejs dla obiektów wymagających regularnej konserwacji
37interface Konserwowalny {
38 wymaganyPoziomKonserwacji: number; // 1-5
39 ostatniaKonserwacja: Date | null;
40 planowanaKonserwacja: Date | null;
41 historiaKonserwacji: Array<{ data: Date, opis: string, wykonawca: string }>;
42
43 zaplanujKonserwację(data: Date): void;
44 wykonajKonserwację(opis: string, wykonawca: string): void;
45 sprawdźStatusKonserwacji(): "wymagana" | "zaplanowana" | "aktualna";
46}
47
48// Interfejs dla systemów bezpieczeństwa
49interface SystemBezpieczeństwa {
50 poziomZagrożenia: 1 | 2 | 3 | 4 | 5;
51 strefaBezpieczeństwa: string;
52 osobyUprawnione: string[];
53
54 podnieśPoziomZagrożenia(): void;
55 obniżPoziomZagrożenia(): void;
56 sprawdźUprawnienia(idPracownika: string): boolean;
57 reagujNaZagrożenie(opis: string): void;
58}
59
60// Implementacja urządzenia monitorującego dinozaury
61class UrządzenieŚledząceT3000 implements PozycjaInwentarza, Śledzone, Monitorowane, Konserwowalny {
62 // PozycjaInwentarza
63 readonly id: string;
64 nazwa: string;
65 kategoria: string = "Urządzenie Śledzące";
66 dataDodania: Date;
67 ostatniaAktualizacja: Date;
68 status: "aktywny" | "nieaktywny" | "w naprawie" | "wycofany";
69
70 // Śledzone
71 lokalizacjaBieżąca: { x: number, y: number } | null = null;
72 historiaLokalizacji: Array<{ czas: Date, x: number, y: number }> = [];
73
74 // Monitorowane
75 parametryMonitorowane: Map<string, number | string | boolean> = new Map();
76 historiaPomiarów: Array<{ czas: Date, parametr: string, wartość: number | string | boolean }> = [];
77 statusMonitoringu: "włączony" | "wyłączony" | "ograniczony" = "wyłączony";
78
79 // Konserwowalny
80 wymaganyPoziomKonserwacji: number = 3;
81 ostatniaKonserwacja: Date | null = null;
82 planowanaKonserwacja: Date | null = null;
83 historiaKonserwacji: Array<{ data: Date, opis: string, wykonawca: string }> = [];
84
85 // Własne właściwości
86 private bateriaPoziom: number = 100; // w procentach
87 private przypisanyDinozaur: string | null = null;
88
89 constructor(id: string, nazwa: string) {
90 this.id = id;
91 this.nazwa = nazwa;
92 this.dataDodania = new Date();
93 this.ostatniaAktualizacja = new Date();
94 this.status = "nieaktywny";
95
96 // Inicjalizacja parametrów monitorowania
97 this.parametryMonitorowane.set("bateria", this.bateriaPoziom);
98 this.parametryMonitorowane.set("aktywny", false);
99 this.parametryMonitorowane.set("temperatura", 25.0);
100 }
101
102 // Implementacja metod PozycjaInwentarza
103 aktualizujStatus(nowyStatus: "aktywny" | "nieaktywny" | "w naprawie" | "wycofany"): void {
104 this.status = nowyStatus;
105 this.ostatniaAktualizacja = new Date();
106 console.log(`Urządzenie ${this.id}: Zmieniono status na ${nowyStatus}`);
107 }
108
109 pobierzInformacje(): Record<string, any> {
110 return {
111 id: this.id,
112 nazwa: this.nazwa,
113 kategoria: this.kategoria,
114 status: this.status,
115 dataDodania: this.dataDodania,
116 ostatniaAktualizacja: this.ostatniaAktualizacja,
117 bateriaPoziom: this.bateriaPoziom,
118 przypisanyDinozaur: this.przypisanyDinozaur
119 };
120 }
121
122 // Implementacja metod Śledzone
123 aktualizujLokalizację(x: number, y: number): void {
124 const czas = new Date();
125
126 // Aktualizacja bieżącej lokalizacji
127 this.lokalizacjaBieżąca = { x, y };
128
129 // Dodanie do historii
130 this.historiaLokalizacji.push({ czas, x, y });
131
132 // Symulacja zużycia baterii
133 this.zmniejszBaterię(0.1);
134
135 console.log(`Urządzenie ${this.id}: Zaktualizowano lokalizację na [x: ${x}, y: ${y}]`);
136 }
137
138 pobierzOstatniaLokalizację(): { czas: Date, x: number, y: number } | null {
139 if (this.historiaLokalizacji.length === 0) {
140 return null;
141 }
142
143 return this.historiaLokalizacji[this.historiaLokalizacji.length - 1];
144 }
145
146 pobierzTraséRuchu(odCzas: Date, doCzas: Date = new Date()): Array<{ czas: Date, x: number, y: number }> {
147 return this.historiaLokalizacji.filter(lok =>
148 lok.czas >= odCzas && lok.czas <= doCzas
149 );
150 }
151
152 // Implementacja metod Monitorowane
153 rozpocznijMonitoring(): void {
154 if (this.statusMonitoringu !== "włączony") {
155 this.statusMonitoringu = "włączony";
156 console.log(`Urządzenie ${this.id}: Rozpoczęto monitoring`);
157
158 // Symulacja pomiaru przy włączeniu monitoringu
159 this.dodajPomiar("aktywny", true);
160 }
161 }
162
163 zakończMonitoring(): void {
164 if (this.statusMonitoringu !== "wyłączony") {
165 this.statusMonitoringu = "wyłączony";
166 console.log(`Urządzenie ${this.id}: Zakończono monitoring`);
167
168 // Aktualizacja parametru aktywności
169 this.parametryMonitorowane.set("aktywny", false);
170 this.dodajPomiar("aktywny", false);
171 }
172 }
173
174 dodajPomiar(parametr: string, wartość: number | string | boolean): void {
175 const czas = new Date();
176
177 // Aktualizacja bieżącej wartości parametru
178 this.parametryMonitorowane.set(parametr, wartość);
179
180 // Dodanie do historii pomiarów
181 this.historiaPomiarów.push({ czas, parametr, wartość });
182
183 // Aktualizacja czasu ostatniej aktualizacji
184 this.ostatniaAktualizacja = czas;
185
186 console.log(`Urządzenie ${this.id}: Dodano pomiar ${parametr} = ${wartość}`);
187 }
188
189 pobierzOstatniePomiary(liczba: number = 10): Array<{ czas: Date, parametr: string, wartość: number | string | boolean }> {
190 // Zwraca określoną liczbę ostatnich pomiarów
191 return this.historiaPomiarów.slice(-liczba);
192 }
193
194 // Implementacja metod Konserwowalny
195 zaplanujKonserwację(data: Date): void {
196 this.planowanaKonserwacja = data;
197 console.log(`Urządzenie ${this.id}: Zaplanowano konserwację na ${data.toLocaleDateString()}`);
198 }
199
200 wykonajKonserwację(opis: string, wykonawca: string): void {
201 const data = new Date();
202
203 // Dodanie do historii konserwacji
204 this.historiaKonserwacji.push({ data, opis, wykonawca });
205
206 // Aktualizacja daty ostatniej konserwacji
207 this.ostatniaKonserwacja = data;
208
209 // Resetowanie planowanej konserwacji
210 this.planowanaKonserwacja = null;
211
212 // Aktualizacja statusu i baterii po konserwacji
213 this.aktualizujStatus("aktywny");
214 this.bateriaPoziom = 100;
215 this.parametryMonitorowane.set("bateria", this.bateriaPoziom);
216 this.dodajPomiar("bateria", this.bateriaPoziom);
217
218 console.log(`Urządzenie ${this.id}: Wykonano konserwację przez ${wykonawca}: ${opis}`);
219 }
220
221 sprawdźStatusKonserwacji(): "wymagana" | "zaplanowana" | "aktualna" {
222 // Brak wcześniejszej konserwacji - wymagana
223 if (!this.ostatniaKonserwacja) {
224 return "wymagana";
225 }
226
227 // Zaplanowana konserwacja w przyszłości
228 if (this.planowanaKonserwacja && this.planowanaKonserwacja > new Date()) {
229 return "zaplanowana";
230 }
231
232 // Sprawdzenie, czy minęło więcej niż 90 dni od ostatniej konserwacji
233 const dzisiaj = new Date();
234 const różnicaMilisekundy = dzisiaj.getTime() - this.ostatniaKonserwacja.getTime();
235 const różnicaDni = różnicaMilisekundy / (1000 * 60 * 60 * 24);
236
237 if (różnicaDni > 90 || this.bateriaPoziom < 20) {
238 return "wymagana";
239 }
240
241 return "aktualna";
242 }
243
244 // Własne metody
245 przypiszDinozaura(idDinozaura: string): void {
246 this.przypisanyDinozaur = idDinozaura;
247 this.dodajPomiar("przypisanyDinozaur", idDinozaura);
248 console.log(`Urządzenie ${this.id}: Przypisano do dinozaura ${idDinozaura}`);
249 }
250
251 private zmniejszBaterię(wartość: number): void {
252 this.bateriaPoziom = Math.max(0, this.bateriaPoziom - wartość);
253 this.parametryMonitorowane.set("bateria", this.bateriaPoziom);
254
255 // Jeśli bateria jest krytycznie niska - zmień status
256 if (this.bateriaPoziom < 5 && this.status === "aktywny") {
257 this.aktualizujStatus("nieaktywny");
258 console.log(`Urządzenie ${this.id}: Krytyczny poziom baterii! Urządzenie wyłączone.`);
259 }
260 }
261}
262
263// Implementacja systemu zabezpieczeń wybiegu dinozaurów
264class OgrodzenieElektryczne implements PozycjaInwentarza, SystemBezpieczeństwa, Konserwowalny {
265 // PozycjaInwentarza
266 readonly id: string;
267 nazwa: string;
268 kategoria: string = "Ogrodzenie Elektryczne";
269 dataDodania: Date;
270 ostatniaAktualizacja: Date;
271 status: "aktywny" | "nieaktywny" | "w naprawie" | "wycofany";
272
273 // SystemBezpieczeństwa
274 poziomZagrożenia: 1 | 2 | 3 | 4 | 5 = 1;
275 strefaBezpieczeństwa: string;
276 osobyUprawnione: string[] = [];
277
278 // Konserwowalny
279 wymaganyPoziomKonserwacji: number = 5; // Najwyższy poziom - kluczowe dla bezpieczeństwa
280 ostatniaKonserwacja: Date | null = null;
281 planowanaKonserwacja: Date | null = null;
282 historiaKonserwacji: Array<{ data: Date, opis: string, wykonawca: string }> = [];
283
284 // Własne właściwości
285 private napięcie: number; // w woltach
286 private długośćOgrodzenia: number; // w metrach
287 private czujnikiRuchu: boolean;
288
289 constructor(
290 id: string,
291 nazwa: string,
292 strefaBezpieczeństwa: string,
293 długośćOgrodzenia: number,
294 napięcie: number = 10000,
295 czujnikiRuchu: boolean = true
296 ) {
297 this.id = id;
298 this.nazwa = nazwa;
299 this.strefaBezpieczeństwa = strefaBezpieczeństwa;
300 this.długośćOgrodzenia = długośćOgrodzenia;
301 this.napięcie = napięcie;
302 this.czujnikiRuchu = czujnikiRuchu;
303
304 this.dataDodania = new Date();
305 this.ostatniaAktualizacja = new Date();
306 this.status = "nieaktywny";
307
308 // Dodanie administratorów systemu jako osób uprawnionych
309 this.osobyUprawnione.push("ADMIN-001", "SEC-CHIEF", "TECH-HEAD");
310 }
311
312 // Implementacja PozycjaInwentarza
313 aktualizujStatus(nowyStatus: "aktywny" | "nieaktywny" | "w naprawie" | "wycofany"): void {
314 // Jeśli przełączamy z nieaktywnego na aktywny
315 if (this.status !== "aktywny" && nowyStatus === "aktywny") {
316 // Sprawdź, czy konserwacja jest wymagana
317 if (this.sprawdźStatusKonserwacji() === "wymagana") {
318 console.log(`Ogrodzenie ${this.id}: OSTRZEŻENIE - Aktywacja bez wymaganej konserwacji!`);
319 }
320 }
321
322 this.status = nowyStatus;
323 this.ostatniaAktualizacja = new Date();
324
325 // Automatycznie dostosuj napięcie w zależności od statusu
326 if (nowyStatus === "aktywny") {
327 console.log(`Ogrodzenie ${this.id}: Aktywowano z napięciem ${this.napięcie}V`);
328 } else if (nowyStatus === "nieaktywny" || nowyStatus === "w naprawie") {
329 this.napięcie = 0;
330 console.log(`Ogrodzenie ${this.id}: Dezaktywowano - napięcie 0V`);
331 }
332 }
333
334 pobierzInformacje(): Record<string, any> {
335 return {
336 id: this.id,
337 nazwa: this.nazwa,
338 kategoria: this.kategoria,
339 status: this.status,
340 strefaBezpieczeństwa: this.strefaBezpieczeństwa,
341 długośćOgrodzenia: this.długośćOgrodzenia,
342 napięcie: this.napięcie,
343 czujnikiRuchu: this.czujnikiRuchu,
344 poziomZagrożenia: this.poziomZagrożenia
345 };
346 }
347
348 // Implementacja SystemBezpieczeństwa
349 podnieśPoziomZagrożenia(): void {
350 if (this.poziomZagrożenia < 5) {
351 this.poziomZagrożenia = (this.poziomZagrożenia + 1) as 1 | 2 | 3 | 4 | 5;
352
353 // Automatyczne zwiększenie napięcia
354 this.zwiększNapięcie(2000 * this.poziomZagrożenia);
355
356 console.log(`Ogrodzenie ${this.id}: Podniesiono poziom zagrożenia do ${this.poziomZagrożenia}. Nowe napięcie: ${this.napięcie}V`);
357 } else {
358 console.log(`Ogrodzenie ${this.id}: Poziom zagrożenia już na maksymalnym poziomie 5`);
359 }
360 }
361
362 obniżPoziomZagrożenia(): void {
363 if (this.poziomZagrożenia > 1) {
364 this.poziomZagrożenia = (this.poziomZagrożenia - 1) as 1 | 2 | 3 | 4 | 5;
365
366 // Automatyczne zmniejszenie napięcia (ale nadal aktywne)
367 const noweNapięcie = 10000 + (2000 * (this.poziomZagrożenia - 1));
368 this.napięcie = noweNapięcie;
369
370 console.log(`Ogrodzenie ${this.id}: Obniżono poziom zagrożenia do ${this.poziomZagrożenia}. Nowe napięcie: ${this.napięcie}V`);
371 } else {
372 console.log(`Ogrodzenie ${this.id}: Poziom zagrożenia już na minimalnym poziomie 1`);
373 }
374 }
375
376 sprawdźUprawnienia(idPracownika: string): boolean {
377 return this.osobyUprawnione.includes(idPracownika);
378 }
379
380 reagujNaZagrożenie(opis: string): void {
381 console.log(`Ogrodzenie ${this.id}: ALERT! ${opis}`);
382
383 // Maksymalny poziom zagrożenia
384 this.poziomZagrożenia = 5;
385
386 // Maksymalne napięcie
387 this.napięcie = 30000;
388
389 console.log(`Ogrodzenie ${this.id}: Poziom zagrożenia 5. Napięcie maksymalne: ${this.napięcie}V`);
390 }
391
392 // Implementacja Konserwowalny
393 zaplanujKonserwację(data: Date): void {
394 this.planowanaKonserwacja = data;
395 console.log(`Ogrodzenie ${this.id}: Zaplanowano konserwację na ${data.toLocaleDateString()}`);
396 }
397
398 wykonajKonserwację(opis: string, wykonawca: string): void {
399 const data = new Date();
400
401 // Zabezpieczenie - tymczasowa dezaktywacja ogrodzenia podczas konserwacji
402 const poprzedniStatus = this.status;
403 this.aktualizujStatus("w naprawie");
404
405 // Dodanie do historii konserwacji
406 this.historiaKonserwacji.push({ data, opis, wykonawca });
407
408 // Aktualizacja daty ostatniej konserwacji
409 this.ostatniaKonserwacja = data;
410
411 // Resetowanie planowanej konserwacji
412 this.planowanaKonserwacja = null;
413
414 console.log(`Ogrodzenie ${this.id}: Wykonano konserwację przez ${wykonawca}: ${opis}`);
415
416 // Przywrócenie poprzedniego statusu
417 this.aktualizujStatus(poprzedniStatus);
418 }
419
420 sprawdźStatusKonserwacji(): "wymagana" | "zaplanowana" | "aktualna" {
421 // Brak wcześniejszej konserwacji - wymagana
422 if (!this.ostatniaKonserwacja) {
423 return "wymagana";
424 }
425
426 // Zaplanowana konserwacja w przyszłości
427 if (this.planowanaKonserwacja && this.planowanaKonserwacja > new Date()) {
428 return "zaplanowana";
429 }
430
431 // Sprawdzenie, czy minęło więcej niż 30 dni od ostatniej konserwacji (krótszy okres dla ogrodzeń)
432 const dzisiaj = new Date();
433 const różnicaMilisekundy = dzisiaj.getTime() - this.ostatniaKonserwacja.getTime();
434 const różnicaDni = różnicaMilisekundy / (1000 * 60 * 60 * 24);
435
436 if (różnicaDni > 30) {
437 return "wymagana";
438 }
439
440 return "aktualna";
441 }
442
443 // Własne metody
444 dodajOsobęUprawnioną(idPracownika: string): void {
445 if (!this.osobyUprawnione.includes(idPracownika)) {
446 this.osobyUprawnione.push(idPracownika);
447 console.log(`Ogrodzenie ${this.id}: Dodano uprawnienia dla pracownika ${idPracownika}`);
448 }
449 }
450
451 usuńOsobęUprawnioną(idPracownika: string): void {
452 const indeks = this.osobyUprawnione.indexOf(idPracownika);
453 if (indeks !== -1) {
454 this.osobyUprawnione.splice(indeks, 1);
455 console.log(`Ogrodzenie ${this.id}: Usunięto uprawnienia dla pracownika ${idPracownika}`);
456 }
457 }
458
459 zwiększNapięcie(wartość: number): void {
460 if (this.status !== "aktywny") {
461 console.log(`Ogrodzenie ${this.id}: Nie można zmienić napięcia - ogrodzenie nie jest aktywne`);
462 return;
463 }
464
465 this.napięcie += wartość;
466 console.log(`Ogrodzenie ${this.id}: Zwiększono napięcie do ${this.napięcie}V`);
467 }
468
469 zmniejszNapięcie(wartość: number): void {
470 if (this.status !== "aktywny") {
471 console.log(`Ogrodzenie ${this.id}: Nie można zmienić napięcia - ogrodzenie nie jest aktywne`);
472 return;
473 }
474
475 this.napięcie = Math.max(0, this.napięcie - wartość);
476 console.log(`Ogrodzenie ${this.id}: Zmniejszono napięcie do ${this.napięcie}V`);
477 }
478}
479
480// Demonstrujemy użycie naszych implementacji
481function demonstrujSystemParku() {
482 console.log("=== DEMONSTRACJA SYSTEMU ZARZĄDZANIA PARKIEM JURAJSKIM ===");
483
484 // Utworzenie urządzenia śledzącego
485 console.log("
486--- Inicjalizacja urządzenia śledzącego ---");
487 const urządzenieŚledzące = new UrządzenieŚledząceT3000("TRACK-001", "Lokalizator T-Rex #1");
488 urządzenieŚledzące.aktualizujStatus("aktywny");
489 urządzenieŚledzące.rozpocznijMonitoring();
490 urządzenieŚledzące.przypiszDinozaura("TREX-001");
491
492 // Symulacja śledzenia lokalizacji
493 urządzenieŚledzące.aktualizujLokalizację(135.42, 86.21);
494 urządzenieŚledzące.aktualizujLokalizację(135.50, 86.35);
495 urządzenieŚledzące.aktualizujLokalizację(135.62, 86.40);
496
497 // Utworzenie ogrodzenia
498 console.log("
499--- Inicjalizacja ogrodzenia ---");
500 const ogrodzenie = new OgrodzenieElektryczne(
501 "FENCE-002",
502 "Ogrodzenie wybiegu T-Rex",
503 "T-REX-A",
504 1200, // 1200 metrów długości
505 15000, // 15000V
506 true // z czujnikami ruchu
507 );
508
509 // Dodanie uprawnień dla pracownika
510 ogrodzenie.dodajOsobęUprawnioną("EMP-047"); // Owen Grady
511
512 // Aktywacja ogrodzenia
513 ogrodzenie.aktualizujStatus("aktywny");
514
515 // Przeprowadzenie konserwacji urządzenia
516 console.log("
517--- Konserwacja urządzenia ---");
518 urządzenieŚledzące.zaplanujKonserwację(new Date("2023-06-15"));
519 urządzenieŚledzące.wykonajKonserwację("Wymiana baterii i kalibracja GPS", "Tech Ivan");
520
521 // Symulacja alarmu
522 console.log("
523--- Symulacja incydentu ---");
524 console.log("T-Rex próbuje przedostać się przez ogrodzenie!");
525
526 // Urządzenie śledzące rejestruje gwałtowny ruch
527 urządzenieŚledzące.aktualizujLokalizację(135.90, 86.70);
528 urządzenieŚledzące.aktualizujLokalizację(136.10, 86.90);
529 urządzenieŚledzące.dodajPomiar("przyspieszenie", 12.5);
530
531 // Ogrodzenie reaguje na zagrożenie
532 ogrodzenie.reagujNaZagrożenie("Wykryto próbę ucieczki T-Rexa");
533
534 // Sprawdzenia statusu po incydencie
535 console.log("
536--- Raport po incydencie ---");
537 console.log("Ostatnia lokalizacja dinozaura:", urządzenieŚledzące.pobierzOstatniaLokalizację());
538 console.log("Status ogrodzenia:", ogrodzenie.pobierzInformacje());
539
540 // Powrót do normalnego trybu
541 console.log("
542--- Normalizacja sytuacji ---");
543 ogrodzenie.obniżPoziomZagrożenia();
544 ogrodzenie.obniżPoziomZagrożenia();
545
546 console.log("
547=== KONIEC DEMONSTRACJI ===");
548}
549
550// Uruchomienie demonstracji
551demonstrujSystemParku();W tym ćwiczeniu poznaliśmy interfejsy TypeScript - potężne narzędzie do definiowania kontraktów i tworzenia spójnych struktur w kodzie.
Najważniejsze cechy interfejsów:
Jak Claire Dearing podsumowałaby: "W Parku Jurajskim, podobnie jak w dobrej architekturze oprogramowania, każdy ma swoją rolę i obowiązki. Interfejsy pozwalają nam jasno zdefiniować te role, zapewniając, że wszystkie systemy dobrze ze sobą współpracują - bez niespodzianek. A uwierzcie mi, niespodzianki w parku pełnym dinozaurów to ostatnia rzecz, jakiej potrzebujemy."