Sinflar bilan funktsional Powershell oksimoron emas, men bunga kafolat beraman

Hey Xabr! E'tiboringizga maqolaning tarjimasini taqdim etaman "Sinflar bilan funktsional PowerShell.
Va'da beraman, bu oksimoron emas"
Kristofer Kuech tomonidan.

Ob'ektga yo'naltirilgan va funktsional dasturlash paradigmalari bir-biriga qarama-qarshi bo'lib tuyulishi mumkin, ammo ikkalasi ham Powershell-da bir xil darajada qo'llab-quvvatlanadi. Deyarli barcha dasturlash tillari, funktsional yoki bo'lmagan, kengaytirilgan nom-qiymat bog'lash uchun imkoniyatlarga ega; Strukturalar va yozuvlar kabi sinflar faqat bitta yondashuvdir. Agar biz sinflardan foydalanishni nomlar va qiymatlarni bog'lash bilan cheklasak va meros, polimorfizm yoki o'zgaruvchanlik kabi og'ir ob'ektga yo'naltirilgan dasturlash tushunchalaridan qochsak, kodimizni murakkablashtirmasdan ularning afzalliklaridan foydalanishimiz mumkin. Bundan tashqari, o'zgarmas turdagi konvertatsiya usullarini qo'shish orqali biz funktsional kodimizni Classes bilan boyitishimiz mumkin.

Kastalarning sehri

Kastlar Powershell-ning eng kuchli xususiyatlaridan biridir. Qiymatni kiritganingizda, muhit ilovangizga qo'shadigan yashirin ishga tushirish va tekshirish imkoniyatlariga tayanasiz. Misol uchun, oddiygina [xml] dagi satrni translyatsiya qilish uni tahlil qilish kodi orqali boshqaradi va to'liq xml daraxtini yaratadi. Xuddi shu maqsadda biz kodimizda Classes dan foydalanishimiz mumkin.

Translatsiya xesh-jadvallari

Agar sizda konstruktor bo'lmasa, sinf turiga xesh-jadvalni ko'chirib, konstruktorsiz davom etishingiz mumkin. Ushbu naqshdan to'liq foydalanish uchun tasdiqlash atributlaridan foydalanishni unutmang. Shu bilan birga, biz chuqurroq ishga tushirish va tekshirish mantig'ini ishga tushirish uchun sinfning yozilgan xususiyatlaridan foydalanishimiz mumkin.

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 tashqari, quyma toza chiqishni olishga yordam beradi. Format-jadvalga o'tkazilgan Klaster xeshtable massivining chiqishini, agar siz avval ushbu xesh-jadvallarni sinfga o'tkazsangiz, olganingiz bilan solishtiring. Klassning xossalari har doim u yerda belgilangan tartibda ro'yxatga olinadi. Natijalarda ko'rinishini istamaydigan barcha xususiyatlar oldiga yashirin kalit so'zni qo'shishni unutmang.

Sinflar bilan funktsional Powershell oksimoron emas, men bunga kafolat beraman

Ma'nolar to'plami

Agar sizda bitta argumentga ega konstruktor bo'lsa, sinf turiga qiymat berish qiymatni konstruktoringizga o'tkazadi, bu erda siz sinfingiz namunasini ishga tushirishingiz mumkin.

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"

Qatorga uzatish

Shuningdek, string interpolyatsiyasidan foydalanish kabi ob'ektning satr tasviri ortidagi mantiqni aniqlash uchun [string] ToString() sinf usulini bekor qilishingiz mumkin.

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

Translatsiya seriyali misollar

Translatsiya xavfsiz seriyadan chiqarish imkonini beradi. Quyidagi misollar, agar ma'lumotlar Klasterdagi spetsifikatsiyamizga mos kelmasa, muvaffaqiyatsiz bo'ladi

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

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

Funktsional kodingizda kastlar

