Klaseekin Powershell funtzionala ez da oximoron bat, bermatzen dut

Kaixo, Habr! Artikuluaren itzulpena aurkezten dizuet "PowerShell funtzionala klaseekin.
agintzen dut ez dela oximoron bat"
Christopher Kuech-en eskutik.

Objektuetara zuzendutako programazio-paradigmak eta funtzionalak elkarren kontrakoak dirudite, baina biak berdin onartzen dira Powershell-en. Ia programazio-lengoaia guztiek, funtzionalak edo ez, izen-balioa lotzeko erraztasunak dituzte; Klaseak, egiturak eta erregistroak bezala, ikuspegi bat besterik ez dira. Klaseen erabilera izenak eta balioak lotzera mugatzen badugu eta objektuetara zuzendutako programazio kontzeptu astunak ekiditen baditugu, hala nola herentzia, polimorfismoa edo aldakortasuna, haien onurak aprobetxa ditzakegu gure kodea zaildu gabe. Gainera, mota aldaezinak bihurtzeko metodoak gehituz, gure kode funtzionala Klaseekin aberastu dezakegu.

Kasten magia

Kastak Powershell-en funtziorik indartsuenetako bat dira. Balio bat igortzen duzunean, inguruneak zure aplikazioari gehitzen dizkion hasierako eta baliozkotze gaitasun inplizituetan oinarritzen zara. Adibidez, kate bat [xml]-n botatzeak analizatzaile-kodearen bidez exekutatu eta xml zuhaitz osoa sortuko du. Gure kodean klaseak erabil ditzakegu helburu berberarekin.

Cast hashtables

Ez baduzu eraikitzailerik, bat gabe jarraitu dezakezu hashtable bat zure klase motara igorriz. Ez ahaztu baliozkotze-atributuak erabiltzea eredu honi etekin handiena ateratzeko. Aldi berean, klasearen idatzitako propietateak erabil ditzakegu hasierako eta baliozkotze logika sakonagoa exekutatzeko.

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
}

Gainera, casting-ak irteera garbia lortzen laguntzen du. Konparatu Format-Table-ra pasatu den Cluster hashtable array-aren irteera hashtable hauek klase batera botatzen badituzu lortzen duzunarekin. Klase baten propietateak beti agertzen dira bertan definitzen diren ordenan. Ez ahaztu emaitzetan ikusgai egon nahi ez dituzun propietate guztien aurretik ezkutuko gako-hitza gehitzea.

Klaseekin Powershell funtzionala ez da oximoron bat, bermatzen dut

Esanahien cast

Argumentu bakarreko konstruktore bat baduzu, balio bat zure klase motara igortzeak balioa zure konstruktoreari pasatuko dio, non zure klasearen instantzia bat has dezazun.

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"

Eman lerrora

[string] ToString() klase metodoa ere baliogabe dezakezu objektuaren kateen irudikapenaren atzean dagoen logika definitzeko, esate baterako, kateen interpolazioa erabiliz.

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'"

Igorri serializatutako instantziak

Cast-ek deserializazio segurua ahalbidetzen du. Beheko adibideek huts egingo dute datuek Cluster-en gure zehaztapena betetzen ez badute

# Валидация сСриализованных Π΄Π°Π½Π½Ρ‹Ρ…

[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"

Kastak zure kode funtzionalean

Programa funtzionalek lehenik datu-egiturak definitzen dituzte, gero programa aldaezinen gaineko eraldaketa-sekuentzia gisa inplementatzen dute. Inpresioa kontraesankorra izan arren, klaseek kode funtzionala idazten laguntzen dizute mota bihurtzeko metodoei esker.

Idazten ari naizen Powershell funtzionala al da?

C# edo antzeko jatorritik datozen jende asko Powershell idazten ari da, hau da, C#ren antzekoa. Hori eginez gero, programazio funtzionalaren kontzeptuak erabiltzetik aldenduko zara eta litekeena da Powershell-en objektuei zuzendutako programazioan asko murgiltzeari edo programazio funtzionalari buruz gehiago ikastea onuragarria izango litzateke.

Datu aldaezinak eraldatzen asko oinarritzen bazara kanalizazioak (|), Non-Object, ForEach-Object, Hautatu-Object, Group-Object, Sort-Object, etab. - estilo funtzionalagoa duzu eta Powershell erabiltzeak mesede egingo diozu. klaseak estilo funtzionalean.

Klaseen erabilera funtzionala

Kastak, sintaxi alternatiboa erabiltzen duten arren, bi domeinuren arteko mapa bat besterik ez dira. Kanalizazio batean, ForEach-Object erabiliz balio-matrize bat mapa dezakezu.

Beheko adibidean, Node eraikitzailea Datum bat botatzen den bakoitzean exekutatzen da, eta honek kode kopuru nahikorik ez idazteko aukera ematen digu. Ondorioz, gure kanalizazioa datuen deklarazioen kontsulta eta agregazioan zentratzen da, gure klaseak datuak analizatzeaz eta balioztatzeaz arduratzen diren bitartean.

# ΠŸΡ€ΠΈΠΌΠ΅Ρ€ комбинирования классов с ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€Π°ΠΌΠΈ для 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 -Unique

Ontzi klasea berrerabiltzeko

Ezer ez da dirudien bezain ona

Zoritxarrez, klaseak ezin dira moduluek esportatu funtzio edo aldagaien moduan; baina badira trikimailu batzuk. Demagun zure klaseak ./my-classes.ps1 fitxategian definituta daudela

  • Fitxategi bat dotsource dezakezu klaseekin:. ./nire-klaseak.ps1. Honek my-classes.ps1 zure uneko esparruan exekutatu eta klase guztiak zehaztuko ditu bertan fitxategitik.

  • Zure API pertsonalizatu guztiak (cmdlet-ak) esportatzen dituen Powershell modulu bat sor dezakezu eta ScriptsToProcess = "./my-classes.ps1" aldagaia ezar dezakezu zure moduluaren manifestuan, emaitza berarekin: ./my-classes.ps1 exekutatu egingo da. zure ingurunea.

Aukeratzen duzun aukera edozein dela ere, kontuan izan Powershell-en mota-sistemak ezin dituela ebatzi leku desberdinetatik kargatutako izen bereko motak.
Leku ezberdinetatik propietate berdinak dituzten bi klase berdin kargatu badituzu ere, arazoak izateko arriskua duzu.

Aurrera egiteko bidea

Mota ebazpen-arazoak saihesteko modurik onena zure klaseak erabiltzaileei inoiz ez erakustea da. Erabiltzaileak klaseak definitutako mota bat inportatzea espero beharrean, esportatu zure modulutik klasera zuzenean sartzeko beharra ezabatzen duen funtzio bat. Cluster-erako, Kluster Berriko funtzio bat esportatu dezakegu, parametro-multzo errazak onartzen dituena eta Cluster bat itzuliko duena.

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

Zer gehiago irakurri

Klaseei buruz
Defentsa PowerShell
Programazio funtzionala PowerShell-en

Iturria: www.habr.com

Gehitu iruzkin berria