Dərsləri olan funksional Powershell oksimoron deyil, buna zəmanət verirəm

Hey Habr! Məqalənin tərcüməsini diqqətinizə təqdim edirəm "Sinifləri olan funksional PowerShell.
Söz verirəm ki, bu oksimoron deyil"
Christopher Kuech tərəfindən.

Obyekt yönümlü və funksional proqramlaşdırma paradiqmaları bir-birinə zidd görünə bilər, lakin hər ikisi Powershell-də eyni dərəcədə dəstəklənir. Demək olar ki, bütün proqramlaşdırma dilləri, funksional və ya olmasın, genişləndirilmiş ad-dəyər bağlaması üçün imkanlara malikdir; Strukturlar və qeydlər kimi siniflər yalnız bir yanaşmadır. Siniflərdən istifadəmizi adların və dəyərlərin bağlanması ilə məhdudlaşdırsaq və irsiyyət, polimorfizm və ya dəyişkənlik kimi ağır obyekt yönümlü proqramlaşdırma anlayışlarından qaçsaq, kodumuzu çətinləşdirmədən onların üstünlüklərindən yararlana bilərik. Bundan əlavə, dəyişməz tip çevirmə üsullarını əlavə etməklə funksional kodumuzu Classes ilə zənginləşdirə bilərik.

Kastaların sehri

Kastlar Powershell-in ən güclü xüsusiyyətlərindən biridir. Dəyər verdiyiniz zaman, mühitin tətbiqinizə əlavə etdiyi gizli başlatma və yoxlama imkanlarına güvənirsiniz. Məsələn, [xml]-də sadəcə bir sətir tökmək onu parser kodundan keçirəcək və tam xml ağacı yaradacaq. Eyni məqsədlə kodumuzda Classes istifadə edə bilərik.

Heshtables yayımlayın

Əgər konstruktorunuz yoxdursa, sinif tipinizə hashtable tökərək, konstruktor olmadan davam edə bilərsiniz. Bu nümunədən tam istifadə etmək üçün doğrulama atributlarından istifadə etməyi unutmayın. Eyni zamanda, biz daha dərin inisializasiya və doğrulama məntiqini işə salmaq üçün sinfin yazılmış xassələrindən istifadə edə bilərik.

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
}

Bundan əlavə, tökmə təmiz bir çıxış əldə etməyə kömək edir. Format-Cədvəl-ə ötürülən Cluster hashtable massivinin çıxışını ilk olaraq bu hashtableları bir sinfə köçürsəniz əldə edəcəklərinizlə müqayisə edin. Bir sinfin xassələri həmişə orada müəyyən olunduğu ardıcıllıqla qeyd olunur. Nəticələrdə görünməsini istəmədiyiniz bütün xüsusiyyətlərdən əvvəl gizli açar sözü əlavə etməyi unutmayın.

Dərsləri olan funksional Powershell oksimoron deyil, buna zəmanət verirəm

Mənaların dökümü

Əgər bir arqumenti olan konstruktorunuz varsa, sinif tipinizə dəyər köçürmək dəyəri konstruktorunuza ötürəcək, burada siz sinifinizin nümunəsini işə sala bilərsiniz.

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"

Xəttə yayımlayın

Siz həmçinin [string] ToString() sinif metodunu ləğv edə bilərsiniz, məsələn, sətir interpolyasiyasından istifadə etməklə obyektin sətir təsvirinin arxasındakı məntiqi müəyyən etmək.

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

Seriallaşdırılmış nümunələri yayımlayın

Yayım təhlükəsiz seriyadan çıxarmağa imkan verir. Məlumatlar Klasterdəki spesifikasiyamıza uyğun gəlmirsə, aşağıdakı nümunələr uğursuz olacaq

# Валидация сериализованных данных

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

Funksional kodunuza daxil olur

