Salam, Habr! Sizi məqalənin tərcüməsi ilə tanış edirəm müəllifi Christopher Kuech.
Obyekt-yönümlü və funksional proqramlaşdırma paradigmalari bir-biri ilə uyğun görünməyə bilər, lakin hər ikisi PowerShell-də bərabər dərəcədə dəstəklənir. Praktik olaraq, funksional və qeyri-funksional bütün proqramlaşdırma dilləri adlar və dəyərlərin genişləndirilmiş bağlanması üçün vasitələrə malikdir; Siniflər, struct-lar və record-lar kimi, bir yanaşmadır. Sinifləri yalnız adların və dəyərlərin bağlanması ilə məhdudlaşdırsaq və miras alma, polimorfizm və dəyişkənlik (mutability) kimi "ağır" obyekt-yönümlü proqramlaşdırma konseptlərindən qaçsaq, kodumuzu çətinləşdirmədən onların üstünlüklərindən istifadə edə bilərik. Sonra, dəyişməz (immutable) tip çevirmə metodlarını əlavə edərək, funksional kodumuzu siniflərlə zənginləşdirə bilərik.
Kastların sehrli
Kastlar PowerShell-də ən güclü xüsusiyyətlərdən biridir. Bir dəyəri kast etdiyiniz zaman, tətbiqinizə əlavə edilən mühitin qeyri-müəyyən ilkinləşdirmə və doğrulama imkanlarına istinad edirsiniz. Məsələn, sadə bir string'i [xml] kast etmək onu parsel kodundan keçirəcək və tam bir xml ağacı yaradacaq. Kodumuzda eyni məqsədlə Siniflərdən istifadə edə bilərik.
Həş cədvəllərinin kastı
Əgər sizin konstruktorunuz yoxdursa, onunla davam edə bilərsiniz, sınıfınızın tipinə kast edilmiş həş cədvəllərini istifadə edərək. Bu nümunə tam şəklində istifadə etməkdən asılılığını artırmaq üçün doğrulama atributlarından istifadə etməyi unutmayın. Eyni zamanda, daha dərin ilkinləşdirmə və doğrulama məntiqini başlatmaq üçün sinifin tipləşdirilmiş xüsusiyyətlərindən istifadə edə bilərik.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
}
[Cluster]@{
Service = "MyService"
FlightingRing = "PROD"
Region = "EastUS"
Index = 2
}Bundan əlavə, kast təmiz çıxış almağa kömək edir. Həş cədvəlləri Cluster-ın Format-Table-da ötürülmüş çıxışını, klasslara kast etdiyimiz zaman alınan çıxışla müqayisə edin. Sinifin xüsusiyyətləri hər zaman burada müəyyən edildiyi sırada sıralanır. Çıxışda görünməməsi lazım olan bütün xüsusiyyətlərdən əvvəl hidden açar sözünü əlavə etməyi unutmayın.

