Tere, Habr! Esitan teile artikli tõlke autori Christopher Kuech.
Objektorienteeritud ja funktsionaalne programmeerimisparadigma võivad näida omavahel kokkusobimatud, kuid mõlemat toetatakse PowerShellis võrdselt. Peaaegu kõik programmeerimiskeeled, nii funktsionaalsed kui ka mitte, sisaldavad nime ja väärtuse sidumise arenenud võimalusi; klassid, nagu struktuurid ja kirjed, on lihtsalt üks lähenemine. Kui me piirdume klasside kasutamisel nimede ja väärtuste sidumisega ning hakkame vältima selliseid "raskete" objektorienteeritud kontseptsioonide nagu pärand, polümorfism või muutuvus (mutability) kasutamist, saame nende eeliseid kasutada, ilma et meie kood keerulisemaks muutuks. Edasi, lisades muutumatuid (immutable) tüübi konverteerimise meetodeid, saame meie funktsionaalset koodi klassidega rikastada.
Kastide maagia
Casting on Powershell is one of its most powerful features. When you cast a value, you rely on the environment's ability to add implicit initialization and validation to your application. For instance, simply casting a string to [xml] will run it through the parser code and generate a complete XML tree. We can utilize classes in our code for the same purpose.
HashTable casting
If you don't have a constructor, you can still proceed without it, using the hash table cast to your class type. Don't forget to use validation attributes to fully leverage this pattern. At the same time, we can utilize typed class properties to trigger even deeper initialization and validation logic.
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 massiivi häshtabelite väljundit, mis edastati Format-Table'ile, sellega, mis saadakse, kui need häshtabelid enne klassiks kastida. Klasside omadused loetletakse alati selles järjekorras, milles need on määratud. Ära unusta lisada märksõna hidden kõigi nende omaduste ees, mis ei tohiks väljundis nähtavad olla.

Väärtuste kastimine
Kui teil on ühes argumendis konstruct, siis väärtuse kastimine teie klassi tüübiks edastab väärtuse sellele teie 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 määrata klassi meetodi [string] ToString(), et määrata objekti stringi esituse loogika, näiteks kasutada stringide 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'"Serialiseeritud instantside struktuur
Struktuur võimaldab turvalist deserialiseerimist. Allpool toodud näidised lõpetavad tõrke, kui andmed ei vasta meie Cluster'i spetsifikatsioonile.
# Валидация сериализованных данных
[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"Struktuurid teie funktsionaalses koodis
Funktsionaalsed programmid määravad esmalt andmestruktuurid, seejärel rakendavad programmi muutuste jada muutumatute andmestruktuuride üle. Vaatamata vastuolulisele muljele aitavad klassid tõeliselt funktsionaalset koodi kirjutada, pakkudes tüüpide konverteerimise meetodeid.
Kas ma kirjutan funktsionaalset Powershelli?
Paljud inimesed, kes tulevad C#-st või sarnastest taustadest, kirjutavad Powershelli, mis on C#-le sarnane. Selliselt tegutsedes loobute funktsionaalse programmeerimise kontseptsioonide kasutamisest ning saate ilmselt kasu, süvenedes objektorienteeritud programmeerimisse Powershellis või õpite paremini funktsionaalset programmeerimist.
Kui toetute tugevalt immutamatute andmete transformatsioonile, kasutades torusid (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object jne — teil on rohkem funktsionaalne stiil, ja klasid Powershellis funktsionaalsetes vormides võivad teid aidata.
Funktsionaalne klasside kasutamine
Castid, kuigi kasutavad alternatiivset süntaksit, on vaid kahe domeeni vahelised kaardistamised. Torus saab väärtuste massi kaardistada, kasutades ForEach-Object.
Allolevas näites käivitatakse Node konstruktor iga kord, kui toimub Datum'iks castimine, mis annab meile võimaluse mitte kirjutada rikast koodi. Selle tulemusena keskendub meie toru deklaratiivsele andmete pärimisele ja aggregeerimisele, samas kui meie klassid tegelevad andmete parsimise 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 -UniqueTaaskasutatava klassi pakett
Mitte miski pole nii hea, nagu paistab
Kahjuks ei saa klasse eksportida moodulite kaudu samamoodi nagu funktsioone või muutujaid; kuid on mõned nipid. Oletame, et teie klassid on määratletud failis ./my-classes.ps1
Saate klasside faili allika:. ./my-classes.ps1. See käivitab my-classes.ps1 teie praeguses ulatuses ja määratleb seal kõik klassid failist.
Saate luua Powershelli mooduli, mis ekspordib kõik teie kohandatud API-d (cmdlet'id) ja seada muutujaks ScriptsToProcess = "./my-classes.ps1" oma mooduli manifestis, saavutades sama tulemuse: ./my-classes.ps1 käivitatakse teie keskkonnas.
Ükskõik, millise variandi valite, pidage meeles, et Powershelli tüübisüsteem ei suuda hallata sama nimega tüüpe, mis on laaditud erinevatest kohtadest.
Isegi kui olete laadinud kahest erinevast kohast kaks identselt klassi sama omadustega, riskite probleemidega.
Edasi liikuda
Parim viis vältida tüübi määramise probleeme on mitte lubada kasutajatel oma klasse kasutada. Selle asemel, et oodata, et kasutaja impordib klassis määratud tüübi, eksportige oma moodulist funktsioon, mis vabastab vajadusest otseselt klassi juurde pääseda. Clustere puhul saame eksportida funktsiooni New-Cluster, mis toetab kasutajasõbralikke parameetrite komplekte 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-ClusterMida veel lugeda
Allikas: habr.com