Funksional proqramlar əvvəlcə verilənlər strukturlarını müəyyənləşdirir, sonra proqramı dəyişməz verilənlər strukturları üzərində çevrilmə ardıcıllığı kimi həyata keçirir. Ziddiyyətli təəssüratlara baxmayaraq, siniflər tip çevirmə üsulları sayəsində funksional kod yazmağa həqiqətən kömək edir.

Yazdığım Powershell işləyirmi?

C# və ya oxşar fonlardan gələn bir çox insan C# ilə oxşar olan Powershell yazır. Bununla siz funksional proqramlaşdırma konsepsiyalarından istifadə etməkdən uzaqlaşırsınız və çox güman ki, Powershell-də obyekt yönümlü proqramlaşdırmaya ciddi şəkildə dalmaqdan və ya funksional proqramlaşdırma haqqında daha çox öyrənməkdən faydalanacaqsınız.

Əgər siz (|), Harada-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object və s. istifadə edərək dəyişməz məlumatların transformasiyasına çox etibar edirsinizsə, daha funksional üslubunuz var və Powershell-dən istifadə etmək sizə fayda verəcəkdir. funksional üslubda dərslər.

Siniflərin funksional istifadəsi

Kastalar, alternativ sintaksisdən istifadə etsələr də, sadəcə iki domen arasındakı xəritədir. Boru kəmərində ForEach-Object-dən istifadə edərək bir sıra dəyərlərin xəritəsini çəkə bilərsiniz.

Aşağıdakı nümunədə Node konstruktoru hər dəfə Datum ötürüldükdə yerinə yetirilir və bu, bizə kifayət qədər kod yazmamaq imkanı verir. Nəticədə, bizim boru kəmərimiz deklarativ məlumat sorğusuna və aqreqasiyaya diqqət yetirir, siniflərimiz isə məlumatların təhlili və təsdiqlənməsi ilə məşğul olur.

# Пример комбинирования классов с конвейерами для 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

Təkrar istifadə üçün qablaşdırma sinfi

Heç bir şey göründüyü qədər yaxşı deyil

Təəssüf ki, siniflər funksiyalar və ya dəyişənlər kimi modullar tərəfindən ixrac edilə bilməz; amma bəzi hiylələr var. Tutaq ki, sinifləriniz ./my-classes.ps1 faylında müəyyən edilib

  • Siz sinifləri olan faylı dotsource edə bilərsiniz:. ./my-classes.ps1. Bu, cari əhatənizdə my-classes.ps1-i icra edəcək və oradakı fayldan bütün sinifləri müəyyən edəcək.

  • Siz bütün fərdi API-lərinizi (cmdlet-lər) ixrac edən Powershell modulu yarada və modul manifestinizdə eyni nəticə ilə ScriptsToProcess = "./my-classes.ps1" dəyişənini təyin edə bilərsiniz: ./my-classes.ps1 burada yerinə yetiriləcək. mühitiniz.

Hansı variantı seçsəniz, unutmayın ki, Powershell tipli sistem müxtəlif yerlərdən yüklənmiş eyni adlı növləri həll edə bilməz.
Fərqli yerlərdən eyni xüsusiyyətlərə malik iki eyni sinif yükləsəniz belə, problemlərlə üzləşmək riskiniz var.

İrəli gedən yol

Tip həlli ilə bağlı problemlərdən qaçmağın ən yaxşı yolu heç vaxt dərslərinizi istifadəçilərə açıqlamamaqdır. İstifadəçinin siniflə müəyyən edilmiş növü idxal etməsini gözləmək əvəzinə modulunuzdan sinfə birbaşa daxil olmaq ehtiyacını aradan qaldıran funksiyanı ixrac edin. Klaster üçün biz istifadəçi dostu parametr dəstlərini dəstəkləyəcək və Klaster qaytaracaq New-Cluster funksiyasını ixrac edə bilərik.

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

Başqa nə oxumaq

Dərslər haqqında
Müdafiə PowerShell
PowerShell-də funksional proqramlaşdırma

Mənbə: www.habr.com

Добавить комментарий