Hello, Habr! Ipinakita ko sa iyong pansin ang isang pagsasalin ng artikulo ni Christopher Kuech.
Ang Object-oriented at functional na mga paradigm sa programming ay maaaring mukhang magkasalungat sa isa't isa, ngunit pareho silang sinusuportahan sa PowerShell. Halos lahat ng programming language, functional man o hindi, ay nag-aalok ng malawak na name-value binding; Ang mga klase, tulad ng mga istruktura at talaan, ay isang diskarte lamang. Sa pamamagitan ng paglilimita sa aming paggamit ng mga klase sa name-value binding at pag-iwas sa heavyweight object-oriented programming concepts tulad ng inheritance, polymorphism, o mutability, maaari naming gamitin ang mga benepisyo ng mga ito nang hindi kumplikado ang aming code. Higit pa rito, sa pamamagitan ng pagdaragdag ng hindi nababagong uri ng mga paraan ng conversion, maaari naming pagyamanin ang aming functional code sa mga klase.
Caste magic
Ang mga cast ay isa sa pinakamakapangyarihang feature sa PowerShell. Kapag nag-cast ka ng value, umaasa ka sa mga implicit initialization at mga kakayahan sa pagpapatunay na idinaragdag ng environment sa iyong application. Halimbawa, ang pag-cast lang ng string sa [xml] ay tatakbo nito sa parser code at bubuo ng isang buong XML tree. Maaari naming gamitin ang Mga Klase sa aming code para sa parehong layunin.
Mag-cast ng mga hashtable
Kung wala kang constructor, maaari kang magpatuloy nang walang isa sa pamamagitan ng pag-cast ng hashtable sa uri ng iyong klase. Huwag kalimutang gumamit ng mga katangian ng pagpapatunay upang lubos na mapakinabangan ang pattern na ito. Maaari rin kaming gumamit ng mga na-type na katangian ng klase upang ipatupad ang mas malalim na pagsisimula at lohika ng pagpapatunay.
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
}Higit pa rito, nakakatulong ang casting na makagawa ng mas malinis na output. Ihambing ang output ng isang Cluster array ng mga hashtable na ipinasa sa Format-Table sa kung ano ang makukuha mo kung una mong i-cast ang mga hashtable na ito sa isang klase. Ang mga pag-aari ng klase ay palaging nakalista sa pagkakasunud-sunod na tinukoy ang mga ito. Huwag kalimutang idagdag ang nakatagong keyword bago ang anumang mga katangian na hindi mo gustong makita sa output.

Caste of Values
Kung mayroon kang constructor na may isang argumento, ang paglalagay ng value sa uri ng iyong klase ay ipapasa ang value sa iyong constructor, kung saan maaari mong simulan ang isang instance ng iyong klase.
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"I-cast sa linya
Maaari mo ring i-override ang paraan ng ToString() ng klase ng [string] upang tukuyin ang lohika para sa kumakatawan sa object sa isang string, gaya ng paggamit ng string interpolation.
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'"Nag-cast ng mga serialized na instance
Nagbibigay-daan ang cast para sa ligtas na deserialization. Ang mga halimbawa sa ibaba ay mabibigo kung ang data ay hindi nakakatugon sa aming Cluster na detalye.
# Валидация сериализованных данных
[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"Nag-cast sa iyong functional code
Tinutukoy muna ng mga functional na programa ang mga istruktura ng data, pagkatapos ay ipinatupad ang programa bilang isang pagkakasunud-sunod ng mga pagbabago sa hindi nababagong istruktura ng data. Sa kabila ng counterintuitive na impression, ang mga klase ay talagang tumutulong sa pagsulat ng functional code salamat sa kanilang uri ng mga paraan ng conversion.
Nagsusulat ba ako ng functional Powershell?
Maraming tao na nagmumula sa C# o katulad na background ang sumulat ng PowerShell, na katulad ng C#. Sa paggawa nito, tinatalikuran mo ang mga konsepto ng functional na programming at malamang na makikinabang sa pag-aaral nang mas malalim sa object-oriented na programming sa PowerShell o pag-aaral pa tungkol sa functional programming.
Kung lubos kang umaasa sa pagbabago ng hindi nababagong data gamit ang mga pipe (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object, atbp., mayroon kang mas functional na istilo at makikinabang sa paggamit ng functional-style na mga klase ng Powershell.
Functional na paggamit ng mga klase
Ang mga cast, bagama't gumagamit sila ng alternatibong syntax, ay isang pagmamapa lamang sa pagitan ng dalawang domain. Sa isang pipeline, maaari mong imapa ang isang hanay ng mga halaga gamit ang ForEach-Object.
Sa halimbawa sa ibaba, ang Node constructor ay isinasagawa sa bawat oras na ang isang Datum ay na-cast, na nag-aalis ng malaking halaga ng code. Bilang resulta, ang aming pipeline ay nakatuon sa deklaratibong pag-query at pagsasama-sama ng data, habang ang aming mga klase ay humahawak ng pag-parse at pagpapatunay ng data.
# Пример комбинирования классов с конвейерами для 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 -UniqueRecyclable na packaging
Walang kasing ganda sa tila
Sa kasamaang palad, ang mga klase ay hindi maaaring i-export ng mga module sa parehong paraan tulad ng mga function o variable, ngunit may ilang mga trick. Sabihin nating ang iyong mga klase ay tinukoy sa file na ./my-classes.ps1
Maaari kang mag-dotsource ng class file: ./my-classes.ps1. Ipapatupad nito ang my-classes.ps1 sa iyong kasalukuyang saklaw at tutukuyin ang lahat ng mga klase mula sa file doon.
Maaari kang gumawa ng Powershell module na nag-e-export ng lahat ng iyong custom na API (cmdlets) at itakda ang ScriptsToProcess = "./my-classes.ps1" na variable sa manifest ng iyong module, na may parehong resulta: ./my-classes.ps1 ay isasagawa sa iyong environment.
Alinmang opsyon ang pipiliin mo, tandaan na hindi malulutas ng PowerShell type system ang mga uri na may parehong pangalan na na-load mula sa iba't ibang lokasyon.
Kahit na nag-load ka ng dalawang magkaparehong klase na may parehong mga katangian mula sa iba't ibang lugar, nanganganib kang magkaroon ng mga problema.
Ang daan pasulong
Ang pinakamahusay na paraan upang maiwasan ang mga isyu sa paglutas ng uri ay ang hindi kailanman ilantad ang iyong mga klase sa mga user. Sa halip na asahan ang mga user na mag-import ng isang uri na tinukoy sa isang klase, mag-export ng isang function mula sa iyong module na nag-aalis ng pangangailangan na direktang ma-access ang klase. Para sa Cluster, maaari kaming mag-export ng New-Cluster function na sumusuporta sa user-friendly na mga set ng parameter at nagbabalik ng 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-ClusterKung anu-ano pang babasahin
Pinagmulan: www.habr.com
