Ahoj, Habr! Predstavujem vám preklad článku autora Christophera Kuecha.
Objektovo-orientované a funkcionálne paradigmy programovania sa môžu zdať nesúladné, ale obidve sú rovnako podporované v PowerShelli. Prakticky všetky programovacie jazyky, funkcionálne i ne, majú prostriedky na rozšírené prepojenie mien a hodnôt; Triedy, podobne ako štruktúry a záznamy, sú len jedným prístupom. Ak obmedzíme použitie tried na prepojenie mien a hodnôt a budeme sa vyhýbať takým "ťažkým" objektovo-orientovaným programovým konceptom, ako sú dedičstvo, polymorfizmus alebo mutabilita, môžeme využívať ich výhody bez zloženia nášho kódu. Ďalej, pridávaním nemenných (immutable) metód na konverziu typov môžeme obohatiť náš funkcionálny kód triedami.
Kúzlo konverzií
Konverzie sú jednou z najsilnejších funkcií v PowerShelli. Keď aplikujete hodnotu na konverziu, spoliehate sa na neimplicitnú inicializáciu a validáciu, ktorú prostredie dodáva vášmu aplikácii. Napríklad jednoduchá konverzia reťazca na [xml] prejde cez parserový kód a vygeneruje kompletný xml strom. V našom kóde môžeme použiť triedy na rovnaký účel.
Konverzia hash tabuliek
Ak nemáte konštruktor, môžete pokračovať ďalej bez neho, používajúc konverziu hash tabuliek na typ vašej triedy. Nezabudnite využiť validačné atribúty, aby ste plne využili tento vzor. Zároveň môžeme využiť typované vlastnosti triedy, aby sme spustili ešte hlbšiu logiku inicializácie a validácie.
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
}Okrem toho, konverzia pomáha získať čistý výstup. Porovnajte výstup poľa hash tabuliek Cluster, ktorý bol odoslaný do Format-Table, s tým, čo dostanete, ak predtým prevediete tieto hash tabuľky na triedu. Vlastnosti triedy sú vždy uvedené v tom poradí, v akom sú definované. Nezabudnite pridať kľúčové slovo hidden pred všetky tie vlastnosti, ktoré by nemali byť viditeľné vo výstupe.

Konverzia hodnôt
Ak máte konštruktor s jedným argumentom, konverzia hodnoty na váš typ triedy prenesie hodnotu do vášho konštruktora, v ktorom môžete inicializovať inštanciu vašej triedy.
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"Konverzia na reťazec
Môžete tiež pretiahnuť metódu triedy [string] ToString(), aby ste definovali logiku reťazcového zobrazenia objektu, napríklad použiť interpoláciu reťazcov.
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 "Práve sme vytvorili model pre '$cluster'"Konverzia serializovaných inštancií
Konverzia umožňuje bezpečnú deserialize. Nižšie uvedené príklady skončia chybou, ak údaje nespĺňajú našu špecifikáciu v Cluster.
# Валидация сериализованных данных
[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"Typy vo vašom funkčnom kóde
Funkčné programy najprv definujú štruktúry údajov a potom implementujú program ako sekvenciu transformácií nad nemennými štruktúrami údajov. Napriek rozporuplnému dojmu triedy skutočne pomáhajú písať funkčný kód, vďaka metódam konverzie typov.
Píšem funkčný Powershell?
Mnoho ľudí prichádzajúcich z C# alebo s podobnou minulosťou píše Powershell, ktorý vyzerá ako C#. Týmto sa vzdávate používania konceptov funkčného programovania a pravdepodobne získate výhodu, keď sa hlbšie ponoríte do objektovo orientovaného programovania v Powershell alebo sa lepšie naučíte funkčné programovanie.
Ak sa hlboko spoliehate na transformáciu nemenných údajov pomocou potrubí (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object a pod. — máte funkčnejší štýl a pomôže vám to využitie tried Powershell vo funkčnom štýle.
Funkčné využitie tried
Castingy, hoci používajú alternatívnu syntaxy, sú iba mapovaním medzi dvoma doménami. V potrubí môžete mapovať pole hodnôt pomocou ForEach-Object.
V nasledujúcom príklade sa konštruktor Node vykonáva zakaždým, keď dôjde k cástingu na Datum, čo nám umožňuje napísať značné množstvo kódu. V dôsledku toho sa naše potrubie sústreďuje na deklaratívny dotaz údajov a agregáciu, zatiaľ čo naše triedy preberajú analýzu údajov a validáciu.
# Пример комбинирования классов с конвейерами для 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 -UniqueBalenie triedy na znovupoužitie
Nič nie je tak dobré, ako sa zdá
Bohužiaľ, triedy nemôžu byť exportované modulmi rovnakým spôsobom ako funkcie alebo premenné; ale existujú nejaké triky. Predpokladajme, že vaše triedy sú definované v súbore ./my-classes.ps1
Môžete urobiť dotSource na súbor s triedami: . ./my-classes.ps1. To vykoná my-classes.ps1 vo vašej súčasnej oblasti viditeľnosti a v definovaní všetkých tried z tohto súboru.
Môžete vytvoriť modul Powershell, ktorý exportuje všetky vaše používateľské API (cmdlety) a nastaviť premennú ScriptsToProcess = "./my-classes.ps1" v manifeste vášho modulu, s rovnakým výsledkom: ./my-classes.ps1 sa vykoná vo vašom prostredí.
Bez ohľadu na to, ktorú možnosť si vyberiete, nezabúdajte, že systém typov Powershell nemôže vyriešiť rovnomenné typy načítané z rôznych miest.
Aj keď ste načítali z rôznych miest dva identické triedy so rovnakými vlastnosťami, môžete naraziť na problémy.
Cesta vpred
Najlepší spôsob, ako sa vyhnúť problémom s rozlíšením typov, je nikdy neexponovať vaše triedy používateľom. Namiesto toho, aby ste očakávali, že používateľ importuje konkrétny typ v triede, exportujte zo svojho modulu funkciu, ktorá zbavuje potreby priamo sa odkazovať na triedu. Pre Cluster môžeme exportovať funkciu New-Cluster, ktorá podporí priateľské súpravy parametrov a vráti Cluster.
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-ClusterČo ešte prečítať
Zdroj: habr.com