Funktsional dasturlar birinchi navbatda ma'lumotlar tuzilmalarini belgilaydi, so'ngra dasturni o'zgarmas ma'lumotlar tuzilmalari ustidan o'zgartirishlar ketma-ketligi sifatida amalga oshiradi. Qarama-qarshi taassurotga qaramay, sinflar turlarni o'zgartirish usullari tufayli funktsional kod yozishga yordam beradi.

Men yozayotgan Powershell ishlaydimi?

C# yoki shunga o'xshash fondan kelgan ko'p odamlar C# ga o'xshash Powershell yozishmoqda. Shunday qilib, siz funktsional dasturlash tushunchalaridan voz kechasiz va Powershell-da ob'ektga yo'naltirilgan dasturlashga jiddiy kirish yoki funktsional dasturlash haqida ko'proq ma'lumotga ega bo'lishingiz mumkin.

Agar siz (|), Qayerda-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object va h.k.lar yordamida o'zgarmas ma'lumotlarni o'zgartirishga katta tayansangiz - sizda ko'proq funktsional uslub mavjud va Powershell-dan foydalanish sizga foyda keltiradi. funktsional uslubdagi sinflar.

Sinflardan funksional foydalanish

Kastlar, garchi ular muqobil sintaksisdan foydalansalar ham, faqat ikkita domen o'rtasidagi xaritadir. Quvur liniyasida siz ForEach-Object-dan foydalanib, qiymatlar qatorini xaritalashingiz mumkin.

Quyidagi misolda Node konstruktori har safar Datum uzatilganda bajariladi va bu bizga yetarli miqdorda kod yozmaslik imkoniyatini beradi. Natijada, bizning quvur liniyasi deklarativ ma'lumotlarni so'rash va yig'ishga e'tibor qaratadi, bizning sinflarimiz esa ma'lumotlarni tahlil qilish va tekshirish bilan shug'ullanadi.

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

Qayta foydalanish uchun qadoqlash klassi

Hech narsa ko'rinadigan darajada yaxshi emas

Afsuski, sinflarni modullar tomonidan funksiyalar yoki o'zgaruvchilar kabi eksport qilish mumkin emas; lekin ba'zi hiylalar bor. Aytaylik, sizning sinflaringiz ./my-classes.ps1 faylida aniqlangan

  • Siz sinflar bilan faylni dotsource qilishingiz mumkin:. ./my-classes.ps1. Bu joriy doirangizda my-classes.ps1 ni ishga tushiradi va u yerdagi fayldagi barcha sinflarni belgilaydi.

  • Siz barcha maxsus API-larni (cmdletlar) eksport qiladigan Powershell modulini yaratishingiz va modul manifestida ScriptsToProcess = "./my-classes.ps1" o'zgaruvchisini o'rnatishingiz mumkin, xuddi shu natija bilan: ./my-classes.ps1 bu erda ishlaydi. sizning muhitingiz.

Qaysi variantni tanlamasligingizdan qat'iy nazar, Powershell turi tizimi turli joylardan yuklangan bir xil nomdagi turlarni hal qila olmasligini yodda tuting.
Agar siz turli joylardan bir xil xususiyatlarga ega ikkita bir xil sinfni yuklagan bo'lsangiz ham, muammolarga duch kelishingiz mumkin.

Oldinga yo'l

Turni aniqlash bilan bog'liq muammolardan qochishning eng yaxshi usuli - bu hech qachon o'z sinflaringizni foydalanuvchilarga ko'rsatmaslikdir. Foydalanuvchidan sinf tomonidan belgilangan turni import qilishini kutishning o'rniga, modulingizdan sinfga to'g'ridan-to'g'ri kirish zaruratini bartaraf etadigan funksiyani eksport qiling. Klaster uchun biz foydalanuvchilarga qulay parametrlar to'plamini qo'llab-quvvatlaydigan va Klasterni qaytaradigan Yangi-Klaster funksiyasini eksport qilishimiz mumkin.

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

Yana nimani o'qish kerak

Sinflar haqida
Himoya PowerShell
PowerShell-da funktsional dasturlash

Manba: www.habr.com

a Izoh qo'shish