Ֆունկցիոնալ Powershell-ը դասերի հետ չի համընկնում, ես դա երաշխավորում եմ

Բարև, Հաբր! Ջենեցի ձեր ուշադրությանը հոդվածի թարգմանությունը "Ֆունկցիոնալ PowerShell դասերով։
Հիմա վստահեցնում եմ, որ դա ոչ մի հակասություն չէ"
աութոր՝ Christopher Kuech։

Առարկայական և ֆունկցիոնալ ծրագրավորման պարադիգմերը կարող են թվալ միմյանց հակասող, բայց երկուսն էլ հավասարապես աջակցվում են PowerShell- ի կողմից։ Nearly յուրաքանչյուր ծրագրային լեզու, լինի այն ֆունկցիոնալ, թե ոչ, ունի անունների և արժեքների ընդլայնված կապի միջոցներ։ Դասերը, նման struct-երի և record-ների, ընդամենը մեկ մոտեցում են։ Եթե մենք սահմանափակենք դասերի օգտագործումը անունների և արժեքների կապով և խուսափել "ծանր" առարկայական ծրագրավորման գաղափարներից, ինչպիսիք են ժառանգությունը, բազմազանությունը կամ փոփոխականությունը, մենք կարող ենք օգտվել դրանց առավելություններից, առանց մեր կոդը բարդացնելու։ Հաջորդը՝ ավելացնելով անփոփոխ (immutable) տեսակների փոխարկման մեթոդներ, կարող ենք հարստացնել մեր ֆունկցիոնալ կոդը դասերով։

Կաստի magie

Կաստերը PowerShell- ի ամենաբարձր հզորություններից մեկն են։ Երբ դուք մեծացնում եք արժեքը, վստահվում եք, որ միջանձնային ծրագիրը տալիս է ձեր հավելվածին հնարավարություն՝ ոչ միանշանակ սկզբնական և հաստատման։ Օրինակ, պարզ մի կաստի տող՝ [xml] այն կանցնի պարսման կոդի միջով և կստեղծի լիարժեք xml ծառ։ Մենք կարող ենք մեր կոդում օգտագործել դասերն այդ նույն նպատակով։

Հաշիվների կաստ

Եթե դուք չունեք կոնստրուկտոր, կարող եք շարունակել առանց դրա, օգտագործելով հաշիվները ձեր դասի տեսակով։ Մի նկատեք վավերացման ատրիբուտները, որպեսզի լիովին օգտագործեք այս պատկերի ձևաչափը։ Եվ մեկ դիվան կունենանք դասի տեսակավորված հատկությունները՝ ավելի խորություն ապահովելու համար։

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
}

Ավելին, կաստը օգնում է ստանալ մաքուր ցուցադրում։ Համեմատեք Cluster հաշվի զանգվածի ցուցադրումը Format-Table․ ում՝ այն, ինչ կստացվի, եթե նախքան այս հաշիվների դասը։ Դասի հատկությունները միշտ ցուցակվում են այն կարգով, որով նրանք այնտեղ սահմանված են։ Մի մոռացեք ավելացնել թաքցված բանալի քեռի բոլոր նրանք հատկություններին, որոնք պետք է չեն երևան ցուցադրման։

Ֆունկցիոնալ Powershell-ը դասերի հետ չի համընկնում, ես դա երաշխավորում եմ

Հիմնական արժեքներ

Եթե դուք ունեք կոնստրուկտոր մեկ արգումենտով, արժեքի կաստը դեպի ձեր դասի տեսակն է փոխանցելու արժեքը՝ ձեր կոնստրուկտորին, որտեղ դուք կարող եք սկսել ձեր դասի՝ ինստանցը։

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"

Կաստ դեպի թել

Դուք նաև կարող եք վերագրանցել [string] ToString() դասի մեթոդը, որպեսզի սահմանեք օբյեկտի տողային ներկայացման տրամաբանությունը, օրինակ, օգտագործել տողերի միջակայման:

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 "Մենք刚刚创建了一个模型 '$cluster'"

Կաշառված երանգների միավորներ

Կաշառքն ապահովում է անվտանգ դեսերիալիզացիա։ Սկզբում նշված օրինակները կհանգեցնեն lỗi, եթե տվյալները չեն համապատասխանում մեր Cluster պայմաններին

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

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

Կաշառները ձեր ֆունկցիոնալ կոդում

