najważniejsze podobieństwa
omówię:
- klasy
- silne typowanie
- enumy
- interfejsy
- wstrzykiwanie zależności
- kolekcje
klasy
Klasa to jedna z podstawowych konstrukcji jeżeli chodzi o Javę i TS.
Jakie wspólne elementy posiada klasa w TS które znasz z Javy?
– konstruktor
– zmienne
– metody/funkcje
– operatory zasięgu
Spójrz na poniższy kod.
export class Car {
public brand: string;
public model: string;
public engineType: EngineType;
public type: CarType;
constructor(brand: string,
model: string,
engineType: EngineType,
type: CarType) {
this.brand = brand;
this.model = model;
this.engineType = engineType;
this.type = type;
}
public getBrand(): string {
return this.brand;
}
public setBrand(brand: string): void {
this.brand = brand;
}
public getModel(): string {
return this.model;
}
public setModel(model: string): void {
this.model = model;
}
public getEngineType(): EngineType {
return this.engineType;
}
public setEngineType(engineType: EngineType): void {
this.engineType = engineType;
}
public getType(): CarType {
return this.type;
}
public setType(type: CarType): void {
this.type = type;
}
}
Tak mogłaby wyglądać klasa, która reprezentuje obiekt samochodu. Powyższy kod będzie działał poprawnie natomiast nie jest najbardziej optymalny oraz zgodny z powszechnie panującymi standardami.
Obecnie programowanie idzie w kierunku szybszego pisania oraz wszelkiego sugar syntaxu. W Javie możesz zastosować Lombok’a i zapewne wiele razy z niego korzystałeś. To co uzyskujesz dzięki tej bibliotece to m.in. mniej kodu boilerplate. Dzięki takiemu podejściu możesz się skupić na tym jak dany kod wpływa na rozwiązanie biznesowe a nie na pisaniu getterów i setterów. Type Script dostarcza takiej możliwości bez potrzeby dodawania zewnętrznych bibliotek.
Ważną różnicą między Javą a Type Scriptem jest dostęp do zmiennych w klasie. Type Script dopuszcza odwołanie do zmiennych obiektu poprzez nazwę zmiennej np. this.car.model.
Spójrz poniżej jak uprościć klasę Car
export class Car {
constructor(public brand: string,
public model: string,
public engineType: string,
public type: string) {}
}
Jak widzisz klasa po zmianach wygląda jak ta w Javie gdy dodamy do niej adnotacje Lombokowe.
Ważne aby zmienne w konstruktorze były oznaczone jako public. Dzięki temu będziesz mógł się do nich odnieść za pomocą nazwy.
Użycie klasy car.model.ts w app.component.ts
import { Component } from '@angular/core';
import { Car } from './car/car.model';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public car: Car;
public car1: Car;
constructor() {
this.car = new Car('Audi', 'A6', 'benzyna', 'sedan');
this.car1 = new Car('Mercedes', 'E', 'diesel', 'coupe');
const carToString =
`${this.car.brand}, ${this.car.model}, ${this.car.type}, ${this.car.engineType}`
}
}
Do zapamiętania:
– w Type Scripcie aby dostać się do zmiennych nie potrzebujesz getterów i setterów, aczkolwiek gettery i settery także występują.
– w Type Scripcie klasa może posiadać tylko jeden konstruktor.
enumy
Enumy to kolejna przydatna konstrukcja. W TS enumy są nieco uproszczone względem Javy.
Spójrz na poniższy przykład.
export enum EngineType {
DIESEL,
GASOLINE,
}
Pozornie wszystko wydaje się niemal identyczne jak w Javie. Jeżeli spróbujesz wyświetlić wartość jaka kryje się w poszczególnych elementach to DIESEL będzie miało wartość „0”, natomiast GASOLINE wartość „1”. Domyślnie przypisywane są numery od 0 do n. Poprawnie jest nadać wartość elementowi
export enum EngineType {
DIESEL = 'DIESEL',
GASOLINE = 'GASOLINE'
}
W tym momencie wartości będą takie jak przypisałeś po prawej stronie znaku równości.
Jeżeli chodzi o enumy to nie ma tutaj za wiele do dodania.
interfejsy
Interfejsy są bardzo ważną konstrukcją zarówno w Javie jak i Type Scriptcie. Pewne właściwości są wspólne jak deklaracje metod oraz implementacja interfejsu w klasie. Istnieją także różnice jak m.in. odpowiedź z backendu jest mapowana właśnie na interfejs a nie na klasę.
Proces mapowania oraz pobierania danych z backendu prezentuję w materiałach w kroku: Praktyka.
Spójrz na wykorzystanie interfejsu czyli dodanie definicji metody oraz jej nadpisanie. Pokażę Ci to na klasycznym przykładzie zwierząt.
Wszystkie pliki stwórz w katalogu app.
Dodaj plik pet.interface.ts
export interface Pet {
sound(): string;
}
dodaj także cat.ts
import {Pet} from './pet.interface';
export class Cat implements Pet {
sound(): string {
return 'Miau Miau';
}
}
dog.ts
import {Pet} from './pet.interface';
export class Dog implements Pet {
sound(): string {
return 'Hau Hau';
}
}
w pliku app.component.ts dodaj poniższy kod
import {Component} from '@angular/core';
import {Pet} from './pet.interface';
import {Dog} from './dog';
import {Cat} from './cat';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
public pets: Pet[] = [new Dog(), new Cat()];
}
oraz w app.component.html
<div *ngFor="let pet of pets">
{{pet.sound()}}
</div>
Powinieneś zobaczyć następujący widok.
kolekcje
Zanim przejdziemy do wtrzykiwania zależności oraz zanim wytłumaczę Ci czym jest serwis, omówię kolekcję. Zaczniemy od kolekcji ponieważ w kolejnym punkcie wykorzystamy właśnie mapę oraz listę.
Kolekcje nie są aż tak rozbudowane jak w Javie. W Type Script są dostępne trzy rodzaje: lista, mapa oraz set.
Spójrz na poniższy kod
import { Injectable } from '@angular/core';
@Injectable(
{
providedIn: 'root'
}
)
export class CarService {
private carsWithoutDiscount = ['A8', 'Seria 7', 'Klasa S'];
private carsDiscount: Map<string, number> = new Map([
['A6', 20],
['Klasa E', 15],
['Seria 5', 17],
]);
getCarDiscount(carModel: string): number {
return this.carsDiscount.get(carModel);
}
getCarsWithoutDiscount(): string[] {
return this.carsWithoutDiscount;
}
}
W Type Scripcie lista oraz tablica są ze sobą tożsame. Jak widzisz jest to bardzo podobna konstrukcja jak tablice w Javie.
Mapy także są bardzo podobne do tych, które znasz z Javy. Uważam, że są to dla Ciebie na tyle intuicyje konstrukcje, że nie ma sensu za bardzo się o nich rozpisywać i ten prosty przykład wykorzystania wystarczy.
wstrzykiwanie zależności
W Angularze także spotkasz się z pojęciem wstrzykiwania zależności. Nie różni się ono zbytnio od podejścia, które znasz ze Springa. Wstrzykiwanie zależności jest realizowane poprzez konstruktor. Aby klasa była możliwa do wstrzyknięcia musi zostać oznaczona adnotacją @Injectable(). Z reguły klasy z adnotacją @Injectable() są serwisami oraz posiadają w nazwie słowo kluczowe service. Można to pokazać na prostym przykładzie.
Stwórz serwis dla samochodów z metodą która sprawdza czy dana marka pojazdu posiada zniżkę.
W katalogu app stwórz plik car.service.ts oraz dodaj w pliku następujący kod:
import { Injectable } from '@angular/core';
@Injectable(
{
providedIn: 'root'
}
)
export class CarService {
private carsWithoutDiscount = ['A8', 'Seria 7', 'Klasa S'];
private carsDiscount: Map<string, number> = new Map([
['A6', 20],
['Klasa E', 15],
['Seria 5', 17],
]);
getCarDiscount(carModel: string): number {
return this.carsDiscount.get(carModel);
}
getCarsWithoutDiscount(): string[] {
return this.carsWithoutDiscount;
}
}
Czym jest dziwnie wyglądający zapis providedIn: root w adnotacji? Jest to mechanizm który pozwala zakomunikować Angularowi, żeby udostępnił ten serwis dla całej aplikacji automatycznie bez potrzeby dodawania go do głównego modułu app.module.ts.
Więcej na temat architektury znajdziesz w kolejnym kroku procesu: Teoria.
Przejdź do pliku app.component.ts
import {Component, OnInit} from '@angular/core';
import {CarService} from './car/car.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
public discount = 0;
constructor(private carService: CarService) {
}
ngOnInit(): void {
this.discount = this.carService.getCarDiscount('A6');
}
}
oraz w pliku app.component.html dodaj kod
<p>Przysługuje {{ discount }}% zniżki na Audi A6.</p>
<p>Modele bez zniżki:</p>
<div *ngFor="let car of carsWithoutDiscount">
{{car}}
</div>
Gdy przejdziesz do aplikacji powinieneś zobaczyć następujący widok.