angular: wzorzec strategii

strategy-small

omówię:

- jak zaimplementować wzorzec strategii

Wzorzec strategii jest jednym z najpopularniejszych wzorców jakie wykorzystuje się w projektach.

W tym artykule chciałbym przedstawić prostą implementację tego wzorca. W etapie 4 procesu w lekcji 6 będziemy dodawać wzorzec do aplikacji, którą będziemy tworzyć w poszczególnych lekcjach.

Stworzymy funkcjonalność przydzielania zniżki danemu klientowi. Zniżka będzie przydzielana na podstawie kilku danych takich jak: czy klient posiada firmę czy jest klientem prywatnym, wiek klienta oraz jak długo posiada prawo jazdy. 

Utworzymy dwie strategie: biznesową oraz prywatną. Zniżka biznesowa będzie zależna od czasu prowadzenia firmy. Zniżka prywatna od wieku klienta oraz czasu posiadanego prawa jazdy.

W katalogu src/app stwórz katalog strategy a w nim interfejs client.interface.ts

export interface Client {
name: string;
businessInMonths?: number;
isUnder25?: boolean;
licenseInMonths?: number;
}

Kolejnym krokiem będzie stworzenie interfejsu strategii oferty. Stwórz plik offer-strategy.interface.ts

import { Client } from './client.interface';

export interface OfferStrategy {
isDiscountAvailable(client: Client): boolean;
getDiscount(client: Client): number;
}

Utwórz pierwszą z naszych strategii business-offer-strategy.ts

import { OfferStrategy } from './offer-strategy.interface';
import { Client } from './client.interface';

export class BusinessOfferStrategy implements OfferStrategy {
isDiscountAvailable(client: Client): boolean {
return client.businessInMonths > 6;
}

getDiscount(client: Client): number {
if (!this.isDiscountAvailable(client)) {
return 0;
}
const businessInMonths = client.businessInMonths;
if (businessInMonths >= 6 && businessInMonths < 12) {
return 4;
}

if (businessInMonths > 60) {
return 30;
}

return businessInMonths * 0.4;
}
}

oraz strategię dla klienta prywatnego private-offer-strategy.ts

import { OfferStrategy } from './offer-strategy.interface';
import { Client } from './client.interface';

export class PrivateOfferStrategy implements OfferStrategy {

isDiscountAvailable(client: Client): boolean {
return !client.isUnder25 && client.licenseInMonths > 24;
}

getDiscount(client: Client): number {
if (!this.isDiscountAvailable(client)) {
return 0;
}

const licenseInMonths = client.licenseInMonths;
if (licenseInMonths > 60) {
return 15;
}

return licenseInMonths * 0.2;
}
}

Mamy już dwie strategie odpowiedzialne za obsługę klientów biznesowych oraz indywidualnych. Potrzebujemy jeszcze serwisu który będzie się zajmował wyliczeniem składki na podstawie danych o kliencie.

Utwórz discount.service.ts

import { Injectable } from '@angular/core';
import { Client } from './client.interface';
import { OfferStrategy } from './offer-strategy.interface';
import { BusinessOfferStrategy } from './business-offer-strategy';
import { PrivateOfferStrategy } from './private-offer-strategy';

@Injectable(
{
providedIn: 'root'
}
)
export class DiscountService {
public getDiscount(client: Client): number {
return this.resolveStrategy(client).getDiscount(client);
}

private resolveStrategy(client: Client): OfferStrategy {
if (client.businessInMonths) {
return new BusinessOfferStrategy();
}
return new PrivateOfferStrategy();
}
}

W src/app stwórz folder car oraz dodaj plik  car.model.ts

export class Car {

constructor(public brand: string,
public model: string,
public engineType: string,
public type: string) {
}
}

Ostatnie dwie rzeczy jakie zostały to wstrzyknięcie discount.service.ts w app.componet.ts jak poniżej oraz przygotowanie kilku klientów i wyliczenie dla nich zniżki.

import {Component, OnInit} from '@angular/core';
import {DiscountService} from './strategy/discount.service';
import {Car} from './car/car.model';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
public car: Car;
public car1: Car;
public karolDiscount: number;
public jacekDiscount: number;
public wojtekDiscount: number;
public dawidDiscount: number;

constructor(private discountService: DiscountService) {
}

public ngOnInit(): void {
this.car = new Car(
'Audi',
'A6',
'benzyna',
'sedan'
);

this.car1 = new Car(
'Mercedes',
'Klasa E',
'diesel',
'coupe'
);

const karol = {
name: 'Karol',
businessInMonths: 15
};

const jacek = {
name: 'Jacek',
businessInMonths: 60
};

const wojtek = {
name: 'Wojtek',
isUnder25: false,
licenseInMonths: 40
};

const dawid = {
name: 'Dawid',
isUnder25: false,
licenseInMonths: 35
};

this.karolDiscount = this.discountService.getDiscount(karol);
this.jacekDiscount = this.discountService.getDiscount(jacek);
this.wojtekDiscount = this.discountService.getDiscount(wojtek);
this.dawidDiscount = this.discountService.getDiscount(dawid);
}
}

oraz app.component.html

<p>Marka: {{car.brand}}</p>
<p>Model: {{car.model}}</p>
<p>Silnik: {{car.engineType}}</p>
<p>Nadwozie: {{car.type}}</p>
<br>

<p>Marka: {{car1.brand}}</p>
<p>Model: {{car1.model}}</p>
<p>Silnik: {{car1.engineType}}</p>
<p>Nadwozie: {{car1.type}}</p>
<br>

<p>Karol otrzyma: {{karolDiscount}}% zniżki</p>
<p>Jacek otrzyma: {{jacekDiscount}}% zniżki</p>
<p>Wojtek otrzyma: {{wojtekDiscount}}% zniżki</p>
<p>Dawid otrzyma: {{dawidDiscount}}% zniżki</p>