Сыныптары бар функционалды Powershell оксиморон емес, мен оған кепілдік беремін

Эй Хабр! Назарларыңызға мақаланың аудармасын ұсынамын «Сыныптары бар функционалды PowerShell.
Мен бұл оксиморон емес деп уәде беремін»
авторы Кристофер Куч.

Нысанға бағытталған және функционалды бағдарламалау парадигмалары бір-біріне қайшы көрінуі мүмкін, бірақ Powershell бағдарламасында екеуіне бірдей қолдау көрсетіледі. Барлық дерлік бағдарламалау тілдерінің функционалды немесе жоқтығына қарамастан, кеңейтілген атау-мәнді байланыстыру мүмкіндіктері бар; Құрылымдар мен жазбалар сияқты сыныптар бір ғана тәсіл болып табылады. Егер біз Сыныптарды пайдалануды атаулар мен мәндерді байланыстырумен шектейтін болсақ және мұрагерлік, полиморфизм немесе өзгергіштік сияқты ауыр нысанға бағытталған бағдарламалау тұжырымдамаларынан аулақ болсақ, кодымызды қиындатпай олардың артықшылықтарын пайдалана аламыз. Әрі қарай түрлендірудің өзгермейтін әдістерін қосу арқылы біз функционалдық кодымызды Classes көмегімен байыта аламыз.

Касталардың сиқыры

Касталар 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
}

Сонымен қатар, құю таза өнімді алуға көмектеседі. Формат-кестеге берілген Кластер хэш кестелері массивінің шығысын осы хэш кестелерді алдымен сыныпқа шығарсаңыз, алатындарыңызбен салыстырыңыз. Класстың қасиеттері әрқашан сол жерде анықталған ретпен тізімделеді. Нәтижелерде көрінгіңіз келмейтін барлық сипаттардың алдына жасырын кілт сөзді қосуды ұмытпаңыз.

Сыныптары бар функционалды 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 "We just created a model for '$cluster'"

Серияланған даналарды трансляциялау

Трансляциялау қауіпсіз сериядан шығаруға мүмкіндік береді. Деректер Кластердегі спецификацияға сәйкес келмесе, төмендегі мысалдар сәтсіз болады

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

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

Функционалдық кодыңызда касттер

Функционалды бағдарламалар алдымен деректер құрылымдарын анықтайды, содан кейін бағдарламаны өзгермейтін деректер құрылымдары бойынша түрлендірулер тізбегі ретінде жүзеге асырады. Қарама-қайшы әсерге қарамастан, сыныптар типті түрлендіру әдістерінің арқасында функционалдық кодты жазуға шынымен көмектеседі.

Мен жазып жатқан Powershell жұмыс істей ме?

C# немесе ұқсас фоннан шыққан көптеген адамдар C# тіліне ұқсас Powershell жазып жатыр. Бұл әрекетті орындау арқылы сіз функционалдық бағдарламалау тұжырымдамаларын пайдаланудан бас тартасыз және Powershell бағдарламасында объектіге бағытталған бағдарламалауға терең енуден немесе функционалдық бағдарламалау туралы көбірек білуден пайда көресіз.

(|), Қайда-Нысан, ForEach-Нысан, Таңдау-Объект, Топ-Объект, Сұрыптау-Объект, т.б. арқылы өзгермейтін деректерді түрлендіруге қатты сенсеңіз - сізде функционалдық мәнер бар және Powershell пайдаланудан пайда көресіз. функционалдық стильдегі сабақтар.

Сыныптардың функционалдық қолданылуы

Касталар баламалы синтаксисті пайдаланса да, екі домен арасындағы салыстыру ғана. Құбырда ForEach-Object көмегімен мәндер жиымын салыстыруға болады.

Төмендегі мысалда Түйін конструкторы 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 типтік жүйесі әртүрлі жерлерден жүктелген бір атаудағы түрлерді шеше алмайтынын есте сақтаңыз.
Әр түрлі жерлерден бірдей сипаттары бар екі бірдей сыныпты жүктеген болсаңыз да, сіз проблемаларға тап боласыз.

Алға жол

Түрді ажырату мәселелерін болдырмаудың ең жақсы жолы - сыныптарыңызды ешқашан пайдаланушыларға көрсетпеу. Пайдаланушыдан сынып анықталған түрді импорттауын күтудің орнына, сыныпқа тікелей қатынасу қажеттілігін болдырмайтын модульден функцияны экспорттаңыз. Кластер үшін пайдаланушыға ыңғайлы параметрлер жиынын қолдайтын және кластерді қайтаратын Жаңа кластер функциясын экспорттай аламыз.

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 бағдарламасындағы функционалды бағдарламалау

Ақпарат көзі: www.habr.com

пікір қалдыру