Ֆունկցիոնալ ծրագրերը նախ իրագործում են տվյալների կառուցվածքները, ապա ծրագիրը իրականացնում են որպես անշարժ տվյալների կառուցվածքների վրա տրանսֆորմացիաների հաջորդականություն։ Չնայած հակասական տպավորությանը, դասերը իսկապես օգնում են գրել ֆունկցիոնալ կոդ, շնորհիվ տիպերի փոխարկման մեթոդների:

Ես գրում եմ ֆունկցիոնալ Powershell?

Շատ մարդիկ, ովքեր գալիս են C# կամ նման անցյալով, գրում են Powershell, որը նման է C#-ին։ Այսպես գործելով, դուք հրաժարվում եք ֆունկցիոնալ ծրագրման կոնցեպցիաներից և, հավանաբար, կստանաք օգուտ, եթե խորապես ներգրավվեք Powershell-ում օբյեկտային-ուղղված ծրագրավորմանը կամ ավելի լավ ուսումնասիրեք ֆունկցիոնալ ծրագրավորումը:

Եթե դուք խորապես կախված եք անշարժ տվյալների փոխակերպումից, օգտագործելով խողովակներ (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object և այլն՝ դուք ունեք ավելի ֆունկցիոնալ ոճ, և դուք օգնություն կստանաք Powershell դասերի օգտագործումից ֆունկցիոնալ ոճով:

Դասերի ֆունկցիոնալ օգտագործում

Կաշառները, թեև օգտագործում ենAlternatieve սինտաքս, ընդամենը քարտեզավորում են երկու տիրույթների միջև։ Խողովակում կարելի է քարտեզել արժեքների զանգված, օգտագործելով ForEach-Object:

ՍկզբնաբառըNode գործողությունը կատարվում է ամեն անգամ, երբ կատարվում է Datum-ի կաշառ, ինչը մեզ հնարավորություն տալիս է քիչ կոդ գրել։ Արդյունքում մեր խողովակը կենտրոնանում է տվյալների հայտարարատու հարցման և գումարման վրա, մինչդեռ մեր դասերը վերցնում են տվյալների ներթափանցումը և վերաբաշխվածությունը:

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

Դասի դարձնում տարբերակված օգտագործման համար

Չկա ոչինչ այնքան լավ, որքան թվում է

Ցավոք, դասերը չեն կարող արտահանվել մոդուլների համար նույն ձևով, ինչպես գործառույթներ կամ փոփոխականներ, բայց որոշ հնարքներ կան։ Բարի ցանկություն` ձեր դասերը սահմանված են `./my-classes.ps1` ֆայլում

  • Դուք կարող եք անել դասերի ֆայլի տեղադրումը: . ./my-classes.ps1։ Սա կկատարի my-classes.ps1 ձեր ներկայիս տեսանելիության մեջ և սահմանում է ֆայլից բոլոր դասերը:

  • Ձեր API-ները (վարչական տողեր) արտահանող PowerShell մոդուլ ստեղծել կարող եք և ձեր մոդուլի մանիֆեստում ScriptsToProcess փոփոխականը սահմանել որպես ".\/my-classes.ps1", այդպիսով: .\/my-classes.ps1 աշխատելու է ձեր միջավայրում։

Որոնք էլ լինեն ձեր ընտրած տարբերակները, մի մոռացեք, որ PowerShell-ի տիպերի համակարգը չի կարող լուծել տարբեր վայրերից բեռնված նույնանուն տիպերը:
Եթե դուք տարբեր վայրերից նույնատիպ երկու դասեր եք բեռնում՝ նույն հատկություններով, ձեզ կարող են առաջանալ խնդիրներ:

Եղանակը առաջ

Տիպերի լուծման խնդիրներից խուսափելու լավագույն եղանակը՝ երբեք ձեր դասերը օգտվողներին չդարձնել: Փոխարենը, սպասելու փոխարեն, որ օգտվողը ձեզնից բնութագրի որոշակի տիպ, ձեր մոդուլից արտահանեք աշխատանք, որն ազատում է դասի ուղղակի պրոցեսներից: Կլաստերի պարագայում, մենք կարող ենք արտահանեն աշխատանք New-Cluster, որը կաջակցի օգտողին բարեկամ ոճի պարամետրերի հավաքածուին և վերադարձնում է 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-Cluster

Ինչի մասին կարդալը

Ամսագրություններ
Պաշտպանական PowerShell
Պատկերի ծրագրավորում PowerShell-ում

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster