Tere, Habr! Esitlen teile tõlget artiklist autor Christopher Kuech.
Objektorienteeritud ja funktsionaalne programmeerimise paradigma võivad tunduda omavahel vastuolus, kuid mõlemat toetatakse Powershellis võrdse määraga. Peaaegu kõik programmeerimiskeeled, nii funktsionaalsed kui mitte, omavad täiustatud nimede ja väärtuste sidumise vahendeid; Klassid, sarnaselt struct'ide ja record'idega, on vaid üks lähenemine. Kui me piirame Klasside kasutamist nimede ja väärtuste sidumisega ja vältime selliseid "raskete" objektorienteeritud programmeerimise kontseptsioone nagu pärand, polümorfism või muutlikkus (mutability), saame kasutada nende eeliseid, keerukust meie koodis suurendamata. Edasi liikudes, lisades muutumatuid (immutable) tüübi teisendamise meetodeid, saame täiendada meie funktsionaalset koodi Klassidega.
Kastide maagia
Kastid on üks võimsamaid funktsioone Powershellis. Kui te rakendate väärtusele kasti, toetute keskkonna poolt teie rakendusele antud varjatud initsialiseerimise ja valideerimise võimalusele. Näiteks, lihtne stringi kast [xml] suunab selle läbi parseri koodi ja genereerib täieliku XML puu. Me saame oma koodis kasutada klasse sama eesmärgi nimel.
Kast h подсистемы
Kui teil pole konstrueerijat, võite jätkata ilma selleta, kasutades kast hiddlesüsteemi teie klassi tüüpi. Ärge unustage kasutada valideerimise atribuute, et täielikult ära kasutada seda mustrit. Samuti saame kasutada tüübistatud klassi omadusi, et käivitada veelgi sügavam initsialiseerimise ja valideerimise loogika.
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
}Lisaks aitab kast saada puhta väljundi. Võrrelge Clusteri hiddlesüsteemi massiivi väljundit, mis on edastatud Format-Table'isse, sellega, mis juhtub, kui me eelnevalt kastime need hiddlesüsteemid klassiks. Klasside omadused loetletakse alati selles järjekorras, milles need on määratletud. Ärge unustage lisada märksõna hidden kõikide nende omaduste ette, mis ei peaks olema väljundis nähtavad.

Kast väärtused
Kui teil on konstruktor ühe argumendiga, siis teie klassi tüübile kastimine edastab väärtuse sellele konstruktorile, kus saate oma klassi eksemplari initsialiseerida.
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"Kast stringiks
Samuti saate üle kirjutada klassi meetodi [string] ToString(), et määratleda objekti stringi esitamise loogika, näiteks kasutada stringi interpolatsiooni.
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 "We just created a model for '$cluster'"Kast serialiseeritud eksemplaride jaoks
Kastimine tagab ohutu dastserialiseerimise. Allpool toodud näited lõppevad veaga, kui andmed ei vasta meie spetsifikatsioonile klassis Cluster.
# Валидация сериализованных данных
[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"Kastid teie funktsionaalses koodis
Funktsionaalsed programmid defineerivad kõigepealt andmestruktuurid ja seejärel implementeerivad programmi kui järjestikku transformatsioone muutumatute andmestruktuuride üle. Ehkki see võib tunduda vastupidine, aitavad klassid tegelikult kirjutada funktsionaalset koodi, pakkudes tüüpide konverteerimise meetodeid.
Kas ma kirjutan funktsionaalset Powershelli?
Paljud inimesed, kes tulevad C#-st või sarnastest taustadest, kirjutavad Powershelli, mis on sarnane C#-le. Tehes seda, loobute funktsionaalse programmeerimise kontseptsioonide kasutamisest ning tõenäoliselt saad kasu süvenedes objekti-orienteeritud programmeerimisse Powershellis või õppides paremini funktsionaalset programmeerimist.
Kui te toetute sügavalt muutumatute andmete transformeerimisele, kasutades torusid (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object jne — siis on teil rohkem funktsionaalne stiil ja Powershelli klasside kasutamine funktsionaalses stiilis aitab teid.
Funktsionaalne klasside kasutamine
Kastid, kuigi kasutavad alternatiivset süntaksit, on vaid kahte domeeni vaheline kaardistus. Torus saab massiivi väärtusi kaardistada, kasutades ForEach-Object.
Allolevas näites käivitatakse Node konstruktor iga kord, kui toimub kastmine Datum-iks, ning see annab meile võimaluse mitte kirjutada suurt hulka koodi. Tulemuseks on see, et meie toru keskendub deklaratiivsetele andmeteadete ja agregatsioonile, samas kui meie klassid tegelevad andmete parsingu ja valideerimisega.
# Пример комбинирования классов с конвейерами для 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 -UniqueKlassi pakkimine taaskasutamiseks
Mitte miski ei ole nii hea, nagu paistab
Kahjuks ei saa klasse eksportida moodulite kaudu samamoodi nagu funktsioone või muutujaid; kuid siiski on mõned nipid. Oletame, et teie klassid on määratletud failis .\my-classes.ps1
Saate teha dot-sourcingu klassifaili: .\my-classes.ps1. See käivitab my-classes.ps1 teie praeguses kontekstis ja määratleb kõik klassid failist.
Saate luua PowerShelli mooduli, mis ekspordib kõik teie kohandatud API-d (käskudes) ja seadistada muutuja ScriptsToProcess = ".\my-classes.ps1" teie mooduli manifestis, sama tulemusega: .\my-classes.ps1 käivitatakse teie keskkonnas.
Mis tahes variandi valite, pidage meeles, et PowerShelli tüüb süsteem ei oska lahendada sama nimega tüüpe, mis on laaditud erinevatest kohtadest.
Isegi kui olete laadinud kahest erinevast kohast kaks identset klassi sama omadustega, on teil oht probleemidega kokku puutuda.
Eesmine tee
Parim viis tüübide lahendamise probleeme vältida on iialgi mitte esitada oma klasse kasutajatele. Selle asemel, et eeldada, et kasutaja impordib klassi määratletud tüübi, eksportige oma moodulist funktsioon, mis vabastab vajadusest otse klassiga tegeleda. Klasteri kontekstis saame eksportida funktsiooni New-Cluster, mis toetab kasutajasõbralikke parameetrisetteid ja tagastab Clusteri.
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-ClusterLisa lugemist
Allikas: habr.com