Dəyərlərin kastı
Əgər sizdə bir arqumenti olan bir konstruktor varsa, dəyərinizi sinifinizin tipinə kast etmək, bu dəyəri konstruktorunuza göndərəcək, burada sinifinizin instansiyasını ilkinləşdirə bilərsiniz.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
Cluster([string] $id) {
$this.Service, $this.FlightingRing, $this.Region, $this.Index = $id -split "-"
}
}
[Cluster]"MyService-PROD-EastUS-2"Dəyərlə kast
Eyni zamanda, obyekti string şəklində təqdim edən loqikanı müəyyən etmək üçün [string] ToString() sinif metodunu da dəyişdirə bilərsiniz, məsələn, string interpolasiyasından istifadə edərək.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
[string] ToString() {
return $this.Service, $this.FlightingRing, $this.Region, $this.Index -join "-"
}
}
$cluster = [Cluster]@{
Service = "MyService"
FlightingRing = "PROD"
Region = "EastUS"
Index = 2
}
Write-Host "Biz '$cluster' üçün bir model yaratdıq"Seriyalaşdırılmış instansiyaların tipləri
Tiplər təhlükəsiz deserializasiya etməyə imkan verir. Aşağıdakı nümunələr, məlumatlar Cluster spesifikasiyamıza uyğun gəlməsə, xətaya səbəb olacaq.
# Валидация сериализованных данных
[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"Funksional kodunuzda tiplər
Funksional proqramlar əvvəlcə məlumat strukturlarını müəyyən edir, daha sonra proqramı dəyişməz məlumat strukturlarında ardıcıllıqla transformasiyalar kimi tətbiq edirlər. Mübahisəli təsirə baxmayaraq, siniflər funksional kod yazmağa kömək edir, çünki tip konversiya metodlarından istifadə edir.
Yazdığım Powershell funksionaldırmı?
C# və ya oxşar keçmişi olan bir çox insan Powershell-i C#-a bənzər şəkildə yazır. Belə etdikdə, siz funksional proqramlaşdırma konsepsiyalarından istifadə etməməyə qərar verirsiniz və ehtimal ki, Powershell-də obyektyönlü proqramlaşdırmaya daha dərindən dalmağa və ya funksional proqramlaşdırmanı daha yaxşı öyrənməyə fayda görəcəksiniz.
Əgər siz transformasiyalara dərin şəkildə etibar edirsinizsə, immutabl məlumatları istifadə edərək, boru xətləri (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object və s. istifadə edirsinizsə — o zaman siz daha funksional bir üsluba sahibsiniz və Powershell siniflərinin funksional üslubda işlənməsi sizə kömək edə bilər.
Siniflərin funksional istifadəsi
Tiplər, alternativ sintaksis istifadə etsə də, sadəcə iki domen arasında xəritədir. Boru xəttində nizamsız dəyərlər massivini ForEach-Object istifadə edərək xəritələmək mümkündür.
Aşağıdakı nümunədə, Node konstrukturu hər dəfə Datum-a tip çevrilməsi həyata keçirildikdə icra olunur və bu, bizə müəyyən qədər kod yazmamaq imkanı verir. Nəticədə bizim boru xətmimiz məlumatların deklaratı sorğusu və toplanması ilə konsentrasiya olunur, eyni zamanda siniflərimiz məlumat parsinqi və doğrulama işini üstlənir.
# Пример комбинирования классов с конвейерами для separation of concerns в конвейерах
class Node {
[ValidateLength(3, 7)]
[string] $Name
[ValidateSet("INT", "PPE", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope", "WestEurope")]
[string] $Region
Node([string] $Name) {
$Name -match "([a-z]+)(INT|PPE|PROD)([a-z]+)"
$_, $this.Service, $this.FlightingRing, $this.Region = $Matches
$this.Name = $Name
}
}
class Datum {
[string] $Name
[int] $Value
[Node] $Computer
[int] Severity() {
$this.Name -match "[0-9]+$"
return $Matches[0]
}
}
Write-Host "Urgent Security Audit Issues:"
Import-Csv "./audit-results.csv" `
| ForEach-Object {[Datum]$_} `
| Where-Object Value -gt 0 `
| Group-Object {$_.Severity()} `
| Where-Object Name -lt 2 `
| ForEach-Object Group `
| ForEach-Object Computer `
| Where-Object FlightingRing -eq "PROD" `
| Sort-Object Name, Region -UniqueTəkrardan istifadə üçün sinif paketləri
Heç nə görünüşü qədər yaxşı deyil
Təəssüf ki, siniflər modullar tərəfindən funksiyalar və ya dəyişənlər kimi eyni şəkildə ixrac edilə bilmir; lakin bəzi fəndlər var. Tutaq ki, sinifləriniz ./my-classes.ps1 faylında müəyyən edilmişdir.
Siniflərin olduğu faylı aşağıdakı kimi daxil edə bilərsiniz: . ./my-classes.ps1. Bu, my-classes.ps1 faylını hazırkı qeyd sahənizdə icra edəcək və fayldakı bütün sinifləri orada müəyyən edəcək.
Powershell modulunu yaradaraq bütün şəxsi API-nizi (cmdlet-lərinizi) ixrac edə bilərsiniz və modul manifestində ScriptsToProcess = ".\/my-classes.ps1" dəyişənini eyni nəticə əldə etmək üçün təyin edə bilərsiniz: .\/my-classes.ps1 mühitinizdə icra olunacaq.
Hansı variantı seçsəniz seçin, unutmayın ki, Powershell-in tip sistemi eyni adda olan tipləri fərqli yerlərdən yüklənmiş halda idarə edə bilmir.
Eyni xassələrə malik iki eyni sinifi fərqli yerlərdən yükləsəniz, problemlerə rast gəlmə riski ilə qarşılaşırsınız.
Gələcək yol
Tiplərin həll edilməsi ilə bağlı problemlərdən qaçmağın ən yaxşı yolu, siniflərinizi istifadəçilərə təqdim etməməkdir. İstifadəçinin sinifdə konkret bir tip ixrac edəcəyini gözləmək əvəzinə, modulunuzdan bir funksiya ixrac edin ki, bu da istifadəçini birbaşa sinifə müraciət etməyə ehtiyacdan azad etsin. Cluster ilə bağlı, New-Cluster funksiyasını ixrac edə bilərik ki, bu da istifadəçi üçün dost parametr dəstlərini dəstəkləsin və Cluster-i geri qaytarsın.
class Cluster {
[ValidatePattern("^[A-z]+$")]
[string] $Service
[ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
[string] $FlightingRing
[ValidateSet("EastUS", "WestUS", "NorthEurope")]
[string] $Region
[ValidateRange(0, 255)]
[int] $Index
}
function New-Cluster {
[OutputType([Cluster])]
Param(
[Parameter(Mandatory, ParameterSetName = "Id", Position = 0)]
[ValidateNotNullOrEmpty()]
[string] $Id,
[Parameter(Mandatory, ParameterSetName = "Components")]
[string] $Service,
[Parameter(Mandatory, ParameterSetName = "Components")]
[string] $FlightingRing,
[Parameter(Mandatory, ParameterSetName = "Components")]
[string] $Region,
[Parameter(Mandatory, ParameterSetName = "Components")]
[int] $Index
)
if ($Id) {
$Service, $FlightingRing, $Region, $Index = $Id -split "-"
}
[Cluster]@{
Service = $Service
FlightingRing = $FlightingRing
Region = $Region
Index = $Index
}
}
Export-ModuleMember New-ClusterDaha çox oxumaq üçün
Mənbə: habr.com
